[Pkg-virtualbox-commits] [virtualbox] 01/03: Imported Upstream version 5.1.16-dfsg
Gianfranco Costamagna
locutusofborg at moszumanska.debian.org
Wed Mar 8 23:17:22 UTC 2017
This is an automated email from the git hooks/post-receive script.
locutusofborg pushed a commit to branch master
in repository virtualbox.
commit 348874e2311c07b3d853f1a191c1c2bad45f0ee0
Author: Gianfranco Costamagna <costamagnagianfranco at yahoo.it>
Date: Wed Mar 8 23:27:05 2017 +0100
Imported Upstream version 5.1.16-dfsg
---
Config.kmk | 27 +-
configure | 29 +-
doc/manual/user_ChangeLogImpl.xml | 156 +-
include/VBox/usblib.h | 10 +
include/VBox/vmm/cpum.h | 4 +-
include/VBox/vmm/em.h | 1 +
include/VBox/vmm/pdmaudioifs.h | 866 +-
include/VBox/vmm/pdmaudioifs_50.h | 788 --
include/VBox/vmm/pdmpcidev.h | 11 +
include/VBox/vmm/vm.h | 7 +-
include/iprt/asm.h | 2 +-
include/iprt/circbuf.h | 16 +-
include/iprt/cpp/ministring.h | 3 +-
include/iprt/mangling.h | 6 +-
include/iprt/net.h | 24 +
include/iprt/x86.h | 6 +-
src/VBox/Additions/linux/drm/vbox_drv.h | 7 +
src/VBox/Additions/linux/drm/vbox_fb.c | 14 +-
src/VBox/Additions/linux/drm/vbox_main.c | 10 +
src/VBox/Additions/linux/drm/vbox_mode.c | 19 +-
src/VBox/Additions/linux/drm/vbox_ttm.c | 2 +-
src/VBox/Additions/linux/installer/vboxadd.sh | 3 +-
src/VBox/Additions/linux/sharedfolders/lnkops.c | 2 +
src/VBox/Additions/linux/sharedfolders/regops.c | 9 +-
src/VBox/Additions/linux/sharedfolders/utils.c | 7 +
src/VBox/Additions/linux/sharedfolders/vfsmod.c | 3 +
src/VBox/Additions/linux/sharedfolders/vfsmod.h | 5 +
src/VBox/Debugger/VBoxDbgConsole.cpp | 51 +-
src/VBox/Debugger/VBoxDbgConsole.h | 15 +-
src/VBox/Debugger/VBoxDbgGui.cpp | 4 +-
src/VBox/Devices/Audio/AudioMixBuffer.cpp | 1118 +--
src/VBox/Devices/Audio/AudioMixBuffer.h | 20 +-
src/VBox/Devices/Audio/AudioMixer.cpp | 1829 +---
src/VBox/Devices/Audio/AudioMixer.h | 193 +-
src/VBox/Devices/Audio/DevHDA.cpp | 3849 +++-----
src/VBox/Devices/Audio/DevHDACommon.h | 75 -
src/VBox/Devices/Audio/DevIchAc97.cpp | 2026 ++---
.../Devices/{Audio_50 => Audio}/DevIchHdaCodec.h | 0
src/VBox/Devices/Audio/DevSB16.cpp | 584 +-
src/VBox/Devices/Audio/DrvAudio.cpp | 2989 ++++---
src/VBox/Devices/Audio/DrvAudio.h | 100 +-
src/VBox/Devices/Audio/DrvAudioCommon.cpp | 860 +-
src/VBox/Devices/Audio/DrvHostALSAAudio.cpp | 858 +-
src/VBox/Devices/Audio/DrvHostCoreAudio.cpp | 2688 ++----
src/VBox/Devices/Audio/DrvHostDSound.cpp | 1281 ++-
src/VBox/Devices/Audio/DrvHostDebugAudio.cpp | 486 --
src/VBox/Devices/Audio/DrvHostNullAudio.cpp | 342 +-
src/VBox/Devices/Audio/DrvHostOSSAudio.cpp | 710 +-
src/VBox/Devices/Audio/DrvHostPulseAudio.cpp | 1166 +--
src/VBox/Devices/Audio/HDACodec.cpp | 2148 ++---
src/VBox/Devices/Audio/HDACodec.h | 130 -
src/VBox/Devices/Audio/alsa_mangling.h | 7 +-
src/VBox/Devices/Audio/alsa_stubs.c | 20 +-
src/VBox/Devices/Audio/alsa_stubs.h | 2 +-
src/VBox/Devices/Audio/pulse_mangling.h | 5 +-
src/VBox/Devices/Audio/pulse_stubs.c | 18 +-
src/VBox/Devices/Audio/pulse_stubs.h | 2 +-
src/VBox/Devices/{Audio_50 => Audio}/sys-queue.h | 0
src/VBox/Devices/Audio/testcase/Makefile.kmk | 9 +-
.../Devices/Audio/testcase/tstAudioMixBuffer.cpp | 367 +-
src/VBox/Devices/Audio_50/AudioMixBuffer.cpp | 1756 ----
src/VBox/Devices/Audio_50/AudioMixBuffer.h | 82 -
src/VBox/Devices/Audio_50/AudioMixer.cpp | 520 --
src/VBox/Devices/Audio_50/AudioMixer.h | 113 -
src/VBox/Devices/Audio_50/DevHDA.cpp | 5139 -----------
src/VBox/Devices/Audio_50/DevIchAc97.cpp | 2758 ------
src/VBox/Devices/Audio_50/DevSB16.cpp | 2451 ------
src/VBox/Devices/Audio_50/DrvAudio.cpp | 2627 ------
src/VBox/Devices/Audio_50/DrvAudio.h | 156 -
src/VBox/Devices/Audio_50/DrvAudioCommon.cpp | 413 -
src/VBox/Devices/Audio_50/DrvHostALSAAudio.cpp | 1425 ---
src/VBox/Devices/Audio_50/DrvHostCoreAudio.cpp | 2260 -----
src/VBox/Devices/Audio_50/DrvHostDSound.cpp | 2302 -----
src/VBox/Devices/Audio_50/DrvHostNullAudio.cpp | 342 -
src/VBox/Devices/Audio_50/DrvHostOSSAudio.cpp | 1006 ---
src/VBox/Devices/Audio_50/DrvHostPulseAudio.cpp | 1257 ---
src/VBox/Devices/Audio_50/HDACodec.cpp | 2782 ------
src/VBox/Devices/Audio_50/Makefile.kup | 0
src/VBox/Devices/Audio_50/alsa_mangling.h | 55 -
src/VBox/Devices/Audio_50/alsa_stubs.c | 190 -
src/VBox/Devices/Audio_50/alsa_stubs.h | 21 -
src/VBox/Devices/Audio_50/pulse_mangling.h | 69 -
src/VBox/Devices/Audio_50/pulse_stubs.c | 287 -
src/VBox/Devices/Audio_50/pulse_stubs.h | 21 -
src/VBox/Devices/Audio_50/testcase/Makefile.kmk | 41 -
.../Audio_50/testcase/tstAudioMixBuffer.cpp | 591 --
src/VBox/Devices/Bus/DevPCI.cpp | 16 +-
src/VBox/Devices/Bus/DevPciIch9.cpp | 490 +-
src/VBox/Devices/EFI/DevEFI.cpp | 35 +-
src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd | Bin 2097152 -> 2097152 bytes
src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd | Bin 2097152 -> 2097152 bytes
.../Graphics/BIOS/VBoxVgaBiosAlternative286.asm | 6 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum | 2 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative386.asm | 6 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum | 2 +-
.../Graphics/BIOS/VBoxVgaBiosAlternative8086.asm | 6 +-
.../BIOS/VBoxVgaBiosAlternative8086.md5sum | 2 +-
src/VBox/Devices/Graphics/DevVGA_VBVA.cpp | 2 +-
src/VBox/Devices/Makefile.kmk | 51 +-
src/VBox/Devices/Network/DrvNAT.cpp | 17 +-
src/VBox/Devices/Network/lwip-new/src/api/tcpip.c | 1 +
.../Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp | 27 +-
src/VBox/Devices/Network/slirp/ip_input.c | 4 +-
src/VBox/Devices/Network/slirp/slirp.c | 6 +
src/VBox/Devices/Network/slirp/socket.c | 2 +-
.../Devices/PC/BIOS/VBoxBiosAlternative286.asm | 4 +-
.../Devices/PC/BIOS/VBoxBiosAlternative286.md5sum | 2 +-
.../Devices/PC/BIOS/VBoxBiosAlternative386.asm | 4 +-
.../Devices/PC/BIOS/VBoxBiosAlternative386.md5sum | 2 +-
.../Devices/PC/BIOS/VBoxBiosAlternative8086.asm | 4 +-
.../Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum | 2 +-
src/VBox/Devices/PC/DevACPI.cpp | 80 +-
src/VBox/Devices/PC/DevFwCommon.cpp | 29 +-
src/VBox/Devices/PC/DevPcBios.cpp | 76 +-
src/VBox/Devices/PC/vbox.dsl | 191 +-
src/VBox/Devices/Samples/DevPlayground.cpp | 9 +-
src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp | 3 +-
src/VBox/Devices/USB/VUSBSnifferPcapNg.cpp | 17 +-
src/VBox/Devices/VMMDev/VMMDev.cpp | 9 +-
src/VBox/Devices/VirtIO/Virtio.cpp | 2 +-
src/VBox/Devices/build/VBoxDD.cpp | 4 -
src/VBox/Devices/build/VBoxDD.h | 4 -
.../Devices/testcase/tstDeviceStructSizeRC.cpp | 34 +-
src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp | 134 +-
src/VBox/Frontends/VBoxBugReport/VBoxBugReport.h | 44 +-
.../Frontends/VBoxBugReport/VBoxBugReportWin.cpp | 50 +
src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp | 3 +-
.../Frontends/VBoxManage/VBoxManageHostonly.cpp | 42 +-
src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp | 2 +-
src/VBox/Frontends/VirtualBox/VBoxUI.pro | 1 +
.../Frontends/VirtualBox/nls/ApprovedLanguages.kmk | 1 +
src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts | 24 +-
.../Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts | 24 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts | 2 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts | 18 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts | 159 +-
.../Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts | 20 +-
.../Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts | 26 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts | 16 +-
.../Frontends/VirtualBox/nls/VirtualBox_km_KH.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts | 20 +-
.../Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts | 185 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts | 20 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_th.ts | 9213 ++++++++++++++++++++
src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts | 20 +-
.../Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts | 20 +-
.../Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts | 16 +-
.../Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts | 16 +-
src/VBox/Frontends/VirtualBox/nls/qt_th.ts | 5321 +++++++++++
.../Frontends/VirtualBox/src/UIVMInfoDialog.cpp | 2 +-
.../VirtualBox/src/globals/VBoxGlobal.cpp | 48 +-
.../Frontends/VirtualBox/src/globals/VBoxGlobal.h | 4 +
.../VirtualBox/src/runtime/UIFrameBuffer.cpp | 8 +-
.../runtime/fullscreen/UIMachineViewFullscreen.cpp | 4 +-
.../runtime/information/UIInformationDataItem.cpp | 4 +-
.../src/runtime/normal/UIMachineViewNormal.cpp | 13 +
.../src/runtime/seamless/UIMachineViewSeamless.cpp | 4 +-
.../runtime/seamless/UIMachineWindowSeamless.cpp | 95 +-
.../src/runtime/seamless/UIMachineWindowSeamless.h | 10 +
.../graphics/details/UIGDetailsElements.cpp | 4 +-
.../VirtualBox/src/settings/UISettingsDialog.cpp | 12 +-
.../VirtualBox/src/settings/UISettingsDialog.h | 2 +
.../src/settings/UISettingsSerializer.cpp | 4 +
.../VirtualBox/src/settings/UISettingsSerializer.h | 6 +
.../settings/global/UIGlobalSettingsNetwork.cpp | 96 +-
.../src/settings/global/UIGlobalSettingsNetwork.h | 36 +-
.../global/UIGlobalSettingsNetworkDetailsHost.cpp | 53 +-
.../global/UIGlobalSettingsNetworkDetailsHost.h | 11 +-
.../global/UIGlobalSettingsNetworkDetailsNAT.cpp | 2 +-
.../global/UIGlobalSettingsNetworkDetailsNAT.h | 6 +-
.../src/settings/machine/UIMachineSettingsAudio.h | 4 +-
.../settings/machine/UIMachineSettingsDisplay.h | 4 +-
.../settings/machine/UIMachineSettingsGeneral.h | 4 +-
.../settings/machine/UIMachineSettingsInterface.h | 4 +-
.../settings/machine/UIMachineSettingsNetwork.cpp | 10 +-
.../settings/machine/UIMachineSettingsNetwork.h | 10 +-
.../settings/machine/UIMachineSettingsParallel.cpp | 6 +-
.../settings/machine/UIMachineSettingsParallel.h | 10 +-
.../src/settings/machine/UIMachineSettingsSF.cpp | 6 +-
.../src/settings/machine/UIMachineSettingsSF.h | 10 +-
.../settings/machine/UIMachineSettingsSerial.cpp | 6 +-
.../src/settings/machine/UIMachineSettingsSerial.h | 10 +-
.../settings/machine/UIMachineSettingsStorage.cpp | 36 +-
.../settings/machine/UIMachineSettingsStorage.h | 30 +-
.../src/settings/machine/UIMachineSettingsSystem.h | 4 +-
.../src/settings/machine/UIMachineSettingsUSB.cpp | 2 +-
.../src/settings/machine/UIMachineSettingsUSB.h | 6 +-
.../VirtualBox/src/widgets/UIMiniToolBar.cpp | 36 +-
.../VirtualBox/src/widgets/UIMiniToolBar.h | 2 +-
.../src/widgets/UIPortForwardingTable.cpp | 7 +-
.../HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp | 130 +-
src/VBox/HostServices/GuestProperties/service.cpp | 14 +
src/VBox/HostServices/SharedFolders/vbsfpath.cpp | 253 +-
src/VBox/Installer/common/virtualbox.desktop.in | 6 +
src/VBox/Installer/linux/vboxdrv.sh | 2 +-
src/VBox/Installer/win/NLS/en_US.wxl | 2 +-
src/VBox/Installer/win/NLS/it_IT.wxl | 2 +-
src/VBox/Main/Makefile.kmk | 10 +-
src/VBox/Main/include/ApplianceImplPrivate.h | 2 +
src/VBox/Main/include/DrvAudioVRDE.h | 2 +-
src/VBox/Main/include/DrvAudioVRDE_50.h | 64 -
src/VBox/Main/include/DrvAudioVideoRec.h | 2 +-
src/VBox/Main/include/DrvAudioVideoRec_50.h | 62 -
src/VBox/Main/include/USBProxyBackend.h | 21 +-
src/VBox/Main/include/USBProxyService.h | 2 +-
src/VBox/Main/src-client/ConsoleImpl2.cpp | 11 +-
src/VBox/Main/src-client/DrvAudioVRDE.cpp | 431 +-
src/VBox/Main/src-client/DrvAudioVRDE_50.cpp | 618 --
src/VBox/Main/src-client/DrvAudioVideoRec.cpp | 81 +-
src/VBox/Main/src-client/DrvAudioVideoRec_50.cpp | 911 --
src/VBox/Main/src-server/ApplianceImplExport.cpp | 308 +-
src/VBox/Main/src-server/ApplianceImplImport.cpp | 5 +-
src/VBox/Main/src-server/DHCPServerImpl.cpp | 82 +-
src/VBox/Main/src-server/HostImpl.cpp | 1 +
src/VBox/Main/src-server/MachineImpl.cpp | 4 +-
src/VBox/Main/src-server/MediumImpl.cpp | 2 +-
src/VBox/Main/src-server/USBProxyBackend.cpp | 11 +-
src/VBox/Main/src-server/USBProxyService.cpp | 17 +-
.../src-server/darwin/USBProxyBackendDarwin.cpp | 5 +-
.../src-server/freebsd/USBProxyBackendFreeBSD.cpp | 5 +-
.../src-server/generic/USBProxyBackendUsbIp.cpp | 74 +-
.../Main/src-server/linux/USBProxyBackendLinux.cpp | 5 +-
.../src-server/solaris/USBProxyBackendSolaris.cpp | 5 +-
.../Main/src-server/win/USBProxyBackendWindows.cpp | 5 +-
src/VBox/Main/src-server/win/svcmain.cpp | 52 +-
src/VBox/Main/src-server/xpcom/server.cpp | 24 +-
src/VBox/NetworkServices/DHCP/Config.cpp | 5 +-
src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp | 14 +-
src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp | 2 +-
src/VBox/RDP/client-1.8.3/Makefile.in | 2 +-
src/VBox/RDP/client-1.8.3/Makefile.kmk | 28 +-
src/VBox/RDP/client-1.8.3/rdesktop.c | 15 +-
src/VBox/Runtime/common/dbg/dbgas.cpp | 2 +
src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp | 15 +-
src/VBox/Runtime/common/misc/circbuf.cpp | 18 +-
src/VBox/Runtime/common/net/netaddrstr2.cpp | 50 +
src/VBox/Runtime/common/string/RTUtf16NLen.cpp | 2 +-
src/VBox/Runtime/common/zip/tarcmd.cpp | 4 +-
.../Runtime/r0drv/linux/semmutex-r0drv-linux.c | 2 +-
src/VBox/Runtime/r0drv/linux/the-linux-kernel.h | 4 +
src/VBox/Runtime/r3/posix/ldrNative-posix.cpp | 5 +
src/VBox/Runtime/r3/xml.cpp | 22 +
src/VBox/Runtime/testcase/tstLdr-4.cpp | 9 +
src/VBox/Runtime/testcase/tstRTInlineAsm.cpp | 8 +-
src/VBox/Runtime/testcase/tstRTNetIPv4.cpp | 157 +
src/VBox/Storage/testcase/vbox-img.cpp | 2 +
src/VBox/VMM/VMMAll/EMAll.cpp | 46 +
src/VBox/VMM/VMMAll/GIMAllKvm.cpp | 17 +-
src/VBox/VMM/VMMAll/IEMAll.cpp | 70 +-
src/VBox/VMM/VMMAll/IEMAllAImplC.cpp | 2 +-
src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h | 7 +-
src/VBox/VMM/VMMAll/IEMAllInstructions.cpp.h | 20 +-
src/VBox/VMM/VMMAll/PGMAllBth.h | 24 +-
src/VBox/VMM/VMMAll/PGMAllPool.cpp | 21 +-
src/VBox/VMM/VMMR0/HMR0.cpp | 6 +-
src/VBox/VMM/VMMR0/HMVMXR0.cpp | 20 +-
src/VBox/VMM/VMMR3/CFGM.cpp | 6 -
src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp | 3 +-
src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp | 10 +-
src/VBox/VMM/VMMR3/EM.cpp | 40 +-
src/VBox/VMM/VMMR3/MMHyper.cpp | 2 +
src/VBox/VMM/VMMR3/PDMAsyncCompletionFile.cpp | 3 +
src/VBox/VMM/VMMR3/PDMBlkCache.cpp | 2 +
src/VBox/VMM/VMMR3/PGM.cpp | 8 +-
src/VBox/VMM/include/GIMHvInternal.h | 12 +-
src/VBox/VMM/testcase/tstAnimate.cpp | 3 -
src/VBox/VMM/testcase/tstIEMCheckMc.cpp | 1 +
.../bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c | 4 +-
.../bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c | 4 +-
src/libs/Makefile.kmk | 8 +-
src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c | 7 +-
.../xpcom18a4/xpcom/base/nsExceptionService.cpp | 8 +-
292 files changed, 26897 insertions(+), 49270 deletions(-)
diff --git a/Config.kmk b/Config.kmk
index 8637671..dc0d971 100644
--- a/Config.kmk
+++ b/Config.kmk
@@ -208,7 +208,7 @@ VBOX_VERSION_MINOR = 1
# This is the current build number. It should be increased every time we publish a
# new build. The define is available in every source file. Only even build numbers
# will be published, odd numbers are set during development.
-VBOX_VERSION_BUILD = 14
+VBOX_VERSION_BUILD = 16
# The raw version string. This *must not* contain any other information/fields than
# major, minor and build revision (as it is now) -- also will be used for host/guest version
# comparison.
@@ -235,9 +235,6 @@ ifneq ($(VBOX_RELEASE_EXACT_MATCH),)
export VBOX_EXTPACKS_SH_MODE = release
endif
-# by default use the old 5.0 audio code as the new code still has too many regressions
-VBOX_WITH_AUDIO_50 := 1
-
# Some info on the vendor
VBOX_VENDOR = Oracle Corporation
VBOX_VENDOR_SHORT = Oracle
@@ -1169,18 +1166,6 @@ ifdef VBOX_OSE
endif
#
-# Audio: Which code base to use.
-# This can be overriden in LocalConfig.kmk.
-#
-ifdef VBOX_WITH_AUDIO_50
- VBOX_AUDIO_PATH_SOURCES=Audio_50
- VBOX_AUDIO_FILE_SUFFIX=_50
-else
- VBOX_AUDIO_PATH_SOURCES=Audio
- VBOX_AUDIO_FILE_SUFFIX=
-endif
-
-#
# VBOX_WITHOUT_HARDENING is for developers (put in LocalConfig.kmk).
# Note that this is a bit rough since hardening governs more than one
# variable... Also note that we allow VBOX_WITH_HARDENING=1 on the
@@ -2342,6 +2327,12 @@ VBOX_PATH_X11_XORG_7_1 = $(VBOX_PATH_X11_ROOT)/7.1
#
+# Miscellaneous includes
+#
+VBOX_JPEG_INCS = $(PATH_ROOT)/src/libs/jpeg-9b
+
+
+#
# crOpenGL related paths and variables.
#
ifdef VBOX_WITH_CROGL
@@ -3641,7 +3632,7 @@ VBOXLNX32GUEST_SUFF_LIB = .a
# SDKs for external libraries.
#
SDK_VBOX_LIBXML2 = .
-SDK_VBOX_LIBXML2_INCS ?= $(PATH_ROOT)/src/libs/libxml2-2.9.2/include
+SDK_VBOX_LIBXML2_INCS ?= $(PATH_ROOT)/src/libs/libxml2-2.9.4/include
SDK_VBOX_LIBXML2_DEFS ?= _REENTRANT
SDK_VBOX_LIBXML2_DEFS.win += WIN32 _WINDOWS _MBCS
# note: no linking to LIB here, we do that explicitly in src/VBox/Runtime/Makefile.kmk to link
@@ -6955,7 +6946,7 @@ endif
SVN ?= svn$(HOSTSUFF_EXE)
VBOX_SVN_REV_KMK = $(PATH_OUT)/revision.kmk
ifndef VBOX_SVN_REV
- VBOX_SVN_REV_FALLBACK := $(patsubst %:,, $Rev: 112924 $ )
+ VBOX_SVN_REV_FALLBACK := $(patsubst %:,, $Rev: 113841 $ )
VBOX_SVN_DEP := $(firstword $(wildcard $(PATH_ROOT)/.svn/wc.db $(abspath $(PATH_ROOT)/../.svn/wc.db) $(abspath $(PATH_ROOT)/../../.svn/wc.db) $(PATH_ROOT)/.svn/entries))
ifeq ($(which $(SVN)),)
VBOX_SVN_DEP :=
diff --git a/configure b/configure
index a63bf8c..116b442 100755
--- a/configure
+++ b/configure
@@ -1694,6 +1694,8 @@ EOF
if [ $? -eq 0 ]; then
echo "(Qt5 from pkg-config)" >> $LOG
FLGQT5=`pkg-config Qt5Core --cflags`
+ # gcc 4.8 is able to compile with C++11 (see also VBOX_GCC_std in Config.kmk)
+ [ $cc_maj -eq 4 -a $cc_min -eq 8 ] && FLGQT5="$FLGQT5 -std=c++11"
INCQT5=`strip_I "$FLGQT5"`
LIBDIR5=`pkg-config Qt5Core --variable=libdir`
LIBQT5=`pkg-config Qt5Core --libs`
@@ -1921,12 +1923,35 @@ EOF
fail
else
if test_execute; then
- cnf_append "VBOX_LINUX_SRC" "`cd $LINUX ; pwd`"
+ cat > $ODIR.tmp_src.c << EOF
+#include <linux/version.h>
+int printf(const char *format, ...);
+int main(void)
+{
+ return LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) ? 1 : 0;
+}
+EOF
+ echo "compiling the following source file:" >> $LOG
+ cat $ODIR.tmp_src.c >> $LOG
+ echo "using the following command line:" >> $LOG
+ echo "$CC -O -Wall -o $ODIR.tmp_out $ODIR.tmp_src.c -nostdinc -I$LINUX/include " \
+ "-I$LINUX/include/generated/uapi" >> $LOG
+ $CC -O -Wall -o $ODIR.tmp_out $ODIR.tmp_src.c -nostdinc -I$LINUX/include \
+ -I$LINUX/include/generated/uapi >> $LOG 2>&1
+ if [ $? -eq 0 ]; then
+ $ODIR.tmp_out
+ if [ $? -ne 0 ]; then
+ cnf_append "VBOX_WITH_VBOXDRV" ""
+ cnf_append "VBOX_WITH_ADDITION_DRIVERS" ""
+ echo "Detected Linux >= 4.8 -- disabling compiling of Linux kernel modules."
+ else
+ cnf_append "VBOX_LINUX_SRC" "`cd $LINUX ; pwd`"
+ fi
+ fi
fi
fi
}
-
#
# Check for kchmviewer, needed to display the online help
# (unused as we ship kchmviewer)
diff --git a/doc/manual/user_ChangeLogImpl.xml b/doc/manual/user_ChangeLogImpl.xml
index 4086b34..e2c71f7 100644
--- a/doc/manual/user_ChangeLogImpl.xml
+++ b/doc/manual/user_ChangeLogImpl.xml
@@ -3,6 +3,150 @@
<chapter> <!-- HACK ALERT! Seems we must have a single top level element for xi:include to work.
So, we use chapter and xpointer="xpointer(/chapter/)" with xi:include. -->
<sect1>
+ <title>Version 5.1.16 (2017-03-08)</title>
+
+ <para>This is a maintenance release. The following items were fixed and/or
+ added:</para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>VMM: don't access the <emphasis>MSR_IA32_SMM_MONITOR_CTL</emphasis>
+ MSR if <emphasis>dual-monitor treatment</emphasis> is not available
+ (KVM workaround, bug #14965)</para>
+ </listitem>
+
+ <listitem>
+ <para>VMM: another fix for handling certain MSRs on ancient CPUs
+ without VT-x support for MSR bitmaps</para>
+ </listitem>
+
+ <listitem>
+ <para>VMM: fixed <emphasis>VERR_SSM_LOAD_CPUID_MISMATCH</emphasis>
+ errors when restoring a saved state with SMP guests on hosts without
+ the <emphasis>CPUID/HTT</emphasis> bit set (bug #16428)</para>
+ </listitem>
+
+ <listitem>
+ <para>VMM: fixed a bug in call gate emulation</para>
+ </listitem>
+
+ <listitem>
+ <para>VMM: <emphasis>FWAIT</emphasis> instruction fix</para>
+ </listitem>
+
+ <listitem>
+ <para>VMM: fixed a sporadic guest hang under certain conditions</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: hide the mini-toolbar from the taskbar and the pager on
+ certain X11 hosts</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: better error handling on the global settings / network /
+ host-only / DHCP server settings</para>
+ </listitem>
+
+ <listitem>
+ <para>GUI: fixes for full-screen with multiple screens</para>
+ </listitem>
+
+ <listitem>
+ <para>Host-only Network: fixed host-only adapter creation issue preventing
+ VirtualBox installation on Windows 10 hosts (bug #16379)</para>
+ </listitem>
+
+ <listitem>
+ <para>NAT network: fixed two potential crashes in the DHCP server</para>
+ </listitem>
+
+ <listitem>
+ <para>ICH9: fixed incorrect initialization of the primary bus for PCI
+ bridges (5.1.14 regression)</para>
+ </listitem>
+
+ <listitem>
+ <para>Storage: LsiLogic fix for Windows 10</para>
+ </listitem>
+
+ <listitem>
+ <para>USB: fixed not being able to attach certain USB devices having
+ invalid characters in the device strings (5.0.18 regression; bug #15956)</para>
+ </listitem>
+
+ <listitem>
+ <para>USB: several fixes for the USB/IP support (bug #16462)</para>
+ </listitem>
+
+ <listitem>
+ <para>VBoxSVC: fixed another crash during shutdown under rare
+ circumstances</para>
+ </listitem>
+
+ <listitem>
+ <para>VBoxSVC: fixed a stack overflow on (Windows debug builds
+ only; bug #16409)</para>
+ </listitem>
+
+ <listitem>
+ <para>OVF: when importing an appliance handle more than 10 network
+ adapters if the OVA was created by VirtualBox (bug #16401)</para>
+ </listitem>
+
+ <listitem>
+ <para>OVF: fixes for exporting and importing appliances with many
+ disks (bug #16402)</para>
+ </listitem>
+
+ <listitem>
+ <para>VBoxManage: fixed regression with <emphasis>modifyhd
+ --resize</emphasis> (bug #16311)</para>
+ </listitem>
+
+ <listitem>
+ <para>rdesktop-vrdp: source code tarball fixes</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux Installers: do not rebuild kernel modules unnecessarily
+ (bug #16408)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts: added an action for opening the VM manager
+ window to the .desktop file</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux hosts / guests: Linux 4.11 compile fixes (bug #16506)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux Additions: added <emphasis>vboxsf</emphasis> FS modules
+ alias (bug #16404)</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux Additions: fix for the shared folders kernel module to
+ compile on Linux 4.10</para>
+ </listitem>
+
+ <listitem>
+ <para>Linux Additions: properly install the Linux kernel module
+ override rule on distributions without /etc/depmod.d</para>
+ </listitem>
+
+ <listitem>
+ <para>Windows Additions: fixed a crash with recent Windows 10 builds
+ if 3D is disabled (bug #15973)</para>
+ </listitem>
+
+ </itemizedlist>
+ </sect1>
+
+ <sect1>
<title>Version 5.1.14 (2017-01-16)</title>
<para>This is a maintenance release. The following items were fixed and/or
@@ -593,7 +737,7 @@
</listitem>
<listitem>
- <para>VMDK: Fixed an issue creating fixed size images with certain
+ <para>VMDK: fixed an issue creating fixed size images with certain
sizes and the Split2G option enabled (bug #15748)</para>
</listitem>
@@ -603,7 +747,7 @@
</listitem>
<listitem>
- <para>Storage: Fixed broken bandwidth limitation when the limit is very
+ <para>Storage: fixed broken bandwidth limitation when the limit is very
low (bug #14982)</para>
</listitem>
@@ -1727,7 +1871,7 @@
<listitem>
<para>GUI: fixed another 3D overlay window reparenting issue when the
- VM is switched to fullscreen mode on X11 hosts</para>
+ VM is switched to full-screen mode on X11 hosts</para>
</listitem>
<listitem>
@@ -3278,13 +3422,13 @@
<listitem>
<para>VMM: fixed a Guru Meditation <emphasis>VINF_EM_TRIPLE_FAULT</emphasis>
- on older CPUs that don't support MSR-bitmaps (VT-x only;
+ on older CPUs that don't support MSR bitmaps (VT-x only;
bugs #13034, #13125, #13311, #13425, #13426, #13463, #13585)</para>
</listitem>
<listitem>
<para>GUI: fix 3D overlay window reparenting issue when VM goes to
- fullscreen mode on X11 hosts</para>
+ full-screen mode on X11 hosts</para>
</listitem>
<listitem>
@@ -4582,7 +4726,7 @@
</listitem>
<listitem>
- <para>Host-only Networking: fixed creating of host-only network interfaces
+ <para>Host-only Network: fixed creating of host-only network interfaces
(4.3.0 regression; bug #12182)</para>
</listitem>
diff --git a/include/VBox/usblib.h b/include/VBox/usblib.h
index e138fdf..df85d29 100644
--- a/include/VBox/usblib.h
+++ b/include/VBox/usblib.h
@@ -123,6 +123,9 @@ USBLIB_DECL(uint64_t) USBLibHashSerial(const char *pszSerial);
*
* @returns String length (excluding terminator).
* @param psz The string to purge.
+ *
+ * @remarks The return string may be shorter than the input, left over space
+ * after the end of the string will be filled with zeros.
*/
DECLINLINE(size_t) USBLibPurgeEncoding(char *psz)
{
@@ -155,6 +158,13 @@ DECLINLINE(size_t) USBLibPurgeEncoding(char *psz)
if (ch == '\0')
break;
}
+
+ /* Wind back to the zero terminator and zero fill any gap to make
+ USBFilterValidate happy. (offSrc is at zero terminator too.) */
+ offDst--;
+ while (offSrc > offDst)
+ psz[offSrc--] = '\0';
+
return offDst;
}
if (ch == '\0')
diff --git a/include/VBox/vmm/cpum.h b/include/VBox/vmm/cpum.h
index 7c55121..0aa622b 100644
--- a/include/VBox/vmm/cpum.h
+++ b/include/VBox/vmm/cpum.h
@@ -996,6 +996,8 @@ typedef struct CPUMFEATURES
uint32_t fMonitorMWait : 1;
/** MWAIT Extensions present. */
uint32_t fMWaitExtensions : 1;
+ /** Supports CMPXCHG16B in 64-bit mode. */
+ uint32_t fMovCmpXchg16b : 1;
/** Supports AMD 3DNow instructions. */
uint32_t f3DNow : 1;
@@ -1021,7 +1023,7 @@ typedef struct CPUMFEATURES
uint32_t fLeakyFxSR : 1;
/** Alignment padding / reserved for future use. */
- uint32_t fPadding : 29;
+ uint32_t fPadding : 28;
uint32_t auPadding[3];
} CPUMFEATURES;
#ifndef VBOX_FOR_DTRACE_LIB
diff --git a/include/VBox/vmm/em.h b/include/VBox/vmm/em.h
index 5554307..4cdc014 100644
--- a/include/VBox/vmm/em.h
+++ b/include/VBox/vmm/em.h
@@ -199,6 +199,7 @@ VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX
VMM_INT_DECL(bool) EMMonitorWaitShouldContinue(PVMCPU pVCpu, PCPUMCTX pCtx);
VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx, RTGCPHYS GCPhys);
VMM_INT_DECL(int) EMMonitorWaitPerform(PVMCPU pVCpu, uint64_t rax, uint64_t rcx);
+VMM_INT_DECL(int) EMUnhaltAndWakeUp(PVM pVM, PVMCPU pVCpuDst);
/** @name Assembly routines
* @{ */
diff --git a/include/VBox/vmm/pdmaudioifs.h b/include/VBox/vmm/pdmaudioifs.h
index 8b8e2fd..1e5dc98 100644
--- a/include/VBox/vmm/pdmaudioifs.h
+++ b/include/VBox/vmm/pdmaudioifs.h
@@ -23,94 +23,66 @@
* terms and conditions of either the GPL or the CDDL or both.
*/
-#ifdef VBOX_WITH_AUDIO_50
-# include "pdmaudioifs_50.h"
-#endif
-
#ifndef ___VBox_vmm_pdmaudioifs_h
#define ___VBox_vmm_pdmaudioifs_h
-#include <iprt/circbuf.h>
+#include <VBox/types.h>
#include <iprt/critsect.h>
#include <iprt/list.h>
-#include <VBox/types.h>
-#ifdef VBOX_WITH_STATISTICS
-# include <VBox/vmm/stam.h>
-#endif
/** @defgroup grp_pdm_ifs_audio PDM Audio Interfaces
* @ingroup grp_pdm_interfaces
* @{
*/
-/** PDM audio driver instance flags. */
+/** @todo r=bird: Don't be lazy with documentation! */
typedef uint32_t PDMAUDIODRVFLAGS;
/** No flags set. */
-#define PDMAUDIODRVFLAGS_NONE 0
+/** @todo r=bird: s/PDMAUDIODRVFLAG/PDMAUDIODRV_FLAGS/g */
+#define PDMAUDIODRVFLAG_NONE 0
/** Marks a primary audio driver which is critical
* when running the VM. */
-#define PDMAUDIODRVFLAGS_PRIMARY RT_BIT(0)
+#define PDMAUDIODRVFLAG_PRIMARY RT_BIT(0)
/**
* Audio format in signed or unsigned variants.
*/
typedef enum PDMAUDIOFMT
{
- /** Invalid format, do not use. */
- PDMAUDIOFMT_INVALID,
- /** 8-bit, unsigned. */
- PDMAUDIOFMT_U8,
- /** 8-bit, signed. */
- PDMAUDIOFMT_S8,
- /** 16-bit, unsigned. */
- PDMAUDIOFMT_U16,
- /** 16-bit, signed. */
- PDMAUDIOFMT_S16,
- /** 32-bit, unsigned. */
- PDMAUDIOFMT_U32,
- /** 32-bit, signed. */
- PDMAUDIOFMT_S32,
+ AUD_FMT_INVALID,
+ AUD_FMT_U8,
+ AUD_FMT_S8,
+ AUD_FMT_U16,
+ AUD_FMT_S16,
+ AUD_FMT_U32,
+ AUD_FMT_S32,
/** Hack to blow the type up to 32-bit. */
- PDMAUDIOFMT_32BIT_HACK = 0x7fffffff
+ AUD_FMT_32BIT_HACK = 0x7fffffff
} PDMAUDIOFMT;
/**
- * Audio configuration of a certain host backend.
+ * Audio configuration of a certain backend.
*/
typedef struct PDMAUDIOBACKENDCFG
{
- /** Size (in bytes) of the host backend's audio output stream structure. */
size_t cbStreamOut;
- /** Size (in bytes) of the host backend's audio input stream structure. */
size_t cbStreamIn;
- /** Number of valid output sinks found on the host. */
- uint8_t cSinks;
- /** Number of valid input sources found on the host. */
- uint8_t cSources;
- /** Number of concurrent output streams supported on the host.
- * UINT32_MAX for unlimited concurrent streams. */
- uint32_t cMaxStreamsOut;
- /** Number of concurrent input streams supported on the host.
- * UINT32_MAX for unlimited concurrent streams. */
- uint32_t cMaxStreamsIn;
+ uint32_t cMaxHstStrmsOut;
+ uint32_t cMaxHstStrmsIn;
} PDMAUDIOBACKENDCFG, *PPDMAUDIOBACKENDCFG;
/**
- * A single audio sample, representing left and right channels (stereo).
+ * An audio sample. At the moment stereo (left + right channels) only.
+ * @todo Replace this with a more generic union
+ * which then also could handle 2.1 or 5.1 sound.
*/
typedef struct PDMAUDIOSAMPLE
{
- /** Left channel. */
int64_t i64LSample;
- /** Right channel. */
int64_t i64RSample;
-} PDMAUDIOSAMPLE;
-/** Pointer to a single (stereo) audio sample. */
-typedef PDMAUDIOSAMPLE *PPDMAUDIOSAMPLE;
-/** Pointer to a const single (stereo) audio sample. */
-typedef PDMAUDIOSAMPLE const *PCPDMAUDIOSAMPLE;
+} PDMAUDIOSAMPLE, *PPDMAUDIOSAMPLE;
typedef enum PDMAUDIOENDIANNESS
{
@@ -128,180 +100,70 @@ typedef enum PDMAUDIOENDIANNESS
PDMAUDIOENDIANNESS_32BIT_HACK = 0x7fffffff
} PDMAUDIOENDIANNESS;
+typedef struct PDMAUDIOSTREAMCFG
+{
+ /** Frequency in Hertz (Hz). */
+ uint32_t uHz;
+ /** Number of channels (2 for stereo). */
+ uint8_t cChannels;
+ /** Audio format. */
+ PDMAUDIOFMT enmFormat;
+ /** @todo Use RT_LE2H_*? */
+ PDMAUDIOENDIANNESS enmEndianness;
+} PDMAUDIOSTREAMCFG, *PPDMAUDIOSTREAMCFG;
+
+#if defined(RT_LITTLE_ENDIAN)
+# define PDMAUDIOHOSTENDIANNESS PDMAUDIOENDIANNESS_LITTLE
+#elif defined(RT_BIG_ENDIAN)
+# define PDMAUDIOHOSTENDIANNESS PDMAUDIOENDIANNESS_BIG
+#else
+# error "Port me!"
+#endif
+
/**
* Audio direction.
*/
typedef enum PDMAUDIODIR
{
- /** Unknown direction. */
- PDMAUDIODIR_UNKNOWN = 0,
- /** Input. */
- PDMAUDIODIR_IN = 1,
- /** Output. */
- PDMAUDIODIR_OUT = 2,
- /** Duplex handling. */
- PDMAUDIODIR_ANY = 3,
+ PDMAUDIODIR_UNKNOWN = 0,
+ PDMAUDIODIR_IN = 1,
+ PDMAUDIODIR_OUT = 2,
+ PDMAUDIODIR_DUPLEX = 3,
/** Hack to blow the type up to 32-bit. */
PDMAUDIODIR_32BIT_HACK = 0x7fffffff
} PDMAUDIODIR;
/**
- * Audio playback destinations.
+ * Audio mixer controls.
*/
-typedef enum PDMAUDIOPLAYBACKDEST
+typedef enum PDMAUDIOMIXERCTL
{
- /** Unknown destination. */
- PDMAUDIOPLAYBACKDEST_UNKNOWN = 0,
- /** Front channel. */
- PDMAUDIOPLAYBACKDEST_FRONT,
- /** Center / LFE (Subwoofer) channel. */
- PDMAUDIOPLAYBACKDEST_CENTER_LFE,
- /** Rear channel. */
- PDMAUDIOPLAYBACKDEST_REAR,
+ PDMAUDIOMIXERCTL_UNKNOWN = 0,
+ PDMAUDIOMIXERCTL_VOLUME,
+ PDMAUDIOMIXERCTL_PCM,
+ PDMAUDIOMIXERCTL_LINE_IN,
+ PDMAUDIOMIXERCTL_MIC_IN,
/** Hack to blow the type up to 32-bit. */
- PDMAUDIOPLAYBACKDEST_32BIT_HACK = 0x7fffffff
-} PDMAUDIOPLAYBACKDEST;
+ PDMAUDIOMIXERCTL_32BIT_HACK = 0x7fffffff
+} PDMAUDIOMIXERCTL;
/**
* Audio recording sources.
*/
typedef enum PDMAUDIORECSOURCE
{
- /** Unknown recording source. */
PDMAUDIORECSOURCE_UNKNOWN = 0,
- /** Microphone-In. */
PDMAUDIORECSOURCE_MIC,
- /** CD. */
PDMAUDIORECSOURCE_CD,
- /** Video-In. */
PDMAUDIORECSOURCE_VIDEO,
- /** AUX. */
PDMAUDIORECSOURCE_AUX,
- /** Line-In. */
- PDMAUDIORECSOURCE_LINE,
- /** Phone-In. */
+ PDMAUDIORECSOURCE_LINE_IN,
PDMAUDIORECSOURCE_PHONE,
/** Hack to blow the type up to 32-bit. */
PDMAUDIORECSOURCE_32BIT_HACK = 0x7fffffff
} PDMAUDIORECSOURCE;
/**
- * Audio stream (data) layout.
- */
-typedef enum PDMAUDIOSTREAMLAYOUT
-{
- /** Unknown access type; do not use. */
- PDMAUDIOSTREAMLAYOUT_UNKNOWN = 0,
- /** Non-interleaved access, that is, consecutive
- * access to the data. */
- PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED,
- /** Interleaved access, where the data can be
- * mixed together with data of other audio streams. */
- PDMAUDIOSTREAMLAYOUT_INTERLEAVED,
- /** Complex layout, which does not fit into the
- * interleaved / non-interleaved layouts. */
- PDMAUDIOSTREAMLAYOUT_COMPLEX,
- /** Hack to blow the type up to 32-bit. */
- PDMAUDIOSTREAMLAYOUT_32BIT_HACK = 0x7fffffff
-} PDMAUDIOSTREAMLAYOUT, *PPDMAUDIOSTREAMLAYOUT;
-
-/** No stream channel data flags defined. */
-#define PDMAUDIOSTREAMCHANNELDATA_FLAG_NONE 0
-
-/**
- * Structure for keeping a stream channel data block around.
- */
-typedef struct PDMAUDIOSTREAMCHANNELDATA
-{
- /** Circular buffer for the channel data. */
- PRTCIRCBUF pCircBuf;
- size_t cbAcq;
- /** Channel data flags. */
- uint32_t fFlags;
-} PDMAUDIOSTREAMCHANNELDATA, *PPDMAUDIOSTREAMCHANNELDATA;
-
-/**
- * Structure for a single channel of an audio stream.
- * An audio stream consists of one or multiple channels,
- * depending on the configuration.
- */
-typedef struct PDMAUDIOSTREAMCHANNEL
-{
- /** Channel ID. */
- uint8_t uChannel;
- /** Step size (in bytes) to the channel's next frame. */
- size_t cbStep;
- /** Frame size (in bytes) of this channel. */
- size_t cbFrame;
- /** Offset (in bytes) to first sample in the data block. */
- size_t cbFirst;
- /** Currente offset (in bytes) in the data stream. */
- size_t cbOff;
- /** Associated data buffer. */
- PDMAUDIOSTREAMCHANNELDATA Data;
-} PDMAUDIOSTREAMCHANNEL, *PPDMAUDIOSTREAMCHANNEL;
-
-/**
- * Structure for keeping an audio stream configuration.
- */
-typedef struct PDMAUDIOSTREAMCFG
-{
- /** Friendly name of the stream. */
- char szName[64];
- /** Direction of the stream. */
- PDMAUDIODIR enmDir;
- union
- {
- /** Desired playback destination (for an output stream). */
- PDMAUDIOPLAYBACKDEST Dest;
- /** Desired recording source (for an input stream). */
- PDMAUDIORECSOURCE Source;
- } DestSource;
- /** Frequency in Hertz (Hz). */
- uint32_t uHz;
- /** Number of audio channels (2 for stereo, 1 for mono). */
- uint8_t cChannels;
- /** Audio format. */
- PDMAUDIOFMT enmFormat;
- /** @todo Use RT_LE2H_*? */
- PDMAUDIOENDIANNESS enmEndianness;
- /** Hint about the optimal sample buffer size (in audio samples).
- * 0 if no hint is given. */
- uint32_t cSampleBufferSize;
-} PDMAUDIOSTREAMCFG, *PPDMAUDIOSTREAMCFG;
-
-#if defined(RT_LITTLE_ENDIAN)
-# define PDMAUDIOHOSTENDIANNESS PDMAUDIOENDIANNESS_LITTLE
-#elif defined(RT_BIG_ENDIAN)
-# define PDMAUDIOHOSTENDIANNESS PDMAUDIOENDIANNESS_BIG
-#else
-# error "Port me!"
-#endif
-
-/**
- * Audio mixer controls.
- */
-typedef enum PDMAUDIOMIXERCTL
-{
- /** Unknown mixer control. */
- PDMAUDIOMIXERCTL_UNKNOWN = 0,
- /** Master volume. */
- PDMAUDIOMIXERCTL_VOLUME_MASTER,
- /** Front. */
- PDMAUDIOMIXERCTL_FRONT,
- /** Center / LFE (Subwoofer). */
- PDMAUDIOMIXERCTL_CENTER_LFE,
- /** Rear. */
- PDMAUDIOMIXERCTL_REAR,
- /** Line-In. */
- PDMAUDIOMIXERCTL_LINE_IN,
- /** Microphone-In. */
- PDMAUDIOMIXERCTL_MIC_IN,
- /** Hack to blow the type up to 32-bit. */
- PDMAUDIOMIXERCTL_32BIT_HACK = 0x7fffffff
-} PDMAUDIOMIXERCTL;
-
-/**
* Audio stream commands. Used in the audio connector
* as well as in the actual host backends.
*/
@@ -325,7 +187,7 @@ typedef enum PDMAUDIOSTREAMCMD
* Properties of audio streams for host/guest
* for in or out directions.
*/
-typedef struct PDMAUDIOPCMPROPS
+typedef struct PDMPCMPROPS
{
/** Sample width. Bits per sample. */
uint8_t cBits;
@@ -345,34 +207,25 @@ typedef struct PDMAUDIOPCMPROPS
uint32_t uAlign;
/** Sample frequency in Hertz (Hz). */
uint32_t uHz;
- /** Bitrate (in bytes/s). */
- uint32_t cbBitrate;
+ /** Bandwidth (bytes/s). */
+ uint32_t cbPerSec;
/** Whether the endianness is swapped or not. */
bool fSwapEndian;
-} PDMAUDIOPCMPROPS, *PPDMAUDIOPCMPROPS;
+} PDMPCMPROPS, *PPDMPCMPROPS;
/**
- * Audio volume parameters.
+ * Structure keeping an audio volume level.
*/
typedef struct PDMAUDIOVOLUME
{
/** Set to @c true if this stream is muted, @c false if not. */
- bool fMuted;
- /** Left channel volume.
- * Range is from [0 ... 255], whereas 0 specifies
- * the most silent and 255 the loudest value. */
- uint8_t uLeft;
- /** Right channel volume.
- * Range is from [0 ... 255], whereas 0 specifies
- * the most silent and 255 the loudest value. */
- uint8_t uRight;
+ bool fMuted;
+ /** Left channel volume. */
+ uint32_t uLeft;
+ /** Right channel volume. */
+ uint32_t uRight;
} PDMAUDIOVOLUME, *PPDMAUDIOVOLUME;
-/** Defines the minimum volume allowed. */
-#define PDMAUDIO_VOLUME_MIN (0)
-/** Defines the maximum volume allowed. */
-#define PDMAUDIO_VOLUME_MAX (255)
-
/**
* Structure for holding rate processing information
* of a source + destination audio stream. This is needed
@@ -397,118 +250,44 @@ typedef struct PDMAUDIOSTRMRATE
} PDMAUDIOSTRMRATE, *PPDMAUDIOSTRMRATE;
/**
- * Structure for holding mixing buffer volume parameters.
- * The volume values are in fixed point style and must
- * be converted to/from before using with e.g. PDMAUDIOVOLUME.
- */
-typedef struct PDMAUDMIXBUFVOL
-{
- /** Set to @c true if this stream is muted, @c false if not. */
- bool fMuted;
- /** Left volume to apply during conversion. Pass 0
- * to convert the original values. May not apply to
- * all conversion functions. */
- uint32_t uLeft;
- /** Right volume to apply during conversion. Pass 0
- * to convert the original values. May not apply to
- * all conversion functions. */
- uint32_t uRight;
-} PDMAUDMIXBUFVOL, *PPDMAUDMIXBUFVOL;
-
-/**
- * Structure for holding sample conversion parameters for
- * the audioMixBufConvFromXXX / audioMixBufConvToXXX macros.
- */
-typedef struct PDMAUDMIXBUFCONVOPTS
-{
- /** Number of audio samples to convert. */
- uint32_t cSamples;
- union
- {
- struct
- {
- /** Volume to use for conversion. */
- PDMAUDMIXBUFVOL Volume;
- } From;
- };
-} PDMAUDMIXBUFCONVOPTS;
-/** Pointer to conversion parameters for the audio mixer. */
-typedef PDMAUDMIXBUFCONVOPTS *PPDMAUDMIXBUFCONVOPTS;
-/** Pointer to const conversion parameters for the audio mixer. */
-typedef PDMAUDMIXBUFCONVOPTS const *PCPDMAUDMIXBUFCONVOPTS;
-
-/**
* Note: All internal handling is done in samples,
* not in bytes!
*/
typedef uint32_t PDMAUDIOMIXBUFFMT;
typedef PDMAUDIOMIXBUFFMT *PPDMAUDIOMIXBUFFMT;
-/**
- * Convertion-from function used by the PDM audio buffer mixer.
- *
- * @returns Number of samples returned.
- * @param paDst Where to return the converted samples.
- * @param pvSrc The source samples bytes.
- * @param cbSrc Number of bytes to convert.
- * @param pOpts Conversion options.
- */
-typedef DECLCALLBACK(uint32_t) FNPDMAUDIOMIXBUFCONVFROM(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc,
- PCPDMAUDMIXBUFCONVOPTS pOpts);
-/** Pointer to a convertion-from function used by the PDM audio buffer mixer. */
-typedef FNPDMAUDIOMIXBUFCONVFROM *PFNPDMAUDIOMIXBUFCONVFROM;
-
-/**
- * Convertion-to function used by the PDM audio buffer mixer.
- *
- * @param pvDst Output buffer.
- * @param paSrc The input samples.
- * @param pOpts Conversion options.
- */
-typedef DECLCALLBACK(void) FNPDMAUDIOMIXBUFCONVTO(void *pvDst, PCPDMAUDIOSAMPLE paSrc, PCPDMAUDMIXBUFCONVOPTS pOpts);
-/** Pointer to a convertion-to function used by the PDM audio buffer mixer. */
-typedef FNPDMAUDIOMIXBUFCONVTO *PFNPDMAUDIOMIXBUFCONVTO;
-
typedef struct PDMAUDIOMIXBUF *PPDMAUDIOMIXBUF;
typedef struct PDMAUDIOMIXBUF
{
- RTLISTNODE Node;
+ RTLISTNODE Node;
/** Name of the buffer. */
- char *pszName;
+ char *pszName;
/** Sample buffer. */
- PPDMAUDIOSAMPLE pSamples;
+ PPDMAUDIOSAMPLE pSamples;
/** Size of the sample buffer (in samples). */
- uint32_t cSamples;
- /** The current read position (in samples). */
- uint32_t offRead;
- /** The current write position (in samples). */
- uint32_t offWrite;
+ uint32_t cSamples;
+ /** The current read/write position (in samples)
+ * in the samples buffer. */
+ uint32_t offReadWrite;
/**
* Total samples already mixed down to the parent buffer (if any). Always starting at
- * the parent's offRead position.
+ * the parent's offReadWrite position.
*
* Note: Count always is specified in parent samples, as the sample count can differ between parent
* and child.
*/
- uint32_t cMixed;
- /** How much audio samples are currently being used
- * in this buffer.
- * Note: This also is known as the distance in ring buffer terms. */
- uint32_t cUsed;
+ uint32_t cMixed;
+ uint32_t cProcessed;
/** Pointer to parent buffer (if any). */
- PPDMAUDIOMIXBUF pParent;
+ PPDMAUDIOMIXBUF pParent;
/** List of children mix buffers to keep in sync with (if being a parent buffer). */
- RTLISTANCHOR lstChildren;
+ RTLISTANCHOR lstBuffers;
/** Intermediate structure for buffer conversion tasks. */
- PPDMAUDIOSTRMRATE pRate;
- /** Internal representation of current volume used for mixing. */
- PDMAUDMIXBUFVOL Volume;
+ PPDMAUDIOSTRMRATE pRate;
+ /** Current volume used for mixing. */
+ PDMAUDIOVOLUME Volume;
/** This buffer's audio format. */
- PDMAUDIOMIXBUFFMT AudioFmt;
- /** Standard conversion-to function for set AudioFmt. */
- PFNPDMAUDIOMIXBUFCONVTO pfnConvTo;
- /** Standard conversion-from function for set AudioFmt. */
- PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom;
+ PDMAUDIOMIXBUFFMT AudioFmt;
/**
* Ratio of the associated parent stream's frequency by this stream's
* frequency (1<<32), represented as a signed 64 bit integer.
@@ -519,173 +298,131 @@ typedef struct PDMAUDIOMIXBUF
*
* Currently this does not get changed once assigned.
*/
- int64_t iFreqRatio;
- /** For quickly converting samples <-> bytes and vice versa. */
- uint8_t cShift;
+ int64_t iFreqRatio;
+ /* For quickly converting samples <-> bytes and
+ * vice versa. */
+ uint8_t cShift;
} PDMAUDIOMIXBUF;
-typedef uint32_t PDMAUDIOFILEFLAGS;
-
-/* No flags defined. */
-#define PDMAUDIOFILEFLAG_NONE 0
-
-/**
- * Audio file types.
- */
-typedef enum PDMAUDIOFILETYPE
-{
- /** Unknown type, do not use. */
- PDMAUDIOFILETYPE_UNKNOWN = 0,
- /** Wave (.WAV) file. */
- PDMAUDIOFILETYPE_WAV
-} PDMAUDIOFILETYPE;
-
-/**
- * Structure for an audio file handle.
- */
-typedef struct PDMAUDIOFILE
-{
- /** Type of the audio file. */
- PDMAUDIOFILETYPE enmType;
- /** File name. */
- char szName[255];
- /** Actual file handle. */
- RTFILE hFile;
- /** Data needed for the specific audio file type implemented.
- * Optional, can be NULL. */
- void *pvData;
- /** Data size (in bytes). */
- size_t cbData;
-} PDMAUDIOFILE, *PPDMAUDIOFILE;
-
/** Stream status flag. To be used with PDMAUDIOSTRMSTS_FLAG_ flags. */
typedef uint32_t PDMAUDIOSTRMSTS;
/** No flags being set. */
#define PDMAUDIOSTRMSTS_FLAG_NONE 0
-/** Whether this stream has been initialized by the
- * backend or not. */
-#define PDMAUDIOSTRMSTS_FLAG_INITIALIZED RT_BIT_32(0)
/** Whether this stream is enabled or disabled. */
-#define PDMAUDIOSTRMSTS_FLAG_ENABLED RT_BIT_32(1)
+#define PDMAUDIOSTRMSTS_FLAG_ENABLED RT_BIT_32(0)
/** Whether this stream has been paused or not. This also implies
* that this is an enabled stream! */
-#define PDMAUDIOSTRMSTS_FLAG_PAUSED RT_BIT_32(2)
+#define PDMAUDIOSTRMSTS_FLAG_PAUSED RT_BIT_32(1)
/** Whether this stream was marked as being disabled
* but there are still associated guest output streams
* which rely on its data. */
-#define PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE RT_BIT_32(3)
-/** Data can be read from the stream. */
-#define PDMAUDIOSTRMSTS_FLAG_DATA_READABLE RT_BIT_32(4)
-/** Data can be written to the stream. */
-#define PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE RT_BIT_32(5)
-/** Whether this stream is in re-initialization phase.
- * All other bits remain untouched to be able to restore
- * the stream's state after the re-initialization bas been
- * finished. */
-#define PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT RT_BIT_32(6)
+#define PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE RT_BIT_32(2)
/** Validation mask. */
-#define PDMAUDIOSTRMSTS_VALID_MASK UINT32_C(0x0000007F)
+#define PDMAUDIOSTRMSTS_VALID_MASK UINT32_C(0x00000007)
/**
- * Enumeration presenting a backend's current status.
+ * Represents an audio input on the host of a certain
+ * backend (e.g. DirectSound, PulseAudio etc).
+ *
+ * One host audio input is assigned to exactly one parent
+ * guest input stream.
*/
-typedef enum PDMAUDIOBACKENDSTS
+struct PDMAUDIOGSTSTRMIN;
+typedef PDMAUDIOGSTSTRMIN *PPDMAUDIOGSTSTRMIN;
+
+typedef struct PDMAUDIOHSTSTRMIN
{
- /** Unknown/invalid status. */
- PDMAUDIOBACKENDSTS_UNKNOWN = 0,
- /** The backend is in its initialization phase.
- * Not all backends support this status. */
- PDMAUDIOBACKENDSTS_INITIALIZING,
- /** The backend has stopped its operation. */
- PDMAUDIOBACKENDSTS_STOPPED,
- /** The backend is up and running. */
- PDMAUDIOBACKENDSTS_RUNNING,
- /** The backend ran into an error and is unable to recover.
- * A manual re-initialization might help. */
- PDMAUDIOBACKENDSTS_ERROR
-} PDMAUDIOBACKENDSTS;
+ /** List node. */
+ RTLISTNODE Node;
+ /** PCM properties. */
+ PDMPCMPROPS Props;
+ /** Stream status flag. */
+ PDMAUDIOSTRMSTS fStatus;
+ /** Critical section for serializing access. */
+ RTCRITSECT CritSect;
+ /** This stream's mixing buffer. */
+ PDMAUDIOMIXBUF MixBuf;
+ /** Pointer to (parent) guest stream. */
+ PPDMAUDIOGSTSTRMIN pGstStrmIn;
+} PDMAUDIOHSTSTRMIN, *PPDMAUDIOHSTSTRMIN;
-/**
- * Audio stream context.
+/*
+ * Represents an audio output on the host through a certain
+ * backend (e.g. DirectSound, PulseAudio etc).
+ *
+ * One host audio output can have multiple (1:N) guest outputs
+ * assigned.
*/
-typedef enum PDMAUDIOSTREAMCTX
+typedef struct PDMAUDIOHSTSTRMOUT
{
- /** No context set / invalid. */
- PDMAUDIOSTREAMCTX_UNKNOWN = 0,
- /** Host stream, connected to a backend. */
- PDMAUDIOSTREAMCTX_HOST,
- /** Guest stream, connected to the device emulation. */
- PDMAUDIOSTREAMCTX_GUEST
-} PDMAUDIOSTREAMCTX;
+ /** List node. */
+ RTLISTNODE Node;
+ /** Stream properites. */
+ PDMPCMPROPS Props;
+ /** Stream status flag. */
+ PDMAUDIOSTRMSTS fStatus;
+ /** Critical section for serializing access. */
+ RTCRITSECT CritSect;
+ /** This stream's mixing buffer. */
+ PDMAUDIOMIXBUF MixBuf;
+ /** Associated guest output streams. */
+ RTLISTANCHOR lstGstStrmOut;
+} PDMAUDIOHSTSTRMOUT, *PPDMAUDIOHSTSTRMOUT;
/**
- * Structure for keeping audio input stream specifics.
- * Do not use directly. Instead, use PDMAUDIOSTREAM.
+ * Guest audio stream state.
*/
-typedef struct PDMAUDIOSTREAMIN
+typedef struct PDMAUDIOGSTSTRMSTATE
{
- /** Timestamp (in ms) since last read. */
- uint64_t tsLastReadMS;
-#ifdef VBOX_WITH_STATISTICS
- STAMCOUNTER StatBytesElapsed;
- STAMCOUNTER StatBytesTotalRead;
- STAMCOUNTER StatSamplesCaptured;
-#endif
-} PDMAUDIOSTREAMIN, *PPDMAUDIOSTREAMIN;
+ /** Guest audio out stream active or not. */
+ bool fActive;
+ /** Guest audio output stream has some samples or not. */
+ bool fEmpty;
+ /** Name of this stream. */
+ char *pszName;
+ /** Number of references to this stream. Only can be
+ * destroyed if the reference count is reaching 0. */
+ uint8_t cRefs;
+} PDMAUDIOGSTSTRMSTATE, *PPDMAUDIOGSTSTRMSTATE;
/**
- * Structure for keeping audio output stream specifics.
- * Do not use directly. Instead, use PDMAUDIOSTREAM.
+ * Represents an audio input from the guest (that is, from the
+ * emulated device, e.g. Intel HDA).
+ *
+ * Each guest input can have multiple host input streams.
*/
-typedef struct PDMAUDIOSTREAMOUT
+typedef struct PDMAUDIOGSTSTRMIN
{
- /** Timestamp (in ms) since last write. */
- uint64_t tsLastWriteMS;
-#ifdef VBOX_WITH_STATISTICS
- STAMCOUNTER StatBytesElapsed;
- STAMCOUNTER StatBytesTotalWritten;
- STAMCOUNTER StatSamplesPlayed;
-#endif
-} PDMAUDIOSTREAMOUT, *PPDMAUDIOSTREAMOUT;
-
-struct PDMAUDIOSTREAM;
-typedef PDMAUDIOSTREAM *PPDMAUDIOSTREAM;
+ /** Guest stream properites. */
+ PDMPCMPROPS Props;
+ /** Current stream state. */
+ PDMAUDIOGSTSTRMSTATE State;
+ /** This stream's mixing buffer. */
+ PDMAUDIOMIXBUF MixBuf;
+ /** Pointer to associated host input stream. */
+ PPDMAUDIOHSTSTRMIN pHstStrmIn;
+} PDMAUDIOGSTSTRMIN, *PPDMAUDIOGSTSTRMIN;
/**
- * Structure for maintaining an nput/output audio stream.
+ * Represents an audio output from the guest (that is, from the
+ * emulated device, e.g. Intel HDA).
+ *
+ * Each guest output is assigned to a single host output.
*/
-typedef struct PDMAUDIOSTREAM
+typedef struct PDMAUDIOGSTSTRMOUT
{
/** List node. */
RTLISTNODE Node;
- /** Pointer to the other pair of this stream.
- * This might be the host or guest side. */
- PPDMAUDIOSTREAM pPair;
- /** Name of this stream. */
- char szName[64];
- /** Number of references to this stream. Only can be
- * destroyed if the reference count is reaching 0. */
- uint32_t cRefs;
- /** The stream's audio configuration. */
- PDMAUDIOSTREAMCFG Cfg;
- /** Stream status flag. */
- PDMAUDIOSTRMSTS fStatus;
+ /** Guest output stream properites. */
+ PDMPCMPROPS Props;
+ /** Current stream state. */
+ PDMAUDIOGSTSTRMSTATE State;
/** This stream's mixing buffer. */
PDMAUDIOMIXBUF MixBuf;
- /** Audio direction of this stream. */
- PDMAUDIODIR enmDir;
- /** Context of this stream. */
- PDMAUDIOSTREAMCTX enmCtx;
- /** Timestamp (in ms) since last iteration. */
- uint64_t tsLastIterateMS;
- /** Union for input/output specifics. */
- union
- {
- PDMAUDIOSTREAMIN In;
- PDMAUDIOSTREAMOUT Out;
- };
-} PDMAUDIOSTREAM, *PPDMAUDIOSTREAM;
+ /** Pointer to the associated host output stream. */
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut;
+} PDMAUDIOGSTSTRMOUT, *PPDMAUDIOGSTSTRMOUT;
/** Pointer to a audio connector interface. */
typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR;
@@ -743,154 +480,147 @@ typedef struct PDMAUDIOCALLBACK
*/
typedef struct PDMIAUDIOCONNECTOR
{
+ DECLR3CALLBACKMEMBER(int, pfnQueryStatus, (PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbAvailIn, uint32_t *pcbFreeOut, uint32_t *pcSamplesLive));
+
/**
- * Retrieves the current configuration of the host audio backend.
+ * Reads PCM audio data from the host (input).
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pCfg Where to store the host audio backend configuration data.
- */
- DECLR3CALLBACKMEMBER(int, pfnGetConfig, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg));
-
- /**
- * @todo Docs!
+ * @param pGstStrmIn Pointer to guest input stream to write to.
+ * @param pvBuf Where to store the read data.
+ * @param cbBuf Number of bytes to read.
+ * @param pcbRead Bytes of audio data read. Optional.
*/
- DECLR3CALLBACKMEMBER(PDMAUDIOBACKENDSTS, pfnGetStatus, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir));
+ DECLR3CALLBACKMEMBER(int, pfnRead, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead));
/**
- * Creates an audio stream.
+ * Writes PCM audio data to the host (output).
*
* @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pCfgHost Stream configuration for host side.
- * @param pCfgGuest Stream configuration for guest side.
- * @param ppStream Pointer where to return the created audio stream on success.
+ * @param pInterface Pointer to the interface structure containing the called function pointer.
+ * @param pGstStrmOut Pointer to guest output stream to read from.
+ * @param pvBuf Audio data to be written.
+ * @param cbBuf Number of bytes to be written.
+ * @param pcbWritten Bytes of audio data written. Optional.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamCreate, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest, PPDMAUDIOSTREAM *ppStream));
+ DECLR3CALLBACKMEMBER(int, pfnWrite, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten));
/**
- * Destroys an audio stream.
+ * Retrieves the current configuration of the host audio backend.
+ *
+ * @returns VBox status code.
*
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
+ * @param pCfg Where to store the host audio backend configuration data.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamDestroy, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(int, pfnGetConfiguration, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg));
/**
- * Adds a reference to the specified audio stream.
+ * Checks whether a specific guest input stream is active or not.
*
- * @returns New reference count. UINT32_MAX on error.
+ * @returns Whether the specified stream is active or not.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream adding the reference to.
+ * @param pGstStrmIn Pointer to guest input stream.
*/
- DECLR3CALLBACKMEMBER(uint32_t, pfnStreamRetain, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(bool, pfnIsActiveIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
/**
- * Releases a reference from the specified stream.
+ * Checks whether a specific guest output stream is active or not.
*
- * @returns New reference count. UINT32_MAX on error.
+ * @returns Whether the specified stream is active or not.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream releasing a reference from.
+ * @param pGstStrmOut Pointer to guest output stream.
*/
- DECLR3CALLBACKMEMBER(uint32_t, pfnStreamRelease, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(bool, pfnIsActiveOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
/**
- * Reads PCM audio data from the host (input).
+ * Checks whether the specified guest input stream is in a valid (working) state.
*
- * @returns VBox status code.
+ * @returns True if a host voice in is available, false if not.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream to write to.
- * @param pvBuf Where to store the read data.
- * @param cbBuf Number of bytes to read.
- * @param pcbRead Bytes of audio data read. Optional.
+ * @param pGstStrmIn Pointer to guest input stream to check.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamRead, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead));
+ DECLR3CALLBACKMEMBER(bool, pfnIsValidIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
/**
- * Writes PCM audio data to the host (output).
+ * Checks whether the specified guest output stream is in a valid (working) state.
*
- * @returns VBox status code.
+ * @returns True if a host voice out is available, false if not.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream to read from.
- * @param pvBuf Audio data to be written.
- * @param cbBuf Number of bytes to be written.
- * @param pcbWritten Bytes of audio data written. Optional.
+ * @param pGstStrmOut Pointer to guest output stream to check.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamWrite, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten));
+ DECLR3CALLBACKMEMBER(bool, pfnIsValidOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
/**
- * Controls a specific audio stream.
+ * Enables a specific guest output stream and starts the audio device.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
- * @param enmStreamCmd The stream command to issue.
+ * @param pGstStrmOut Pointer to guest output stream.
+ * @param fEnable Whether to enable or disable the specified output stream.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamControl, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd));
+ DECLR3CALLBACKMEMBER(int, pfnEnableOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable));
/**
- * Processes stream data.
+ * Enables a specific guest input stream and starts the audio device.
*
+ * @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
- * @param pcData Data (in audio samples) available. Optional.
+ * @param pGstStrmIn Pointer to guest input stream.
+ * @param fEnable Whether to enable or disable the specified input stream.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamIterate, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(int, pfnEnableIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn, bool fEnable));
/**
- * Returns the number of readable data (in bytes) of a specific audio input stream.
+ * Creates a guest input stream.
*
- * @returns Number of readable data (in bytes).
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
+ * @returns VBox status code.
+ * @param pInterface Pointer to the interface structure containing the called function pointer.
+ * @param pszName Name of the audio channel.
+ * @param enmRecSource Specifies the type of recording source to be opened.
+ * @param pCfg Pointer to PDMAUDIOSTREAMCFG to use.
+ * @param ppGstStrmIn Pointer where to return the guest guest input stream on success.
*/
- DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetReadable, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream));
-
+ DECLR3CALLBACKMEMBER(int, pfnCreateIn, (PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
+ PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg,
+ PPDMAUDIOGSTSTRMIN *ppGstStrmIn));
/**
- * Returns the number of writable data (in bytes) of a specific audio output stream.
+ * Creates a guest output stream.
*
- * @returns Number of writable data (in bytes).
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
+ * @returns VBox status code.
+ * @param pInterface Pointer to the interface structure containing the called function pointer.
+ * @param pszName Name of the audio channel.
+ * @param pCfg Pointer to PDMAUDIOSTREAMCFG to use.
+ * @param ppGstStrmOut Pointer where to return the guest guest input stream on success.
*/
- DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetWritable, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(int, pfnCreateOut, (PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
+ PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut));
/**
- * Returns the status of a specific audio stream.
+ * Destroys a guest input stream.
*
- * @returns Audio stream status
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
+ * @param pGstStrmIn Pointer to guest input stream.
*/
- DECLR3CALLBACKMEMBER(PDMAUDIOSTRMSTS, pfnStreamGetStatus, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(void, pfnDestroyIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
/**
- * Sets the audio volume of a specific audio stream.
+ * Destroys a guest output stream.
*
- * @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
- * @param pVol Pointer to audio volume structure to set the stream's audio volume to.
+ * @param pGstStrmOut Pointer to guest output stream.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamSetVolume, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol));
+ DECLR3CALLBACKMEMBER(void, pfnDestroyOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
/**
- * Plays (transfers) available audio samples via the host backend. Only works with output streams.
+ * Plays (transfers) all available samples via the connected host backend.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param pcSamplesPlayed Number of samples played. Optional.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed));
-
- /**
- * Captures (transfers) available audio samples from the host backend. Only works with input streams.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pcSamplesCaptured Number of samples captured. Optional.
- */
- DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesCaptured));
+ DECLR3CALLBACKMEMBER(int, pfnPlayOut, (PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed));
#ifdef VBOX_WITH_AUDIO_CALLBACKS
DECLR3CALLBACKMEMBER(int, pfnRegisterCallbacks, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOCALLBACK paCallbacks, size_t cCallbacks));
@@ -900,28 +630,28 @@ typedef struct PDMIAUDIOCONNECTOR
} PDMIAUDIOCONNECTOR;
/** PDMIAUDIOCONNECTOR interface ID. */
-#define PDMIAUDIOCONNECTOR_IID "C850CCE0-C5F4-42AB-BFC5-BACB41A8284D"
-
+#define PDMIAUDIOCONNECTOR_IID "8f8ca10e-9039-423c-9a77-0014aaa98626"
/**
* Assigns all needed interface callbacks for an audio backend.
*
- * @param a_Prefix The function name prefix.
+ * @param a_NamePrefix The function name prefix.
*/
-#define PDMAUDIO_IHOSTAUDIO_CALLBACKS(a_Prefix) \
+#define PDMAUDIO_IHOSTAUDIO_CALLBACKS(a_NamePrefix) \
do { \
- pThis->IHostAudio.pfnInit = RT_CONCAT(a_Prefix,Init); \
- pThis->IHostAudio.pfnShutdown = RT_CONCAT(a_Prefix,Shutdown); \
- pThis->IHostAudio.pfnGetConfig = RT_CONCAT(a_Prefix,GetConfig); \
- pThis->IHostAudio.pfnGetStatus = RT_CONCAT(a_Prefix,GetStatus); \
- pThis->IHostAudio.pfnStreamCreate = RT_CONCAT(a_Prefix,StreamCreate); \
- pThis->IHostAudio.pfnStreamDestroy = RT_CONCAT(a_Prefix,StreamDestroy); \
- pThis->IHostAudio.pfnStreamControl = RT_CONCAT(a_Prefix,StreamControl); \
- pThis->IHostAudio.pfnStreamGetStatus = RT_CONCAT(a_Prefix,StreamGetStatus); \
- pThis->IHostAudio.pfnStreamIterate = RT_CONCAT(a_Prefix,StreamIterate); \
- pThis->IHostAudio.pfnStreamPlay = RT_CONCAT(a_Prefix,StreamPlay); \
- pThis->IHostAudio.pfnStreamCapture = RT_CONCAT(a_Prefix,StreamCapture); \
+ pThis->IHostAudio.pfnInit = RT_CONCAT(a_NamePrefix,Init); \
+ pThis->IHostAudio.pfnShutdown = RT_CONCAT(a_NamePrefix,Shutdown); \
+ pThis->IHostAudio.pfnInitIn = RT_CONCAT(a_NamePrefix,InitIn); \
+ pThis->IHostAudio.pfnInitOut = RT_CONCAT(a_NamePrefix,InitOut); \
+ pThis->IHostAudio.pfnControlOut = RT_CONCAT(a_NamePrefix,ControlOut); \
+ pThis->IHostAudio.pfnControlIn = RT_CONCAT(a_NamePrefix,ControlIn); \
+ pThis->IHostAudio.pfnFiniIn = RT_CONCAT(a_NamePrefix,FiniIn); \
+ pThis->IHostAudio.pfnFiniOut = RT_CONCAT(a_NamePrefix,FiniOut); \
+ pThis->IHostAudio.pfnIsEnabled = RT_CONCAT(a_NamePrefix,IsEnabled); \
+ pThis->IHostAudio.pfnPlayOut = RT_CONCAT(a_NamePrefix,PlayOut); \
+ pThis->IHostAudio.pfnCaptureIn = RT_CONCAT(a_NamePrefix,CaptureIn); \
+ pThis->IHostAudio.pfnGetConf = RT_CONCAT(a_NamePrefix,GetConf); \
} while (0)
/** Pointer to a host audio interface. */
@@ -948,103 +678,111 @@ typedef struct PDMIHOSTAUDIO
DECLR3CALLBACKMEMBER(void, pfnShutdown, (PPDMIHOSTAUDIO pInterface));
/**
- * Returns the configuration from the host audio (backend) driver.
+ * Initialize the host-specific audio device for input stream.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pBackendCfg Pointer where to store the backend audio configuration to.
+ * @param pHstStrmIn Pointer to host input stream.
+ * @param pCfgReq Pointer to requested stream configuration.
+ * @param pCfgAcq Pointer to acquired stream configuration.
+ * @param enmRecSource Specifies the type of recording source to be initialized.
+ * @param pcSamples Returns how many samples the backend can handle. Optional.
*/
- DECLR3CALLBACKMEMBER(int, pfnGetConfig, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg));
+ DECLR3CALLBACKMEMBER(int, pfnInitIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples));
/**
- * Returns the current status from the host audio (backend) driver.
+ * Initialize the host-specific output device for output stream.
*
- * @returns PDMAUDIOBACKENDSTS enum.
+ * @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param enmDir Audio direction to get status for. Pass PDMAUDIODIR_ANY for overall status.
+ * @param pHstStrmOut Pointer to host output stream.
+ * @param pCfgReq Pointer to requested stream configuration.
+ * @param pCfgAcq Pointer to acquired stream configuration.
+ * @param pcSamples Returns how many samples the backend can handle. Optional.
*/
- DECLR3CALLBACKMEMBER(PDMAUDIOBACKENDSTS, pfnGetStatus, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir));
+ DECLR3CALLBACKMEMBER(int, pfnInitOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, uint32_t *pcSamples));
/**
- * Creates an audio stream using the requested stream configuration.
- * If a backend is not able to create this configuration, it will return its best match in the acquired configuration
- * structure on success.
+ * Control the host audio device for an input stream.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
- * @param pCfgReq Pointer to requested stream configuration.
- * @param pCfgAcq Pointer to acquired stream configuration.
+ * @param pHstStrmOut Pointer to host output stream.
+ * @param enmStreamCmd The stream command to issue.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamCreate, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq));
+ DECLR3CALLBACKMEMBER(int, pfnControlOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd));
/**
- * Destroys an audio stream.
+ * Control the host audio device for an output stream.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
+ * @param pHstStrmOut Pointer to host output stream.
+ * @param enmStreamCmd The stream command to issue.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamDestroy, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(int, pfnControlIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd));
/**
- * Controls an audio stream.
+ * Ends the host audio input streamm.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
- * @param enmStreamCmd The stream command to issue.
+ * @param pHstStrmIn Pointer to host input stream.
+ */
+ DECLR3CALLBACKMEMBER(int, pfnFiniIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn));
+
+ /**
+ * Ends the host output stream.
+ *
+ * @returns VBox status code.
+ * @param pInterface Pointer to the interface structure containing the called function pointer.
+ * @param pHstStrmOut Pointer to host output stream.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamControl, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd));
+ DECLR3CALLBACKMEMBER(int, pfnFiniOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut));
/**
* Returns whether the specified audio direction in the backend is enabled or not.
*
- * @returns PDMAUDIOSTRMSTS
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param enmDir Audio direction to check status for.
*/
- DECLR3CALLBACKMEMBER(PDMAUDIOSTRMSTS, pfnStreamGetStatus, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(bool, pfnIsEnabled, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir));
/**
- * Gives the host backend the chance to do some (necessary) iteration work.
+ * Plays a host audio stream.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
+ * @param pHstStrmOut Pointer to host output stream.
+ * @param pcSamplesPlayed Pointer to number of samples captured.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamIterate, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream));
+ DECLR3CALLBACKMEMBER(int, pfnPlayOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, uint32_t *pcSamplesPlayed));
/**
- * Plays (writes to) an audio (output) stream.
+ * Records audio to input stream.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
- * @param pvBuf Pointer to audio data buffer to play. Currently not used and must be NULL.
- * @param cbBuf Size (in bytes) of audio data buffer. Currently not used and must be 0.
- * @param pcbWritten Returns number of bytes written. Optional.
+ * @param pHstStrmIn Pointer to host input stream.
+ * @param pcSamplesCaptured Pointer to number of samples captured.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten));
+ DECLR3CALLBACKMEMBER(int, pfnCaptureIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, uint32_t *pcSamplesCaptured));
/**
- * Captures (reads from) an audio (input) stream.
+ * Gets the configuration from the host audio (backend) driver.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pStream Pointer to audio stream.
- * @param pvBuf Buffer where to store read audio data. Currently not used and must be NULL.
- * @param cbBuf Size (in bytes) of buffer. Currently not used and must be 0.
- * @param pcbRead Returns number of bytes read. Optional.
+ * @param pBackendCfg Pointer where to store the backend audio configuration to.
*/
- DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead));
+ DECLR3CALLBACKMEMBER(int, pfnGetConf, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg));
} PDMIHOSTAUDIO;
/** PDMIHOSTAUDIO interface ID. */
-#define PDMIHOSTAUDIO_IID "2922C325-79D3-4E66-B60F-0082878522FE"
+#define PDMIHOSTAUDIO_IID "BCECDD48-D5E8-49AE-9C1A-85ED64D88638"
/** @} */
-#endif /* !___VBox_vmm_pdmaudioifs_h */
+#endif
diff --git a/include/VBox/vmm/pdmaudioifs_50.h b/include/VBox/vmm/pdmaudioifs_50.h
deleted file mode 100644
index 1e5dc98..0000000
--- a/include/VBox/vmm/pdmaudioifs_50.h
+++ /dev/null
@@ -1,788 +0,0 @@
-/** @file
- * PDM - Pluggable Device Manager, audio interfaces.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-#ifndef ___VBox_vmm_pdmaudioifs_h
-#define ___VBox_vmm_pdmaudioifs_h
-
-#include <VBox/types.h>
-#include <iprt/critsect.h>
-#include <iprt/list.h>
-
-
-/** @defgroup grp_pdm_ifs_audio PDM Audio Interfaces
- * @ingroup grp_pdm_interfaces
- * @{
- */
-
-/** @todo r=bird: Don't be lazy with documentation! */
-typedef uint32_t PDMAUDIODRVFLAGS;
-
-/** No flags set. */
-/** @todo r=bird: s/PDMAUDIODRVFLAG/PDMAUDIODRV_FLAGS/g */
-#define PDMAUDIODRVFLAG_NONE 0
-/** Marks a primary audio driver which is critical
- * when running the VM. */
-#define PDMAUDIODRVFLAG_PRIMARY RT_BIT(0)
-
-/**
- * Audio format in signed or unsigned variants.
- */
-typedef enum PDMAUDIOFMT
-{
- AUD_FMT_INVALID,
- AUD_FMT_U8,
- AUD_FMT_S8,
- AUD_FMT_U16,
- AUD_FMT_S16,
- AUD_FMT_U32,
- AUD_FMT_S32,
- /** Hack to blow the type up to 32-bit. */
- AUD_FMT_32BIT_HACK = 0x7fffffff
-} PDMAUDIOFMT;
-
-/**
- * Audio configuration of a certain backend.
- */
-typedef struct PDMAUDIOBACKENDCFG
-{
- size_t cbStreamOut;
- size_t cbStreamIn;
- uint32_t cMaxHstStrmsOut;
- uint32_t cMaxHstStrmsIn;
-} PDMAUDIOBACKENDCFG, *PPDMAUDIOBACKENDCFG;
-
-/**
- * An audio sample. At the moment stereo (left + right channels) only.
- * @todo Replace this with a more generic union
- * which then also could handle 2.1 or 5.1 sound.
- */
-typedef struct PDMAUDIOSAMPLE
-{
- int64_t i64LSample;
- int64_t i64RSample;
-} PDMAUDIOSAMPLE, *PPDMAUDIOSAMPLE;
-
-typedef enum PDMAUDIOENDIANNESS
-{
- /** The usual invalid endian. */
- PDMAUDIOENDIANNESS_INVALID,
- /** Little endian. */
- PDMAUDIOENDIANNESS_LITTLE,
- /** Bit endian. */
- PDMAUDIOENDIANNESS_BIG,
- /** Endianness doesn't have a meaning in the context. */
- PDMAUDIOENDIANNESS_NA,
- /** The end of the valid endian values (exclusive). */
- PDMAUDIOENDIANNESS_END,
- /** Hack to blow the type up to 32-bit. */
- PDMAUDIOENDIANNESS_32BIT_HACK = 0x7fffffff
-} PDMAUDIOENDIANNESS;
-
-typedef struct PDMAUDIOSTREAMCFG
-{
- /** Frequency in Hertz (Hz). */
- uint32_t uHz;
- /** Number of channels (2 for stereo). */
- uint8_t cChannels;
- /** Audio format. */
- PDMAUDIOFMT enmFormat;
- /** @todo Use RT_LE2H_*? */
- PDMAUDIOENDIANNESS enmEndianness;
-} PDMAUDIOSTREAMCFG, *PPDMAUDIOSTREAMCFG;
-
-#if defined(RT_LITTLE_ENDIAN)
-# define PDMAUDIOHOSTENDIANNESS PDMAUDIOENDIANNESS_LITTLE
-#elif defined(RT_BIG_ENDIAN)
-# define PDMAUDIOHOSTENDIANNESS PDMAUDIOENDIANNESS_BIG
-#else
-# error "Port me!"
-#endif
-
-/**
- * Audio direction.
- */
-typedef enum PDMAUDIODIR
-{
- PDMAUDIODIR_UNKNOWN = 0,
- PDMAUDIODIR_IN = 1,
- PDMAUDIODIR_OUT = 2,
- PDMAUDIODIR_DUPLEX = 3,
- /** Hack to blow the type up to 32-bit. */
- PDMAUDIODIR_32BIT_HACK = 0x7fffffff
-} PDMAUDIODIR;
-
-/**
- * Audio mixer controls.
- */
-typedef enum PDMAUDIOMIXERCTL
-{
- PDMAUDIOMIXERCTL_UNKNOWN = 0,
- PDMAUDIOMIXERCTL_VOLUME,
- PDMAUDIOMIXERCTL_PCM,
- PDMAUDIOMIXERCTL_LINE_IN,
- PDMAUDIOMIXERCTL_MIC_IN,
- /** Hack to blow the type up to 32-bit. */
- PDMAUDIOMIXERCTL_32BIT_HACK = 0x7fffffff
-} PDMAUDIOMIXERCTL;
-
-/**
- * Audio recording sources.
- */
-typedef enum PDMAUDIORECSOURCE
-{
- PDMAUDIORECSOURCE_UNKNOWN = 0,
- PDMAUDIORECSOURCE_MIC,
- PDMAUDIORECSOURCE_CD,
- PDMAUDIORECSOURCE_VIDEO,
- PDMAUDIORECSOURCE_AUX,
- PDMAUDIORECSOURCE_LINE_IN,
- PDMAUDIORECSOURCE_PHONE,
- /** Hack to blow the type up to 32-bit. */
- PDMAUDIORECSOURCE_32BIT_HACK = 0x7fffffff
-} PDMAUDIORECSOURCE;
-
-/**
- * Audio stream commands. Used in the audio connector
- * as well as in the actual host backends.
- */
-typedef enum PDMAUDIOSTREAMCMD
-{
- /** Unknown command, do not use. */
- PDMAUDIOSTREAMCMD_UNKNOWN = 0,
- /** Enables the stream. */
- PDMAUDIOSTREAMCMD_ENABLE,
- /** Disables the stream. */
- PDMAUDIOSTREAMCMD_DISABLE,
- /** Pauses the stream. */
- PDMAUDIOSTREAMCMD_PAUSE,
- /** Resumes the stream. */
- PDMAUDIOSTREAMCMD_RESUME,
- /** Hack to blow the type up to 32-bit. */
- PDMAUDIOSTREAMCMD_32BIT_HACK = 0x7fffffff
-} PDMAUDIOSTREAMCMD;
-
-/**
- * Properties of audio streams for host/guest
- * for in or out directions.
- */
-typedef struct PDMPCMPROPS
-{
- /** Sample width. Bits per sample. */
- uint8_t cBits;
- /** Signed or unsigned sample. */
- bool fSigned;
- /** Shift count used for faster calculation of various
- * values, such as the alignment, bytes to samples and so on.
- * Depends on number of stream channels and the stream format
- * being used.
- *
- ** @todo Use some RTAsmXXX functions instead?
- */
- uint8_t cShift;
- /** Number of audio channels. */
- uint8_t cChannels;
- /** Alignment mask. */
- uint32_t uAlign;
- /** Sample frequency in Hertz (Hz). */
- uint32_t uHz;
- /** Bandwidth (bytes/s). */
- uint32_t cbPerSec;
- /** Whether the endianness is swapped or not. */
- bool fSwapEndian;
-} PDMPCMPROPS, *PPDMPCMPROPS;
-
-/**
- * Structure keeping an audio volume level.
- */
-typedef struct PDMAUDIOVOLUME
-{
- /** Set to @c true if this stream is muted, @c false if not. */
- bool fMuted;
- /** Left channel volume. */
- uint32_t uLeft;
- /** Right channel volume. */
- uint32_t uRight;
-} PDMAUDIOVOLUME, *PPDMAUDIOVOLUME;
-
-/**
- * Structure for holding rate processing information
- * of a source + destination audio stream. This is needed
- * because both streams can differ regarding their rates
- * and therefore need to be treated accordingly.
- */
-typedef struct PDMAUDIOSTRMRATE
-{
- /** Current (absolute) offset in the output
- * (destination) stream. */
- uint64_t dstOffset;
- /** Increment for moving dstOffset for the
- * destination stream. This is needed because the
- * source <-> destination rate might be different. */
- uint64_t dstInc;
- /** Current (absolute) offset in the input
- * stream. */
- uint32_t srcOffset;
- /** Last processed sample of the input stream.
- * Needed for interpolation. */
- PDMAUDIOSAMPLE srcSampleLast;
-} PDMAUDIOSTRMRATE, *PPDMAUDIOSTRMRATE;
-
-/**
- * Note: All internal handling is done in samples,
- * not in bytes!
- */
-typedef uint32_t PDMAUDIOMIXBUFFMT;
-typedef PDMAUDIOMIXBUFFMT *PPDMAUDIOMIXBUFFMT;
-
-typedef struct PDMAUDIOMIXBUF *PPDMAUDIOMIXBUF;
-typedef struct PDMAUDIOMIXBUF
-{
- RTLISTNODE Node;
- /** Name of the buffer. */
- char *pszName;
- /** Sample buffer. */
- PPDMAUDIOSAMPLE pSamples;
- /** Size of the sample buffer (in samples). */
- uint32_t cSamples;
- /** The current read/write position (in samples)
- * in the samples buffer. */
- uint32_t offReadWrite;
- /**
- * Total samples already mixed down to the parent buffer (if any). Always starting at
- * the parent's offReadWrite position.
- *
- * Note: Count always is specified in parent samples, as the sample count can differ between parent
- * and child.
- */
- uint32_t cMixed;
- uint32_t cProcessed;
- /** Pointer to parent buffer (if any). */
- PPDMAUDIOMIXBUF pParent;
- /** List of children mix buffers to keep in sync with (if being a parent buffer). */
- RTLISTANCHOR lstBuffers;
- /** Intermediate structure for buffer conversion tasks. */
- PPDMAUDIOSTRMRATE pRate;
- /** Current volume used for mixing. */
- PDMAUDIOVOLUME Volume;
- /** This buffer's audio format. */
- PDMAUDIOMIXBUFFMT AudioFmt;
- /**
- * Ratio of the associated parent stream's frequency by this stream's
- * frequency (1<<32), represented as a signed 64 bit integer.
- *
- * For example, if the parent stream has a frequency of 44 khZ, and this
- * stream has a frequency of 11 kHz, the ration then would be
- * (44/11 * (1 << 32)).
- *
- * Currently this does not get changed once assigned.
- */
- int64_t iFreqRatio;
- /* For quickly converting samples <-> bytes and
- * vice versa. */
- uint8_t cShift;
-} PDMAUDIOMIXBUF;
-
-/** Stream status flag. To be used with PDMAUDIOSTRMSTS_FLAG_ flags. */
-typedef uint32_t PDMAUDIOSTRMSTS;
-
-/** No flags being set. */
-#define PDMAUDIOSTRMSTS_FLAG_NONE 0
-/** Whether this stream is enabled or disabled. */
-#define PDMAUDIOSTRMSTS_FLAG_ENABLED RT_BIT_32(0)
-/** Whether this stream has been paused or not. This also implies
- * that this is an enabled stream! */
-#define PDMAUDIOSTRMSTS_FLAG_PAUSED RT_BIT_32(1)
-/** Whether this stream was marked as being disabled
- * but there are still associated guest output streams
- * which rely on its data. */
-#define PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE RT_BIT_32(2)
-/** Validation mask. */
-#define PDMAUDIOSTRMSTS_VALID_MASK UINT32_C(0x00000007)
-
-/**
- * Represents an audio input on the host of a certain
- * backend (e.g. DirectSound, PulseAudio etc).
- *
- * One host audio input is assigned to exactly one parent
- * guest input stream.
- */
-struct PDMAUDIOGSTSTRMIN;
-typedef PDMAUDIOGSTSTRMIN *PPDMAUDIOGSTSTRMIN;
-
-typedef struct PDMAUDIOHSTSTRMIN
-{
- /** List node. */
- RTLISTNODE Node;
- /** PCM properties. */
- PDMPCMPROPS Props;
- /** Stream status flag. */
- PDMAUDIOSTRMSTS fStatus;
- /** Critical section for serializing access. */
- RTCRITSECT CritSect;
- /** This stream's mixing buffer. */
- PDMAUDIOMIXBUF MixBuf;
- /** Pointer to (parent) guest stream. */
- PPDMAUDIOGSTSTRMIN pGstStrmIn;
-} PDMAUDIOHSTSTRMIN, *PPDMAUDIOHSTSTRMIN;
-
-/*
- * Represents an audio output on the host through a certain
- * backend (e.g. DirectSound, PulseAudio etc).
- *
- * One host audio output can have multiple (1:N) guest outputs
- * assigned.
- */
-typedef struct PDMAUDIOHSTSTRMOUT
-{
- /** List node. */
- RTLISTNODE Node;
- /** Stream properites. */
- PDMPCMPROPS Props;
- /** Stream status flag. */
- PDMAUDIOSTRMSTS fStatus;
- /** Critical section for serializing access. */
- RTCRITSECT CritSect;
- /** This stream's mixing buffer. */
- PDMAUDIOMIXBUF MixBuf;
- /** Associated guest output streams. */
- RTLISTANCHOR lstGstStrmOut;
-} PDMAUDIOHSTSTRMOUT, *PPDMAUDIOHSTSTRMOUT;
-
-/**
- * Guest audio stream state.
- */
-typedef struct PDMAUDIOGSTSTRMSTATE
-{
- /** Guest audio out stream active or not. */
- bool fActive;
- /** Guest audio output stream has some samples or not. */
- bool fEmpty;
- /** Name of this stream. */
- char *pszName;
- /** Number of references to this stream. Only can be
- * destroyed if the reference count is reaching 0. */
- uint8_t cRefs;
-} PDMAUDIOGSTSTRMSTATE, *PPDMAUDIOGSTSTRMSTATE;
-
-/**
- * Represents an audio input from the guest (that is, from the
- * emulated device, e.g. Intel HDA).
- *
- * Each guest input can have multiple host input streams.
- */
-typedef struct PDMAUDIOGSTSTRMIN
-{
- /** Guest stream properites. */
- PDMPCMPROPS Props;
- /** Current stream state. */
- PDMAUDIOGSTSTRMSTATE State;
- /** This stream's mixing buffer. */
- PDMAUDIOMIXBUF MixBuf;
- /** Pointer to associated host input stream. */
- PPDMAUDIOHSTSTRMIN pHstStrmIn;
-} PDMAUDIOGSTSTRMIN, *PPDMAUDIOGSTSTRMIN;
-
-/**
- * Represents an audio output from the guest (that is, from the
- * emulated device, e.g. Intel HDA).
- *
- * Each guest output is assigned to a single host output.
- */
-typedef struct PDMAUDIOGSTSTRMOUT
-{
- /** List node. */
- RTLISTNODE Node;
- /** Guest output stream properites. */
- PDMPCMPROPS Props;
- /** Current stream state. */
- PDMAUDIOGSTSTRMSTATE State;
- /** This stream's mixing buffer. */
- PDMAUDIOMIXBUF MixBuf;
- /** Pointer to the associated host output stream. */
- PPDMAUDIOHSTSTRMOUT pHstStrmOut;
-} PDMAUDIOGSTSTRMOUT, *PPDMAUDIOGSTSTRMOUT;
-
-/** Pointer to a audio connector interface. */
-typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR;
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
-/**
- * Audio callback types. These are all kept generic as those
- * are used by all device emulations across all backends.
- */
-typedef enum PDMAUDIOCALLBACKTYPE
-{
- PDMAUDIOCALLBACKTYPE_GENERIC = 0,
- PDMAUDIOCALLBACKTYPE_INPUT,
- PDMAUDIOCALLBACKTYPE_OUTPUT
-} PDMAUDIOCALLBACKTYPE;
-
-/**
- * Callback data for audio input.
- */
-typedef struct PDMAUDIOCALLBACKDATAIN
-{
- /** Input: How many bytes are availabe as input for passing
- * to the device emulation. */
- uint32_t cbInAvail;
- /** Output: How many bytes have been read. */
- uint32_t cbOutRead;
-} PDMAUDIOCALLBACKDATAIN, *PPDMAUDIOCALLBACKDATAIN;
-
-/**
- * Callback data for audio output.
- */
-typedef struct PDMAUDIOCALLBACKDATAOUT
-{
- /** Input: How many bytes are free for the device emulation to write. */
- uint32_t cbInFree;
- /** Output: How many bytes were written by the device emulation. */
- uint32_t cbOutWritten;
-} PDMAUDIOCALLBACKDATAOUT, *PPDMAUDIOCALLBACKDATAOUT;
-
-/**
- * Structure for keeping an audio callback.
- */
-typedef struct PDMAUDIOCALLBACK
-{
- RTLISTANCHOR Node;
- PDMAUDIOCALLBACKTYPE enmType;
- void *pvCtx;
- size_t cbCtx;
- DECLR3CALLBACKMEMBER(int, pfnCallback, (PDMAUDIOCALLBACKTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser));
-} PDMAUDIOCALLBACK, *PPDMAUDIOCALLBACK;
-#endif
-
-/**
- * Audio connector interface (up).
- */
-typedef struct PDMIAUDIOCONNECTOR
-{
- DECLR3CALLBACKMEMBER(int, pfnQueryStatus, (PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcbAvailIn, uint32_t *pcbFreeOut, uint32_t *pcSamplesLive));
-
- /**
- * Reads PCM audio data from the host (input).
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmIn Pointer to guest input stream to write to.
- * @param pvBuf Where to store the read data.
- * @param cbBuf Number of bytes to read.
- * @param pcbRead Bytes of audio data read. Optional.
- */
- DECLR3CALLBACKMEMBER(int, pfnRead, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead));
-
- /**
- * Writes PCM audio data to the host (output).
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmOut Pointer to guest output stream to read from.
- * @param pvBuf Audio data to be written.
- * @param cbBuf Number of bytes to be written.
- * @param pcbWritten Bytes of audio data written. Optional.
- */
- DECLR3CALLBACKMEMBER(int, pfnWrite, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten));
-
- /**
- * Retrieves the current configuration of the host audio backend.
- *
- * @returns VBox status code.
- *
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pCfg Where to store the host audio backend configuration data.
- */
- DECLR3CALLBACKMEMBER(int, pfnGetConfiguration, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg));
-
- /**
- * Checks whether a specific guest input stream is active or not.
- *
- * @returns Whether the specified stream is active or not.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmIn Pointer to guest input stream.
- */
- DECLR3CALLBACKMEMBER(bool, pfnIsActiveIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
-
- /**
- * Checks whether a specific guest output stream is active or not.
- *
- * @returns Whether the specified stream is active or not.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmOut Pointer to guest output stream.
- */
- DECLR3CALLBACKMEMBER(bool, pfnIsActiveOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
-
- /**
- * Checks whether the specified guest input stream is in a valid (working) state.
- *
- * @returns True if a host voice in is available, false if not.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmIn Pointer to guest input stream to check.
- */
- DECLR3CALLBACKMEMBER(bool, pfnIsValidIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
-
- /**
- * Checks whether the specified guest output stream is in a valid (working) state.
- *
- * @returns True if a host voice out is available, false if not.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmOut Pointer to guest output stream to check.
- */
- DECLR3CALLBACKMEMBER(bool, pfnIsValidOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
-
- /**
- * Enables a specific guest output stream and starts the audio device.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmOut Pointer to guest output stream.
- * @param fEnable Whether to enable or disable the specified output stream.
- */
- DECLR3CALLBACKMEMBER(int, pfnEnableOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable));
-
- /**
- * Enables a specific guest input stream and starts the audio device.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmIn Pointer to guest input stream.
- * @param fEnable Whether to enable or disable the specified input stream.
- */
- DECLR3CALLBACKMEMBER(int, pfnEnableIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn, bool fEnable));
-
- /**
- * Creates a guest input stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pszName Name of the audio channel.
- * @param enmRecSource Specifies the type of recording source to be opened.
- * @param pCfg Pointer to PDMAUDIOSTREAMCFG to use.
- * @param ppGstStrmIn Pointer where to return the guest guest input stream on success.
- */
- DECLR3CALLBACKMEMBER(int, pfnCreateIn, (PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
- PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg,
- PPDMAUDIOGSTSTRMIN *ppGstStrmIn));
- /**
- * Creates a guest output stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pszName Name of the audio channel.
- * @param pCfg Pointer to PDMAUDIOSTREAMCFG to use.
- * @param ppGstStrmOut Pointer where to return the guest guest input stream on success.
- */
- DECLR3CALLBACKMEMBER(int, pfnCreateOut, (PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
- PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut));
-
- /**
- * Destroys a guest input stream.
- *
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmIn Pointer to guest input stream.
- */
- DECLR3CALLBACKMEMBER(void, pfnDestroyIn, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn));
-
- /**
- * Destroys a guest output stream.
- *
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pGstStrmOut Pointer to guest output stream.
- */
- DECLR3CALLBACKMEMBER(void, pfnDestroyOut, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut));
-
- /**
- * Plays (transfers) all available samples via the connected host backend.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pcSamplesPlayed Number of samples played. Optional.
- */
- DECLR3CALLBACKMEMBER(int, pfnPlayOut, (PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed));
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- DECLR3CALLBACKMEMBER(int, pfnRegisterCallbacks, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOCALLBACK paCallbacks, size_t cCallbacks));
- DECLR3CALLBACKMEMBER(int, pfnCallback, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIOCALLBACKTYPE enmType, void *pvUser, size_t cbUser));
-#endif
-
-} PDMIAUDIOCONNECTOR;
-
-/** PDMIAUDIOCONNECTOR interface ID. */
-#define PDMIAUDIOCONNECTOR_IID "8f8ca10e-9039-423c-9a77-0014aaa98626"
-
-
-/**
- * Assigns all needed interface callbacks for an audio backend.
- *
- * @param a_NamePrefix The function name prefix.
- */
-#define PDMAUDIO_IHOSTAUDIO_CALLBACKS(a_NamePrefix) \
- do { \
- pThis->IHostAudio.pfnInit = RT_CONCAT(a_NamePrefix,Init); \
- pThis->IHostAudio.pfnShutdown = RT_CONCAT(a_NamePrefix,Shutdown); \
- pThis->IHostAudio.pfnInitIn = RT_CONCAT(a_NamePrefix,InitIn); \
- pThis->IHostAudio.pfnInitOut = RT_CONCAT(a_NamePrefix,InitOut); \
- pThis->IHostAudio.pfnControlOut = RT_CONCAT(a_NamePrefix,ControlOut); \
- pThis->IHostAudio.pfnControlIn = RT_CONCAT(a_NamePrefix,ControlIn); \
- pThis->IHostAudio.pfnFiniIn = RT_CONCAT(a_NamePrefix,FiniIn); \
- pThis->IHostAudio.pfnFiniOut = RT_CONCAT(a_NamePrefix,FiniOut); \
- pThis->IHostAudio.pfnIsEnabled = RT_CONCAT(a_NamePrefix,IsEnabled); \
- pThis->IHostAudio.pfnPlayOut = RT_CONCAT(a_NamePrefix,PlayOut); \
- pThis->IHostAudio.pfnCaptureIn = RT_CONCAT(a_NamePrefix,CaptureIn); \
- pThis->IHostAudio.pfnGetConf = RT_CONCAT(a_NamePrefix,GetConf); \
- } while (0)
-
-/** Pointer to a host audio interface. */
-typedef struct PDMIHOSTAUDIO *PPDMIHOSTAUDIO;
-/**
- * PDM host audio interface.
- */
-typedef struct PDMIHOSTAUDIO
-{
- /**
- * Initialize the host-specific audio device.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- */
- DECLR3CALLBACKMEMBER(int, pfnInit, (PPDMIHOSTAUDIO pInterface));
-
- /**
- * Shuts down the host-specific audio device.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- */
- DECLR3CALLBACKMEMBER(void, pfnShutdown, (PPDMIHOSTAUDIO pInterface));
-
- /**
- * Initialize the host-specific audio device for input stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pHstStrmIn Pointer to host input stream.
- * @param pCfgReq Pointer to requested stream configuration.
- * @param pCfgAcq Pointer to acquired stream configuration.
- * @param enmRecSource Specifies the type of recording source to be initialized.
- * @param pcSamples Returns how many samples the backend can handle. Optional.
- */
- DECLR3CALLBACKMEMBER(int, pfnInitIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples));
-
- /**
- * Initialize the host-specific output device for output stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pHstStrmOut Pointer to host output stream.
- * @param pCfgReq Pointer to requested stream configuration.
- * @param pCfgAcq Pointer to acquired stream configuration.
- * @param pcSamples Returns how many samples the backend can handle. Optional.
- */
- DECLR3CALLBACKMEMBER(int, pfnInitOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, uint32_t *pcSamples));
-
- /**
- * Control the host audio device for an input stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pHstStrmOut Pointer to host output stream.
- * @param enmStreamCmd The stream command to issue.
- */
- DECLR3CALLBACKMEMBER(int, pfnControlOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd));
-
- /**
- * Control the host audio device for an output stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pHstStrmOut Pointer to host output stream.
- * @param enmStreamCmd The stream command to issue.
- */
- DECLR3CALLBACKMEMBER(int, pfnControlIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd));
-
- /**
- * Ends the host audio input streamm.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pHstStrmIn Pointer to host input stream.
- */
- DECLR3CALLBACKMEMBER(int, pfnFiniIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn));
-
- /**
- * Ends the host output stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pHstStrmOut Pointer to host output stream.
- */
- DECLR3CALLBACKMEMBER(int, pfnFiniOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut));
-
- /**
- * Returns whether the specified audio direction in the backend is enabled or not.
- *
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param enmDir Audio direction to check status for.
- */
- DECLR3CALLBACKMEMBER(bool, pfnIsEnabled, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir));
-
- /**
- * Plays a host audio stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pHstStrmOut Pointer to host output stream.
- * @param pcSamplesPlayed Pointer to number of samples captured.
- */
- DECLR3CALLBACKMEMBER(int, pfnPlayOut, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, uint32_t *pcSamplesPlayed));
-
- /**
- * Records audio to input stream.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pHstStrmIn Pointer to host input stream.
- * @param pcSamplesCaptured Pointer to number of samples captured.
- */
- DECLR3CALLBACKMEMBER(int, pfnCaptureIn, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, uint32_t *pcSamplesCaptured));
-
- /**
- * Gets the configuration from the host audio (backend) driver.
- *
- * @returns VBox status code.
- * @param pInterface Pointer to the interface structure containing the called function pointer.
- * @param pBackendCfg Pointer where to store the backend audio configuration to.
- */
- DECLR3CALLBACKMEMBER(int, pfnGetConf, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg));
-
-} PDMIHOSTAUDIO;
-
-/** PDMIHOSTAUDIO interface ID. */
-#define PDMIHOSTAUDIO_IID "BCECDD48-D5E8-49AE-9C1A-85ED64D88638"
-
-/** @} */
-
-#endif
-
diff --git a/include/VBox/vmm/pdmpcidev.h b/include/VBox/vmm/pdmpcidev.h
index 3e6282d..7ebdaaf 100644
--- a/include/VBox/vmm/pdmpcidev.h
+++ b/include/VBox/vmm/pdmpcidev.h
@@ -622,6 +622,17 @@ DECLINLINE(uint8_t) PDMPciDevGetInterruptPin(PPDMPCIDEV pPciDev)
/** @} */
+/* Special purpose "interface" for getting access to the PDMPCIDEV structure
+ * of a ich9pcibridge instance. This is useful for unusual raw or pass-through
+ * implementation which need to provide different PCI configuration space
+ * content for bridges (as long as we don't allow pass-through of bridges or
+ * custom bridge device implementations). */
+typedef PPDMPCIDEV PPDMIICH9BRIDGEPDMPCIDEV;
+typedef PDMPCIDEV PDMIICH9BRIDGEPDMPCIDEV;
+
+#define PDMIICH9BRIDGEPDMPCIDEV_IID "785c74b1-8510-4458-9422-56750bf221db"
+
+
/** @} */
#endif
diff --git a/include/VBox/vmm/vm.h b/include/VBox/vmm/vm.h
index e005234..90c1d41 100644
--- a/include/VBox/vmm/vm.h
+++ b/include/VBox/vmm/vm.h
@@ -409,7 +409,10 @@ typedef struct VMCPU
#define VMCPU_FF_INTERRUPT_SMI RT_BIT_32(VMCPU_FF_INTERRUPT_SMI_BIT)
/** PDM critical section unlocking is pending, process promptly upon return to R3. */
#define VMCPU_FF_PDM_CRITSECT RT_BIT_32(5)
-/** This action forces the VCPU out of the halted state. */
+/** Special EM internal force flag that is used by EMUnhaltAndWakeUp() to force
+ * the virtual CPU out of the next (/current) halted state. It is not processed
+ * nor cleared by emR3ForcedActions (similar to VMCPU_FF_BLOCK_NMIS), instead it
+ * is cleared the next time EM leaves the HALTED state. */
#define VMCPU_FF_UNHALT RT_BIT_32(6)
/** Pending IEM action (bit number). */
#define VMCPU_FF_IEM_BIT 7
@@ -532,7 +535,7 @@ typedef struct VMCPU
#define VM_FF_NORMAL_PRIORITY_MASK ( VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA \
| VM_FF_REM_HANDLER_NOTIFY | VM_FF_EMT_RENDEZVOUS)
/** Normal priority VMCPU actions. */
-#define VMCPU_FF_NORMAL_PRIORITY_MASK ( VMCPU_FF_REQUEST | VMCPU_FF_UNHALT )
+#define VMCPU_FF_NORMAL_PRIORITY_MASK ( VMCPU_FF_REQUEST )
/** Flags to clear before resuming guest execution. */
#define VMCPU_FF_RESUME_GUEST_MASK ( VMCPU_FF_TO_R3 )
diff --git a/include/iprt/asm.h b/include/iprt/asm.h
index 9bca79b..c3d9a25 100644
--- a/include/iprt/asm.h
+++ b/include/iprt/asm.h
@@ -3872,7 +3872,7 @@ DECLINLINE(void) ASMMemFill32(volatile void *pv, size_t cb, uint32_t u32)
*
* @todo Fix name, it is a predicate function but it's not returning boolean!
*/
-#if !defined(RT_OS_LINUX) || !defined(__KERNEL__)
+#if !defined(RDESKTOP) && (!defined(RT_OS_LINUX) || !defined(__KERNEL__))
DECLASM(void *) ASMMemFirstNonZero(void const *pv, size_t cb);
#else
DECLINLINE(void *) ASMMemFirstNonZero(void const *pv, size_t cb)
diff --git a/include/iprt/circbuf.h b/include/iprt/circbuf.h
index c7dce2e..0a5db1f 100644
--- a/include/iprt/circbuf.h
+++ b/include/iprt/circbuf.h
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 2010-2016 Oracle Corporation
+ * Copyright (C) 2010-2017 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -95,6 +95,20 @@ RTDECL(bool) RTCircBufIsReading(PRTCIRCBUF pBuf);
RTDECL(bool) RTCircBufIsWriting(PRTCIRCBUF pBuf);
/**
+ * Returns the current read offset (in bytes) within the buffer.
+ *
+ * @param pBuf The buffer to query.
+ */
+RTDECL(size_t) RTCircBufOffsetRead(PRTCIRCBUF pBuf);
+
+/**
+ * Returns the current write offset (in bytes) within the buffer.
+ *
+ * @param pBuf The buffer to query.
+ */
+RTDECL(size_t) RTCircBufOffsetWrite(PRTCIRCBUF pBuf);
+
+/**
* Acquire a block of the circular buffer for reading.
*
* @param pBuf The buffer to acquire from.
diff --git a/include/iprt/cpp/ministring.h b/include/iprt/cpp/ministring.h
index b48b57e..d4682e1 100644
--- a/include/iprt/cpp/ministring.h
+++ b/include/iprt/cpp/ministring.h
@@ -623,7 +623,8 @@ public:
bool equals(const RTCString &rThat) const
{
return rThat.length() == length()
- && memcmp(rThat.m_psz, m_psz, length()) == 0;
+ && ( length() == 0
+ || memcmp(rThat.m_psz, m_psz, length()) == 0);
}
/**
diff --git a/include/iprt/mangling.h b/include/iprt/mangling.h
index 465100a..95c9c96 100644
--- a/include/iprt/mangling.h
+++ b/include/iprt/mangling.h
@@ -10,7 +10,7 @@
*/
/*
- * Copyright (C) 2011-2016 Oracle Corporation
+ * Copyright (C) 2011-2017 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -594,6 +594,8 @@
# define RTCircBufFree RT_MANGLER(RTCircBufFree)
# define RTCircBufIsReading RT_MANGLER(RTCircBufIsReading)
# define RTCircBufIsWriting RT_MANGLER(RTCircBufIsWriting)
+# define RTCircBufOffsetRead RT_MANGLER(RTCircBufOffsetRead)
+# define RTCircBufOffsetWrite RT_MANGLER(RTCircBufOffsetWrite)
# define RTCircBufReleaseReadBlock RT_MANGLER(RTCircBufReleaseReadBlock)
# define RTCircBufReleaseWriteBlock RT_MANGLER(RTCircBufReleaseWriteBlock)
# define RTCircBufReset RT_MANGLER(RTCircBufReset)
@@ -1359,6 +1361,8 @@
# define RTNetIPv6PseudoChecksum RT_MANGLER(RTNetIPv6PseudoChecksum)
# define RTNetIPv6PseudoChecksumBits RT_MANGLER(RTNetIPv6PseudoChecksumBits)
# define RTNetIPv6PseudoChecksumEx RT_MANGLER(RTNetIPv6PseudoChecksumEx)
+# define RTNetMaskToPrefixIPv4 RT_MANGLER(RTNetMaskToPrefixIPv4)
+# define RTNetPrefixToMaskIPv4 RT_MANGLER(RTNetPrefixToMaskIPv4)
# define RTNetTCPChecksum RT_MANGLER(RTNetTCPChecksum)
# define RTNetUDPChecksum RT_MANGLER(RTNetUDPChecksum)
# define RTNetStrToMacAddr RT_MANGLER(RTNetStrToMacAddr)
diff --git a/include/iprt/net.h b/include/iprt/net.h
index 5d27bdf..4b54a63 100644
--- a/include/iprt/net.h
+++ b/include/iprt/net.h
@@ -103,6 +103,30 @@ RTDECL(int) RTNetStrToIPv4AddrEx(const char *pcszAddr, PRTNETADDRIPV4 pAddr, cha
RTDECL(int) RTNetStrToIPv4Addr(const char *pcszAddr, PRTNETADDRIPV4 pAddr);
/**
+ * Verifies that RTNETADDRIPV4 is a valid contiguous netmask and
+ * computes its prefix length.
+ *
+ * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
+ * failure.
+ *
+ * @param pMask The netmask to verify and convert.
+ * @param piPrefix Where to store the prefix length. (Optional)
+ */
+RTDECL(int) RTNetMaskToPrefixIPv4(PCRTNETADDRIPV4 pMask, int *piPrefix);
+
+/**
+ * Computes netmask corresponding to the prefix length.
+ *
+ * @returns VINF_SUCCESS on success, VERR_INVALID_PARAMETER on
+ * failure.
+ *
+ * @param iPrefix The prefix to convert.
+ * @param pMask Where to store the netmask.
+ */
+RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask);
+
+
+/**
* IPv6 address.
*/
typedef RTUINT128U RTNETADDRIPV6;
diff --git a/include/iprt/x86.h b/include/iprt/x86.h
index cd9415c..785717e 100644
--- a/include/iprt/x86.h
+++ b/include/iprt/x86.h
@@ -3250,9 +3250,9 @@ typedef struct X86DESCGATE
unsigned u16Sel : 16;
/** 20 - Number of parameters for a call-gate.
* Ignored if interrupt-, trap- or task-gate. */
- unsigned u4ParmCount : 4;
- /** 24 - Reserved / ignored. */
- unsigned u4Reserved : 4;
+ unsigned u5ParmCount : 5;
+ /** 25 - Reserved / ignored. */
+ unsigned u3Reserved : 3;
/** 28 - Segment Type. */
unsigned u4Type : 4;
/** 2c - Descriptor Type (0 = system). */
diff --git a/src/VBox/Additions/linux/drm/vbox_drv.h b/src/VBox/Additions/linux/drm/vbox_drv.h
index f47e11a..ce52b44 100644
--- a/src/VBox/Additions/linux/drm/vbox_drv.h
+++ b/src/VBox/Additions/linux/drm/vbox_drv.h
@@ -67,6 +67,9 @@
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
# include <drm/drm_gem.h>
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+# include <drm/drm_encoder.h>
+#endif
/* #include "vboxvideo.h" */
@@ -143,7 +146,11 @@ struct vbox_private {
#undef CURSOR_DATA_SIZE
int vbox_driver_load(struct drm_device *dev, unsigned long flags);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+void vbox_driver_unload(struct drm_device *dev);
+#else
int vbox_driver_unload(struct drm_device *dev);
+#endif
void vbox_driver_lastclose(struct drm_device *dev);
struct vbox_gem_object;
diff --git a/src/VBox/Additions/linux/drm/vbox_fb.c b/src/VBox/Additions/linux/drm/vbox_fb.c
index 78da136..560db23 100644
--- a/src/VBox/Additions/linux/drm/vbox_fb.c
+++ b/src/VBox/Additions/linux/drm/vbox_fb.c
@@ -80,7 +80,11 @@ static void vbox_dirty_update(struct vbox_fbdev *fbdev,
struct drm_gem_object *obj;
struct vbox_bo *bo;
int src_offset, dst_offset;
- int bpp = (fbdev->afb.base.bits_per_pixel + 7)/8;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ int bpp = fbdev->afb.base.format->cpp[0];
+#else
+ int bpp = (fbdev->afb.base.bits_per_pixel + 7) / 8;
+#endif
int ret = -EBUSY;
bool unmap = false;
bool store_for_later = false;
@@ -350,7 +354,11 @@ static int vboxfb_create(struct drm_fb_helper *helper,
info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0);
info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->format->depth);
+#else
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+#endif
drm_fb_helper_fill_var(info, &fbdev->helper, sizes->fb_width, sizes->fb_height);
info->screen_base = sysram;
@@ -440,7 +448,11 @@ int vbox_fbdev_init(struct drm_device *dev)
#else
drm_fb_helper_prepare(dev, &fbdev->helper, &vbox_fb_helper_funcs);
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ ret = drm_fb_helper_init(dev, &fbdev->helper, vbox->num_crtcs);
+#else
ret = drm_fb_helper_init(dev, &fbdev->helper, vbox->num_crtcs, vbox->num_crtcs);
+#endif
if (ret)
goto free;
diff --git a/src/VBox/Additions/linux/drm/vbox_main.c b/src/VBox/Additions/linux/drm/vbox_main.c
index b85e091..24bbedc 100644
--- a/src/VBox/Additions/linux/drm/vbox_main.c
+++ b/src/VBox/Additions/linux/drm/vbox_main.c
@@ -178,7 +178,11 @@ int vbox_framebuffer_init(struct drm_device *dev,
LogFunc(("vboxvideo: %d: dev=%p, vbox_fb=%p, obj=%p\n", __LINE__, dev,
vbox_fb, obj));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ drm_helper_mode_fill_fb_struct(dev, &vbox_fb->base, mode_cmd);
+#else
drm_helper_mode_fill_fb_struct(&vbox_fb->base, mode_cmd);
+#endif
vbox_fb->obj = obj;
ret = drm_framebuffer_init(dev, &vbox_fb->base, &vbox_fb_funcs);
if (ret) {
@@ -408,7 +412,11 @@ out_free:
return ret;
}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+void vbox_driver_unload(struct drm_device *dev)
+#else
int vbox_driver_unload(struct drm_device *dev)
+#endif
{
struct vbox_private *vbox = dev->dev_private;
@@ -426,7 +434,9 @@ int vbox_driver_unload(struct drm_device *dev)
kfree(vbox);
dev->dev_private = NULL;
LogFunc(("vboxvideo: %d\n", __LINE__));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
return 0;
+#endif
}
/** @note this is described in the DRM framework documentation. AST does not
diff --git a/src/VBox/Additions/linux/drm/vbox_mode.c b/src/VBox/Additions/linux/drm/vbox_mode.c
index ad8a717..62336ea 100644
--- a/src/VBox/Additions/linux/drm/vbox_mode.c
+++ b/src/VBox/Additions/linux/drm/vbox_mode.c
@@ -80,11 +80,15 @@ static void vbox_do_modeset(struct drm_crtc *crtc,
width = mode->hdisplay ? mode->hdisplay : 640;
height = mode->vdisplay ? mode->vdisplay : 480;
crtc_id = vbox_crtc->crtc_id;
- bpp = crtc->enabled ? CRTC_FB(crtc)->bits_per_pixel : 32;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
- pitch = crtc->enabled ? CRTC_FB(crtc)->pitch : width * bpp / 8;
-#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ bpp = crtc->enabled ? CRTC_FB(crtc)->format->cpp[0] * 8 : 32;
pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
+ bpp = crtc->enabled ? CRTC_FB(crtc)->bits_per_pixel : 32;
+ pitch = crtc->enabled ? CRTC_FB(crtc)->pitches[0] : width * bpp / 8;
+#else
+ bpp = crtc->enabled ? CRTC_FB(crtc)->bits_per_pixel : 32;
+ pitch = crtc->enabled ? CRTC_FB(crtc)->pitch : width * bpp / 8;
#endif
/* This is the old way of setting graphics modes. It assumed one screen
* and a frame-buffer at the start of video RAM. On older versions of
@@ -95,7 +99,12 @@ static void vbox_do_modeset(struct drm_crtc *crtc,
&& vbox_crtc->fb_offset / pitch < 0xffff - crtc->y
&& vbox_crtc->fb_offset % (bpp / 8) == 0)
VBoxVideoSetModeRegisters(width, height, pitch * 8 / bpp,
- CRTC_FB(crtc)->bits_per_pixel, 0,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ CRTC_FB(crtc)->format->cpp[0] * 8,
+#else
+ CRTC_FB(crtc)->bits_per_pixel,
+#endif
+ 0,
vbox_crtc->fb_offset % pitch / bpp * 8 + crtc->x,
vbox_crtc->fb_offset / pitch + crtc->y);
flags = VBVA_SCREEN_F_ACTIVE;
diff --git a/src/VBox/Additions/linux/drm/vbox_ttm.c b/src/VBox/Additions/linux/drm/vbox_ttm.c
index 0e23acd..57dd087 100644
--- a/src/VBox/Additions/linux/drm/vbox_ttm.c
+++ b/src/VBox/Additions/linux/drm/vbox_ttm.c
@@ -280,7 +280,7 @@ struct ttm_bo_driver vbox_bo_driver = {
.verify_access = vbox_bo_verify_access,
.io_mem_reserve = &vbox_ttm_io_mem_reserve,
.io_mem_free = &vbox_ttm_io_mem_free,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
.lru_tail = &ttm_bo_default_lru_tail,
.swap_lru_tail = &ttm_bo_default_swap_lru_tail,
#endif
diff --git a/src/VBox/Additions/linux/installer/vboxadd.sh b/src/VBox/Additions/linux/installer/vboxadd.sh
index 9bbd0b4..60e0068 100755
--- a/src/VBox/Additions/linux/installer/vboxadd.sh
+++ b/src/VBox/Additions/linux/installer/vboxadd.sh
@@ -1,6 +1,6 @@
#! /bin/sh
#
-# Linux Additions kernel module init script ($Revision: 111985 $)
+# Linux Additions kernel module init script ($Revision: 113648 $)
#
#
@@ -328,6 +328,7 @@ setup_modules()
show_error "Look at $LOG to find out what went wrong"
fi
succ_msg
+ [ -d /etc/depmod.d ] || mkdir /etc/depmod.d
echo "override vboxguest * misc" > /etc/depmod.d/vboxvideo-upstream.conf
echo "override vboxsf * misc" >> /etc/depmod.d/vboxvideo-upstream.conf
echo "override vboxvideo * misc" >> /etc/depmod.d/vboxvideo-upstream.conf
diff --git a/src/VBox/Additions/linux/sharedfolders/lnkops.c b/src/VBox/Additions/linux/sharedfolders/lnkops.c
index 66ddecd..e43b84c 100644
--- a/src/VBox/Additions/linux/sharedfolders/lnkops.c
+++ b/src/VBox/Additions/linux/sharedfolders/lnkops.c
@@ -90,7 +90,9 @@ static const char *sf_get_link(struct dentry *dentry, struct inode *inode,
struct inode_operations sf_lnk_iops =
{
+# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
.readlink = generic_readlink,
+# endif
# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
.get_link = sf_get_link
# elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
diff --git a/src/VBox/Additions/linux/sharedfolders/regops.c b/src/VBox/Additions/linux/sharedfolders/regops.c
index 44b1f0f..3812462 100644
--- a/src/VBox/Additions/linux/sharedfolders/regops.c
+++ b/src/VBox/Additions/linux/sharedfolders/regops.c
@@ -444,7 +444,9 @@ static int sf_reg_release(struct inode *inode, struct file *file)
return 0;
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+static int sf_reg_fault(struct vm_fault *vmf)
+#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
static int sf_reg_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
static struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vaddr, int *type)
@@ -459,6 +461,9 @@ static struct page *sf_reg_nopage(struct vm_area_struct *vma, unsigned long vadd
loff_t off;
uint32_t nread = PAGE_SIZE;
int err;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ struct vm_area_struct *vma = vmf->vma;
+#endif
struct file *file = vma->vm_file;
struct inode *inode = GET_F_DENTRY(file)->d_inode;
struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
@@ -539,7 +544,7 @@ static struct vm_operations_struct sf_vma_ops =
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 25)
.fault = sf_reg_fault
#else
- .nopage = sf_reg_nopage
+ .nopage = sf_reg_nopage
#endif
};
diff --git a/src/VBox/Additions/linux/sharedfolders/utils.c b/src/VBox/Additions/linux/sharedfolders/utils.c
index b867c83..22ff530 100644
--- a/src/VBox/Additions/linux/sharedfolders/utils.c
+++ b/src/VBox/Additions/linux/sharedfolders/utils.c
@@ -290,9 +290,16 @@ sf_dentry_revalidate(struct dentry *dentry, int flags)
has inode at all) from these new attributes we derive [kstat] via
[generic_fillattr] */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+int sf_getattr(const struct path *path, struct kstat *kstat, u32 request_mask, unsigned int flags)
+# else
int sf_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *kstat)
+# endif
{
int err;
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+ struct dentry *dentry = path->dentry;
+# endif
TRACE();
err = sf_inode_revalidate(dentry);
diff --git a/src/VBox/Additions/linux/sharedfolders/vfsmod.c b/src/VBox/Additions/linux/sharedfolders/vfsmod.c
index 62d0b35..9bf9627 100644
--- a/src/VBox/Additions/linux/sharedfolders/vfsmod.c
+++ b/src/VBox/Additions/linux/sharedfolders/vfsmod.c
@@ -36,6 +36,9 @@
MODULE_DESCRIPTION(VBOX_PRODUCT " VFS Module for Host File System Access");
MODULE_AUTHOR(VBOX_VENDOR);
MODULE_LICENSE("GPL");
+#ifdef MODULE_ALIAS_FS
+MODULE_ALIAS_FS("vboxsf");
+#endif
#ifdef MODULE_VERSION
MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV));
#endif
diff --git a/src/VBox/Additions/linux/sharedfolders/vfsmod.h b/src/VBox/Additions/linux/sharedfolders/vfsmod.h
index 9dd28b6..2f12206 100644
--- a/src/VBox/Additions/linux/sharedfolders/vfsmod.h
+++ b/src/VBox/Additions/linux/sharedfolders/vfsmod.h
@@ -100,8 +100,13 @@ extern int sf_stat(const char *caller, struct sf_glob_info *sf_g,
SHFLSTRING *path, PSHFLFSOBJINFO result, int ok_to_fail);
extern int sf_inode_revalidate(struct dentry *dentry);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+extern int sf_getattr(const struct path *path, struct kstat *kstat,
+ u32 request_mask, unsigned int query_flags);
+# else
extern int sf_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *kstat);
+#endif
extern int sf_setattr(struct dentry *dentry, struct iattr *iattr);
#endif
extern int sf_path_from_dentry(const char *caller, struct sf_glob_info *sf_g,
diff --git a/src/VBox/Debugger/VBoxDbgConsole.cpp b/src/VBox/Debugger/VBoxDbgConsole.cpp
index b3df51a..7ca5b75 100644
--- a/src/VBox/Debugger/VBoxDbgConsole.cpp
+++ b/src/VBox/Debugger/VBoxDbgConsole.cpp
@@ -43,6 +43,7 @@
#include <iprt/alloc.h>
#include <iprt/string.h>
+#include <VBox/com/string.h>
@@ -56,8 +57,9 @@
*/
-VBoxDbgConsoleOutput::VBoxDbgConsoleOutput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
- : QTextEdit(pParent), m_uCurLine(0), m_uCurPos(0), m_hGUIThread(RTThreadNativeSelf())
+VBoxDbgConsoleOutput::VBoxDbgConsoleOutput(QWidget *pParent/* = NULL*/, IVirtualBox *a_pVirtualBox /* = NULL */,
+ const char *pszName/* = NULL*/)
+ : QTextEdit(pParent), m_uCurLine(0), m_uCurPos(0), m_hGUIThread(RTThreadNativeSelf()), m_pVirtualBox(a_pVirtualBox)
{
setReadOnly(true);
setUndoRedoEnabled(false);
@@ -111,8 +113,24 @@ VBoxDbgConsoleOutput::VBoxDbgConsoleOutput(QWidget *pParent/* = NULL*/, const ch
/*
* Set the defaults (which syncs with the menu item checked state).
*/
- setFontCourier();
- setColorGreenOnBlack();
+
+ if (m_pVirtualBox)
+ {
+ com::Bstr strColor;
+ HRESULT hrc = m_pVirtualBox->GetExtraData(com::Bstr("DbgConsole/ColorScheme").raw(), strColor.asOutParam());
+ if ( SUCCEEDED(hrc)
+ && strColor.compareUtf8("blackonwhite", com::Bstr::CaseInsensitive) == 0)
+ setColorBlackOnWhite();
+ else
+ setColorGreenOnBlack();
+ com::Bstr strFont;
+ hrc = m_pVirtualBox->GetExtraData(com::Bstr("DbgConsole/Font").raw(), strFont.asOutParam());
+ if ( SUCCEEDED(hrc)
+ && strFont.compareUtf8("monospace", com::Bstr::CaseInsensitive) == 0)
+ setFontMonospace();
+ else
+ setFontCourier();
+ }
NOREF(pszName);
}
@@ -121,6 +139,11 @@ VBoxDbgConsoleOutput::VBoxDbgConsoleOutput(QWidget *pParent/* = NULL*/, const ch
VBoxDbgConsoleOutput::~VBoxDbgConsoleOutput()
{
Assert(m_hGUIThread == RTThreadNativeSelf());
+ if (m_pVirtualBox)
+ {
+ m_pVirtualBox->Release();
+ m_pVirtualBox = NULL;
+ }
}
@@ -154,6 +177,10 @@ VBoxDbgConsoleOutput::setColorGreenOnBlack()
When used as a trigger, the checked is done automatically by Qt. */
if (!m_pGreenOnBlackAction->isChecked())
m_pGreenOnBlackAction->setChecked(true);
+
+ /* Make this setting persistent */
+ if (m_pVirtualBox)
+ m_pVirtualBox->SetExtraData(com::Bstr("DbgConsole/ColorScheme").raw(), com::Bstr("GreenOnBlack").raw());
}
@@ -165,6 +192,10 @@ VBoxDbgConsoleOutput::setColorBlackOnWhite()
if (!m_pBlackOnWhiteAction->isChecked())
m_pBlackOnWhiteAction->setChecked(true);
+
+ /* Make this setting persistent */
+ if (m_pVirtualBox)
+ m_pVirtualBox->SetExtraData(com::Bstr("DbgConsole/ColorScheme").raw(), com::Bstr("BlackOnWhite").raw());
}
@@ -183,6 +214,10 @@ VBoxDbgConsoleOutput::setFontCourier()
if (!m_pCourierFontAction->isChecked())
m_pCourierFontAction->setChecked(true);
+
+ /* Make this setting persistent */
+ if (m_pVirtualBox)
+ m_pVirtualBox->SetExtraData(com::Bstr("DbgConsole/Font").raw(), com::Bstr("Courier").raw());
}
@@ -197,6 +232,10 @@ VBoxDbgConsoleOutput::setFontMonospace()
if (!m_pMonospaceFontAction->isChecked())
m_pMonospaceFontAction->setChecked(true);
+
+ /* Make this setting persistent */
+ if (m_pVirtualBox)
+ m_pVirtualBox->SetExtraData(com::Bstr("DbgConsole/Font").raw(), com::Bstr("Monospace").raw());
}
@@ -352,7 +391,7 @@ VBoxDbgConsoleInput::returnPressed()
*/
-VBoxDbgConsole::VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent/* = NULL*/)
+VBoxDbgConsole::VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent/* = NULL*/, IVirtualBox *a_pVirtualBox/* = NULL */)
: VBoxDbgBaseWindow(a_pDbgGui, a_pParent), m_pOutput(NULL), m_pInput(NULL), m_fInputRestoreFocus(false),
m_pszInputBuf(NULL), m_cbInputBuf(0), m_cbInputBufAlloc(0),
m_pszOutputBuf(NULL), m_cbOutputBuf(0), m_cbOutputBufAlloc(0),
@@ -364,7 +403,7 @@ VBoxDbgConsole::VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent/* = NUL
/*
* Create the output text box.
*/
- m_pOutput = new VBoxDbgConsoleOutput(this);
+ m_pOutput = new VBoxDbgConsoleOutput(this, a_pVirtualBox);
/* try figure a suitable size */
QLabel *pLabel = new QLabel( "11111111111111111111111111111111111111111111111111111111111111111111111111111112222222222", this);
diff --git a/src/VBox/Debugger/VBoxDbgConsole.h b/src/VBox/Debugger/VBoxDbgConsole.h
index 5820adb..0e2bba6 100644
--- a/src/VBox/Debugger/VBoxDbgConsole.h
+++ b/src/VBox/Debugger/VBoxDbgConsole.h
@@ -29,6 +29,13 @@
#include <iprt/semaphore.h>
#include <iprt/thread.h>
+// VirtualBox COM interfaces declarations (generated header)
+#ifdef VBOX_WITH_XPCOM
+# include <VirtualBox_XPCOM.h>
+#else
+# include <VirtualBox.h>
+#endif
+
class VBoxDbgConsoleOutput : public QTextEdit
{
@@ -39,9 +46,10 @@ public:
* Constructor.
*
* @param pParent Parent Widget.
+ * @param pVirtualBox VirtualBox object for storing extra data.
* @param pszName Widget name.
*/
- VBoxDbgConsoleOutput(QWidget *pParent = NULL, const char *pszName = NULL);
+ VBoxDbgConsoleOutput(QWidget *pParent = NULL, IVirtualBox *pVirtualBox = NULL, const char *pszName = NULL);
/**
* Destructor
@@ -89,6 +97,8 @@ protected:
RTNATIVETHREAD m_hGUIThread;
/** The current color scheme (foreground on background). */
VBoxDbgConsoleColor m_enmColorScheme;
+ /** The IVirtualBox object */
+ IVirtualBox *m_pVirtualBox;
private slots:
/**
@@ -178,8 +188,9 @@ public:
*
* @param a_pDbgGui Pointer to the debugger gui object.
* @param a_pParent Parent Widget.
+ * @param a_pVirtualBox VirtualBox object for storing extra data.
*/
- VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent = NULL);
+ VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent = NULL, IVirtualBox *a_pVirtualBox = NULL);
/**
* Destructor
diff --git a/src/VBox/Debugger/VBoxDbgGui.cpp b/src/VBox/Debugger/VBoxDbgGui.cpp
index 0781963..e4361af 100644
--- a/src/VBox/Debugger/VBoxDbgGui.cpp
+++ b/src/VBox/Debugger/VBoxDbgGui.cpp
@@ -195,7 +195,9 @@ VBoxDbgGui::showConsole()
{
if (!m_pDbgConsole)
{
- m_pDbgConsole = new VBoxDbgConsole(this, m_pParent);
+ IVirtualBox *pVirtualBox = NULL;
+ m_pMachine->COMGETTER(Parent)(&pVirtualBox);
+ m_pDbgConsole = new VBoxDbgConsole(this, m_pParent, pVirtualBox);
connect(m_pDbgConsole, SIGNAL(destroyed(QObject *)), this, SLOT(notifyChildDestroyed(QObject *)));
repositionConsole();
}
diff --git a/src/VBox/Devices/Audio/AudioMixBuffer.cpp b/src/VBox/Devices/Audio/AudioMixBuffer.cpp
index acab3f4..0528dc2 100644
--- a/src/VBox/Devices/Audio/AudioMixBuffer.cpp
+++ b/src/VBox/Devices/Audio/AudioMixBuffer.cpp
@@ -18,31 +18,29 @@
#define LOG_GROUP LOG_GROUP_AUDIO_MIXER_BUFFER
#include <VBox/log.h>
-#if 0
/*
- * AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
- * to a file on the host. Be sure to adjust AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH
+ * DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
+ * to a file on the host. Be sure to adjust DEBUG_DUMP_PCM_DATA_PATH
* to your needs before using this!
*/
-# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
+#if 0
+# define DEBUG_DUMP_PCM_DATA
# ifdef RT_OS_WINDOWS
-# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
+# define DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
# else
-# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
+# define DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
# endif
-/* Warning: Enabling this will generate *huge* logs! */
-//# define AUDIOMIXBUF_DEBUG_MACROS
#endif
#include <iprt/asm-math.h>
#include <iprt/assert.h>
-#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
+#ifdef DEBUG_DUMP_PCM_DATA
# include <iprt/file.h>
#endif
#include <iprt/mem.h>
#include <iprt/string.h> /* For RT_BZERO. */
-#ifdef VBOX_AUDIO_TESTCASE
+#ifdef TESTCASE
# define LOG_ENABLED
# include <iprt/stream.h>
#endif
@@ -50,19 +48,16 @@
#include "AudioMixBuffer.h"
-#ifndef VBOX_AUDIO_TESTCASE
-# ifdef DEBUG
-# define AUDMIXBUF_LOG(x) LogFlowFunc(x)
+#if 0
+# define AUDMIXBUF_LOG(x) LogFlowFunc(x)
+#else
+# if defined(TESTCASE)
+# define AUDMIXBUF_LOG(x) LogFunc(x)
# else
-# define AUDMIXBUF_LOG(x) do {} while (0)
+# define AUDMIXBUF_LOG(x) do {} while (0)
# endif
-#else /* VBOX_AUDIO_TESTCASE */
-# define AUDMIXBUF_LOG(x) RTPrintf x
#endif
-#ifdef DEBUG
-DECLINLINE(void) audioMixBufDbgPrintInternal(PPDMAUDIOMIXBUF pMixBuf);
-#endif
/*
* Soft Volume Control
@@ -71,7 +66,7 @@ DECLINLINE(void) audioMixBufDbgPrintInternal(PPDMAUDIOMIXBUF pMixBuf);
* 0 .. 255 range. This represents 0 to -96dB attenuation where an input
* value of 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
*
- * Each step thus corresponds to 96 / 256 or 0.375dB. Every 6dB (16 steps)
+ * Each step thus correspons to 96 / 256 or 0.375dB. Every 6dB (16 steps)
* represents doubling the sample value.
*
* For internal use, the volume control needs to be converted to a 16-bit
@@ -133,10 +128,43 @@ static uint32_t s_aVolumeConv[256] = {
AssertCompile(AUDIOMIXBUF_VOL_0DB <= 0x40000000); /* Must always hold. */
AssertCompile(AUDIOMIXBUF_VOL_0DB == 0x40000000); /* For now -- when only attenuation is used. */
+/**
+ * Structure for holding sample conversion parameters for
+ * the audioMixBufConvFromXXX / audioMixBufConvToXXX macros.
+ */
+typedef struct AUDMIXBUF_CONVOPTS
+{
+ /** Number of audio samples to convert. */
+ uint32_t cSamples;
+ /** Volume to apply during conversion. Pass 0
+ * to convert the original values. May not apply to
+ * all conversion functions. */
+ PDMAUDIOVOLUME Volume;
+} AUDMIXBUF_CONVOPTS, *PAUDMIXBUF_CONVOPTS;
+
+/*
+ * When running the audio testcases we want to verfiy
+ * the macro-generated routines separately, so unmark them as being
+ * inlined + static.
+ */
+#ifdef TESTCASE
+# define AUDMIXBUF_MACRO_FN
+#else
+# define AUDMIXBUF_MACRO_FN static inline
+#endif
+
#ifdef DEBUG
static uint64_t s_cSamplesMixedTotal = 0;
+static inline void audioMixBufPrint(PPDMAUDIOMIXBUF pMixBuf);
#endif
+typedef uint32_t (AUDMIXBUF_FN_CONVFROM) (PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, const PAUDMIXBUF_CONVOPTS pOpts);
+typedef AUDMIXBUF_FN_CONVFROM *PAUDMIXBUF_FN_CONVFROM;
+
+typedef void (AUDMIXBUF_FN_CONVTO) (void *pvDst, const PPDMAUDIOSAMPLE paSrc, const PAUDMIXBUF_CONVOPTS pOpts);
+typedef AUDMIXBUF_FN_CONVTO *PAUDMIXBUF_FN_CONVTO;
+
+/* Can return VINF_TRY_AGAIN for getting next pointer at beginning (circular) */
/**
* Acquires (reads) a mutable pointer to the mixing buffer's audio samples without
@@ -144,7 +172,7 @@ static uint64_t s_cSamplesMixedTotal = 0;
** @todo Rename to AudioMixBufPeek(Mutable/Raw)?
** @todo Protect the buffer's data?
*
- * @return IPRT status code. VINF_TRY_AGAIN for getting next pointer at beginning (circular).
+ * @return IPRT status code.
* @param pMixBuf Mixing buffer to acquire audio samples from.
* @param cSamplesToRead Number of audio samples to read.
* @param ppvSamples Returns a mutable pointer to the buffer's audio sample data.
@@ -168,9 +196,9 @@ int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead,
}
uint32_t cSamplesRead;
- if (pMixBuf->offRead + cSamplesToRead > pMixBuf->cSamples)
+ if (pMixBuf->offReadWrite + cSamplesToRead > pMixBuf->cSamples)
{
- cSamplesRead = pMixBuf->cSamples - pMixBuf->offRead;
+ cSamplesRead = pMixBuf->cSamples - pMixBuf->offReadWrite;
rc = VINF_TRY_AGAIN;
}
else
@@ -179,12 +207,12 @@ int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead,
rc = VINF_SUCCESS;
}
- *ppvSamples = &pMixBuf->pSamples[pMixBuf->offRead];
+ *ppvSamples = &pMixBuf->pSamples[pMixBuf->offReadWrite];
AssertPtr(ppvSamples);
- pMixBuf->offRead = (pMixBuf->offRead + cSamplesRead) % pMixBuf->cSamples;
- Assert(pMixBuf->offRead <= pMixBuf->cSamples);
- pMixBuf->cUsed -= RT_MIN(cSamplesRead, pMixBuf->cUsed);
+ pMixBuf->offReadWrite = (pMixBuf->offReadWrite + cSamplesRead) % pMixBuf->cSamples;
+ Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
+ pMixBuf->cProcessed -= RT_MIN(cSamplesRead, pMixBuf->cProcessed);
*pcSamplesRead = cSamplesRead;
@@ -192,6 +220,26 @@ int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead,
}
/**
+ * Returns available number of samples for reading.
+ *
+ * @return uint32_t Number of samples available for reading.
+ * @param pMixBuf Mixing buffer to return value for.
+ */
+uint32_t AudioMixBufAvail(PPDMAUDIOMIXBUF pMixBuf)
+{
+ AssertPtrReturn(pMixBuf, true);
+
+ uint32_t cAvail;
+ if (pMixBuf->pParent) /* Child */
+ cAvail = pMixBuf->cMixed;
+ else
+ cAvail = pMixBuf->cProcessed;
+
+ Assert(cAvail <= pMixBuf->cSamples);
+ return cAvail;
+}
+
+/**
* Clears the entire sample buffer.
*
* @param pMixBuf Mixing buffer to clear.
@@ -206,7 +254,7 @@ void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf)
}
/**
- * Clears (zeroes) the buffer by a certain amount of (used) samples and
+ * Clears (zeroes) the buffer by a certain amount of (processed) samples and
* keeps track to eventually assigned children buffers.
*
* @param pMixBuf Mixing buffer to clear.
@@ -214,50 +262,43 @@ void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf)
*/
void AudioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear)
{
- AUDMIXBUF_LOG(("cSamplesToClear=%RU32\n", cSamplesToClear));
- AUDMIXBUF_LOG(("%s: offRead=%RU32, cUsed=%RU32\n",
- pMixBuf->pszName, pMixBuf->offRead, pMixBuf->cUsed));
+ AUDMIXBUF_LOG(("cSamples=%RU32\n", cSamplesToClear));
+ AUDMIXBUF_LOG(("%s: offReadWrite=%RU32, cProcessed=%RU32\n",
+ pMixBuf->pszName, pMixBuf->offReadWrite, pMixBuf->cProcessed));
PPDMAUDIOMIXBUF pIter;
- RTListForEach(&pMixBuf->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
+ RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
{
AUDMIXBUF_LOG(("\t%s: cMixed=%RU32 -> %RU32\n",
pIter->pszName, pIter->cMixed, pIter->cMixed - cSamplesToClear));
pIter->cMixed -= RT_MIN(pIter->cMixed, cSamplesToClear);
+ pIter->offReadWrite = 0;
}
- Assert(cSamplesToClear <= pMixBuf->cSamples);
-
- uint32_t cClearOff;
- uint32_t cClearLen;
+ uint32_t cLeft = RT_MIN(cSamplesToClear, pMixBuf->cSamples);
+ uint32_t offClear;
- /* Clear end of buffer (wrap around). */
- if (cSamplesToClear > pMixBuf->offRead)
+ if (cLeft > pMixBuf->offReadWrite) /* Zero end of buffer first (wrap-around). */
{
- cClearOff = pMixBuf->cSamples - (cSamplesToClear - pMixBuf->offRead);
- cClearLen = pMixBuf->cSamples - cClearOff;
-
- AUDMIXBUF_LOG(("Clearing1: %RU32 - %RU32\n", cClearOff, cClearOff + cClearLen));
+ AUDMIXBUF_LOG(("Clearing1: %RU32 - %RU32\n",
+ (pMixBuf->cSamples - (cLeft - pMixBuf->offReadWrite)),
+ pMixBuf->cSamples));
- RT_BZERO(pMixBuf->pSamples + cClearOff, cClearLen * sizeof(PDMAUDIOSAMPLE));
+ RT_BZERO(pMixBuf->pSamples + (pMixBuf->cSamples - (cLeft - pMixBuf->offReadWrite)),
+ (cLeft - pMixBuf->offReadWrite) * sizeof(PDMAUDIOSAMPLE));
- Assert(cSamplesToClear >= cClearLen);
- cSamplesToClear -= cClearLen;
+ cLeft -= cLeft - pMixBuf->offReadWrite;
+ offClear = 0;
}
+ else
+ offClear = pMixBuf->offReadWrite - cLeft;
- /* Clear beginning of buffer. */
- if ( cSamplesToClear
- && pMixBuf->offRead)
+ if (cLeft)
{
- Assert(pMixBuf->offRead >= cSamplesToClear);
-
- cClearOff = pMixBuf->offRead - cSamplesToClear;
- cClearLen = cSamplesToClear;
-
- AUDMIXBUF_LOG(("Clearing2: %RU32 - %RU32\n", cClearOff, cClearOff + cClearLen));
-
- RT_BZERO(pMixBuf->pSamples + cClearOff, cClearLen * sizeof(PDMAUDIOSAMPLE));
+ AUDMIXBUF_LOG(("Clearing2: %RU32 - %RU32\n",
+ offClear, offClear + cLeft));
+ RT_BZERO(pMixBuf->pSamples + offClear, cLeft * sizeof(PDMAUDIOSAMPLE));
}
}
@@ -308,26 +349,23 @@ uint32_t AudioMixBufFree(PPDMAUDIOMIXBUF pMixBuf)
{
AssertPtrReturn(pMixBuf, 0);
- uint32_t cSamples, cSamplesFree;
+ uint32_t cSamplesFree;
if (pMixBuf->pParent)
{
/*
* As a linked child buffer we want to know how many samples
* already have been consumed by the parent.
*/
- cSamples = pMixBuf->pParent->cSamples;
-
- Assert(pMixBuf->cMixed <= cSamples);
- cSamplesFree = cSamples - pMixBuf->cMixed;
+ Assert(pMixBuf->cMixed <= pMixBuf->pParent->cSamples);
+ cSamplesFree = pMixBuf->pParent->cSamples - pMixBuf->cMixed;
}
else /* As a parent. */
{
- cSamples = pMixBuf->cSamples;
- Assert(cSamples >= pMixBuf->cUsed);
- cSamplesFree = pMixBuf->cSamples - pMixBuf->cUsed;
+ Assert(pMixBuf->cSamples >= pMixBuf->cProcessed);
+ cSamplesFree = pMixBuf->cSamples - pMixBuf->cProcessed;
}
- AUDMIXBUF_LOG(("%s: %RU32 of %RU32\n", pMixBuf->pszName, cSamplesFree, cSamples));
+ AUDMIXBUF_LOG(("%s: cSamplesFree=%RU32\n", pMixBuf->pszName, cSamplesFree));
return cSamplesFree;
}
@@ -357,18 +395,24 @@ static int audioMixBufAlloc(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples)
AUDMIXBUF_LOG(("%s: cSamples=%RU32\n", pMixBuf->pszName, cSamples));
size_t cbSamples = cSamples * sizeof(PDMAUDIOSAMPLE);
+ if (!cbSamples)
+ return VERR_INVALID_PARAMETER;
+
pMixBuf->pSamples = (PPDMAUDIOSAMPLE)RTMemAllocZ(cbSamples);
- if (pMixBuf->pSamples)
- {
- pMixBuf->cSamples = cSamples;
- return VINF_SUCCESS;
- }
- return VERR_NO_MEMORY;
+ if (!pMixBuf->pSamples)
+ return VERR_NO_MEMORY;
+
+ pMixBuf->cSamples = cSamples;
+
+ return VINF_SUCCESS;
}
-#ifdef AUDIOMIXBUF_DEBUG_MACROS
+/** Note: Enabling this will generate huge logs! */
+//#define DEBUG_MACROS
+
+#ifdef DEBUG_MACROS
# define AUDMIXBUF_MACRO_LOG(x) AUDMIXBUF_LOG(x)
-#elif defined(VBOX_AUDIO_TESTCASE_VERBOSE) /* Warning: VBOX_AUDIO_TESTCASE_VERBOSE will generate huge logs! */
+#elif defined(TESTCASE)
# define AUDMIXBUF_MACRO_LOG(x) RTPrintf x
#else
# define AUDMIXBUF_MACRO_LOG(x) do {} while (0)
@@ -383,7 +427,7 @@ static int audioMixBufAlloc(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples)
*/
#define AUDMIXBUF_CONVERT(_aName, _aType, _aMin, _aMax, _aSigned, _aShift) \
/* Clips a specific output value to a single sample value. */ \
- DECLCALLBACK(int64_t) audioMixBufClipFrom##_aName(_aType aVal) \
+ AUDMIXBUF_MACRO_FN int64_t audioMixBufClipFrom##_aName(_aType aVal) \
{ \
if (_aSigned) \
return ((int64_t) aVal) << (32 - _aShift); \
@@ -391,11 +435,11 @@ static int audioMixBufAlloc(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples)
} \
\
/* Clips a single sample value to a specific output value. */ \
- DECLCALLBACK(_aType) audioMixBufClipTo##_aName(int64_t iVal) \
+ AUDMIXBUF_MACRO_FN _aType audioMixBufClipTo##_aName(int64_t iVal) \
{ \
if (iVal >= 0x7fffffff) \
return _aMax; \
- if (iVal < -INT64_C(0x80000000)) \
+ else if (iVal < -INT64_C(0x80000000)) \
return _aMin; \
\
if (_aSigned) \
@@ -403,44 +447,49 @@ static int audioMixBufAlloc(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples)
return ((_aType) ((iVal >> (32 - _aShift)) + ((_aMax >> 1) + 1))); \
} \
\
- DECLCALLBACK(uint32_t) audioMixBufConvFrom##_aName##Stereo(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, \
- PCPDMAUDMIXBUFCONVOPTS pOpts) \
+ AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFrom##_aName##Stereo(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, \
+ const PAUDMIXBUF_CONVOPTS pOpts) \
{ \
- _aType const *pSrc = (_aType const *)pvSrc; \
- uint32_t cSamples = RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
- AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
- pOpts->cSamples, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
+ _aType *pSrc = (_aType *)pvSrc; \
+ uint32_t cSamples = (uint32_t)RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
+ AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, sizeof(%zu), lVol=%RU32, rVol=%RU32\n", \
+ pOpts->cSamples, sizeof(_aType), pOpts->Volume.uLeft, pOpts->Volume.uRight)); \
for (uint32_t i = 0; i < cSamples; i++) \
{ \
- paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
- paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
+ AUDMIXBUF_MACRO_LOG(("%p: l=%RI16, r=%RI16\n", paDst, *pSrc, *(pSrc + 1))); \
+ paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
+ paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
+ AUDMIXBUF_MACRO_LOG(("\t-> l=%RI64, r=%RI64\n", paDst->i64LSample, paDst->i64RSample)); \
paDst++; \
} \
\
return cSamples; \
} \
\
- DECLCALLBACK(uint32_t) audioMixBufConvFrom##_aName##Mono(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, \
- PCPDMAUDMIXBUFCONVOPTS pOpts) \
+ AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFrom##_aName##Mono(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, \
+ const PAUDMIXBUF_CONVOPTS pOpts) \
{ \
- _aType const *pSrc = (_aType const *)pvSrc; \
- const uint32_t cSamples = RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
- AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
- cSamples, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
+ _aType *pSrc = (_aType *)pvSrc; \
+ uint32_t cSamples = (uint32_t)RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
+ AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, sizeof(%zu), lVol=%RU32, rVol=%RU32\n", \
+ cSamples, sizeof(_aType), pOpts->Volume.uLeft, pOpts->Volume.uRight)); \
for (uint32_t i = 0; i < cSamples; i++) \
{ \
- paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->From.Volume.uLeft) >> AUDIOMIXBUF_VOL_SHIFT; \
- paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
- pSrc++; \
+ AUDMIXBUF_MACRO_LOG(("%p: s=%RI16\n", paDst, *pSrc)); \
+ paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uLeft) >> AUDIOMIXBUF_VOL_SHIFT; \
+ paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
+ ++pSrc; \
+ AUDMIXBUF_MACRO_LOG(("\t-> l=%RI64, r=%RI64\n", paDst->i64LSample, paDst->i64RSample)); \
paDst++; \
} \
\
return cSamples; \
} \
\
- DECLCALLBACK(void) audioMixBufConvTo##_aName##Stereo(void *pvDst, PCPDMAUDIOSAMPLE paSrc, PCPDMAUDMIXBUFCONVOPTS pOpts) \
+ AUDMIXBUF_MACRO_FN void audioMixBufConvTo##_aName##Stereo(void *pvDst, const PPDMAUDIOSAMPLE paSrc, \
+ const PAUDMIXBUF_CONVOPTS pOpts) \
{ \
- PCPDMAUDIOSAMPLE pSrc = paSrc; \
+ PPDMAUDIOSAMPLE pSrc = paSrc; \
_aType *pDst = (_aType *)pvDst; \
_aType l, r; \
uint32_t cSamples = pOpts->cSamples; \
@@ -456,9 +505,10 @@ static int audioMixBufAlloc(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples)
} \
} \
\
- DECLCALLBACK(void) audioMixBufConvTo##_aName##Mono(void *pvDst, PCPDMAUDIOSAMPLE paSrc, PCPDMAUDMIXBUFCONVOPTS pOpts) \
+ AUDMIXBUF_MACRO_FN void audioMixBufConvTo##_aName##Mono(void *pvDst, const PPDMAUDIOSAMPLE paSrc, \
+ const PAUDMIXBUF_CONVOPTS pOpts) \
{ \
- PCPDMAUDIOSAMPLE pSrc = paSrc; \
+ PPDMAUDIOSAMPLE pSrc = paSrc; \
_aType *pDst = (_aType *)pvDst; \
uint32_t cSamples = pOpts->cSamples; \
while (cSamples--) \
@@ -484,15 +534,16 @@ AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* M
#undef AUDMIXBUF_CONVERT
#define AUDMIXBUF_MIXOP(_aName, _aOp) \
- static void audioMixBufOp##_aName(PPDMAUDIOSAMPLE paDst, uint32_t cDstSamples, \
- PPDMAUDIOSAMPLE paSrc, uint32_t cSrcSamples, \
- PPDMAUDIOSTRMRATE pRate, \
- uint32_t *pcDstWritten, uint32_t *pcSrcRead) \
+ AUDMIXBUF_MACRO_FN void audioMixBufOp##_aName(PPDMAUDIOSAMPLE paDst, uint32_t cDstSamples, \
+ PPDMAUDIOSAMPLE paSrc, uint32_t cSrcSamples, \
+ PPDMAUDIOSTRMRATE pRate, \
+ uint32_t *pcDstWritten, uint32_t *pcSrcRead) \
{ \
AUDMIXBUF_MACRO_LOG(("cSrcSamples=%RU32, cDstSamples=%RU32\n", cSrcSamples, cDstSamples)); \
- AUDMIXBUF_MACRO_LOG(("Rate: srcOffset=%RU32, dstOffset=%RU32, dstInc=%RU32\n", \
- pRate->srcOffset, \
- (uint32_t)(pRate->dstOffset >> 32), (uint32_t)(pRate->dstInc >> 32))); \
+ AUDMIXBUF_MACRO_LOG(("pRate=%p: srcOffset=0x%RX32 (%RU32), dstOffset=0x%RX32 (%RU32), dstInc=0x%RX64 (%RU64)\n", \
+ pRate, pRate->srcOffset, pRate->srcOffset, \
+ (uint32_t)(pRate->dstOffset >> 32), (uint32_t)(pRate->dstOffset >> 32), \
+ pRate->dstInc, pRate->dstInc)); \
\
if (pRate->dstInc == (UINT64_C(1) + UINT32_MAX)) /* No conversion needed? */ \
{ \
@@ -515,22 +566,28 @@ AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* M
PPDMAUDIOSAMPLE paSrcEnd = paSrc + cSrcSamples; \
PPDMAUDIOSAMPLE paDstStart = paDst; \
PPDMAUDIOSAMPLE paDstEnd = paDst + cDstSamples; \
- PDMAUDIOSAMPLE samCur = { 0 }; \
+ PDMAUDIOSAMPLE samCur = { 0 }; \
PDMAUDIOSAMPLE samOut; \
PDMAUDIOSAMPLE samLast = pRate->srcSampleLast; \
+ uint64_t lDelta = 0; \
+ \
+ AUDMIXBUF_MACRO_LOG(("Start: paDstEnd=%p - paDstStart=%p -> %zu\n", paDstEnd, paDst, paDstEnd - paDstStart)); \
+ AUDMIXBUF_MACRO_LOG(("Start: paSrcEnd=%p - paSrcStart=%p -> %zu\n", paSrcEnd, paSrc, paSrcEnd - paSrcStart)); \
\
while (paDst < paDstEnd) \
{ \
Assert(paSrc <= paSrcEnd); \
Assert(paDst <= paDstEnd); \
- if (paSrc >= paSrcEnd) \
+ if (paSrc == paSrcEnd) \
break; \
\
+ lDelta = 0; \
while (pRate->srcOffset <= (pRate->dstOffset >> 32)) \
{ \
Assert(paSrc <= paSrcEnd); \
samLast = *paSrc++; \
pRate->srcOffset++; \
+ lDelta++; \
if (paSrc == paSrcEnd) \
break; \
} \
@@ -550,24 +607,25 @@ AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* M
paDst->i64LSample _aOp samOut.i64LSample; \
paDst->i64RSample _aOp samOut.i64RSample; \
\
- AUDMIXBUF_MACRO_LOG(("\tiDstOffInt=%RI64, l=%RI64, r=%RI64 (cur l=%RI64, r=%RI64)\n", \
- iDstOffInt, \
- paDst->i64LSample >> 32, paDst->i64RSample >> 32, \
- samCur.i64LSample >> 32, samCur.i64RSample >> 32)); \
+ AUDMIXBUF_MACRO_LOG(("\tlDelta=0x%RX64 (%RU64), iDstOffInt=0x%RX64 (%RI64), l=%RI64, r=%RI64 (cur l=%RI64, r=%RI64)\n", \
+ lDelta, lDelta, iDstOffInt, iDstOffInt, \
+ paDst->i64LSample, paDst->i64RSample, \
+ samCur.i64LSample, samCur.i64RSample)); \
\
paDst++; \
pRate->dstOffset += pRate->dstInc; \
\
- AUDMIXBUF_MACRO_LOG(("\t\tpRate->dstOffset=%RU32\n", pRate->dstOffset >> 32)); \
+ AUDMIXBUF_MACRO_LOG(("\t\tpRate->dstOffset=0x%RX32 (%RU32)\n", pRate->dstOffset, pRate->dstOffset >> 32)); \
\
} \
\
- AUDMIXBUF_MACRO_LOG(("%zu source samples -> %zu dest samples\n", paSrc - paSrcStart, paDst - paDstStart)); \
+ AUDMIXBUF_MACRO_LOG(("End: paDst=%p - paDstStart=%p -> %zu\n", paDst, paDstStart, paDst - paDstStart)); \
+ AUDMIXBUF_MACRO_LOG(("End: paSrc=%p - paSrcStart=%p -> %zu\n", paSrc, paSrcStart, paSrc - paSrcStart)); \
\
pRate->srcSampleLast = samLast; \
\
- AUDMIXBUF_MACRO_LOG(("pRate->srcSampleLast l=%RI64, r=%RI64\n", \
- pRate->srcSampleLast.i64LSample, pRate->srcSampleLast.i64RSample)); \
+ AUDMIXBUF_MACRO_LOG(("pRate->srcSampleLast l=%RI64, r=%RI64, lDelta=0x%RX64 (%RU64)\n", \
+ pRate->srcSampleLast.i64LSample, pRate->srcSampleLast.i64RSample, lDelta, lDelta)); \
\
if (pcDstWritten) \
*pcDstWritten = paDst - paDstStart; \
@@ -575,24 +633,23 @@ AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* M
*pcSrcRead = paSrc - paSrcStart; \
}
+#if 0 // unused
/* audioMixBufOpAssign: Assigns values from source buffer to destination bufffer, overwriting the destination. */
AUDMIXBUF_MIXOP(Assign /* Name */, = /* Operation */)
-#if 0 /* unused */
+#endif
/* audioMixBufOpBlend: Blends together the values from both, the source and the destination buffer. */
AUDMIXBUF_MIXOP(Blend /* Name */, += /* Operation */)
-#endif
#undef AUDMIXBUF_MIXOP
#undef AUDMIXBUF_MACRO_LOG
/** Dummy conversion used when the source is muted. */
-static DECLCALLBACK(uint32_t)
-audioMixBufConvFromSilence(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, PCPDMAUDMIXBUFCONVOPTS pOpts)
+AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFromSilence(PPDMAUDIOSAMPLE paDst, const void *pvSrc,
+ uint32_t cbSrc, const PAUDMIXBUF_CONVOPTS pOpts)
{
RT_NOREF(cbSrc, pvSrc);
-
/* Internally zero always corresponds to silence. */
- RT_BZERO(paDst, pOpts->cSamples * sizeof(paDst[0]));
+ memset(paDst, 0, pOpts->cSamples * sizeof(paDst[0]));
return pOpts->cSamples;
}
@@ -604,9 +661,13 @@ audioMixBufConvFromSilence(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cb
*
* @return PAUDMIXBUF_FN_CONVFROM Function pointer to conversion macro if found, NULL if not supported.
* @param enmFmt Audio format to lookup conversion macro for.
+ * @param fMuted Flag determining whether the source is muted.
*/
-static PFNPDMAUDIOMIXBUFCONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enmFmt)
+static inline PAUDMIXBUF_FN_CONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enmFmt, bool fMuted)
{
+ if (fMuted)
+ return audioMixBufConvFromSilence;
+
if (AUDMIXBUF_FMT_SIGNED(enmFmt))
{
if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
@@ -619,7 +680,7 @@ static PFNPDMAUDIOMIXBUFCONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enm
default: return NULL;
}
}
- else
+ else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
{
switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
{
@@ -642,7 +703,7 @@ static PFNPDMAUDIOMIXBUFCONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enm
default: return NULL;
}
}
- else
+ else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
{
switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
{
@@ -653,7 +714,8 @@ static PFNPDMAUDIOMIXBUFCONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enm
}
}
}
- /* not reached */
+
+ return NULL;
}
/**
@@ -665,7 +727,7 @@ static PFNPDMAUDIOMIXBUFCONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enm
* @return PAUDMIXBUF_FN_CONVTO Function pointer to conversion macro if found, NULL if not supported.
* @param enmFmt Audio format to lookup conversion macro for.
*/
-static PFNPDMAUDIOMIXBUFCONVTO audioMixBufConvToLookup(PDMAUDIOMIXBUFFMT enmFmt)
+static inline PAUDMIXBUF_FN_CONVTO audioMixBufConvToLookup(PDMAUDIOMIXBUFFMT enmFmt)
{
if (AUDMIXBUF_FMT_SIGNED(enmFmt))
{
@@ -679,7 +741,7 @@ static PFNPDMAUDIOMIXBUFCONVTO audioMixBufConvToLookup(PDMAUDIOMIXBUFFMT enmFmt)
default: return NULL;
}
}
- else
+ else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
{
switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
{
@@ -702,7 +764,7 @@ static PFNPDMAUDIOMIXBUFCONVTO audioMixBufConvToLookup(PDMAUDIOMIXBUFFMT enmFmt)
default: return NULL;
}
}
- else
+ else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
{
switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
{
@@ -713,31 +775,8 @@ static PFNPDMAUDIOMIXBUFCONVTO audioMixBufConvToLookup(PDMAUDIOMIXBUFFMT enmFmt)
}
}
}
- /* not reached */
-}
-
-/**
- * Converts a PDM audio volume to an internal mixing buffer volume.
- *
- * @returns IPRT status code.
- * @param pVolDst Where to store the converted mixing buffer volume.
- * @param pVolSrc Volume to convert.
- */
-static int audioMixBufConvVol(PPDMAUDMIXBUFVOL pVolDst, PPDMAUDIOVOLUME pVolSrc)
-{
- if (!pVolSrc->fMuted) /* Only change/convert the volume value if we're not muted. */
- {
- uint8_t uVolL = pVolSrc->uLeft & 0xFF;
- uint8_t uVolR = pVolSrc->uRight & 0xFF;
-
- /** @todo Ensure that the input is in the correct range/initialized! */
- pVolDst->uLeft = s_aVolumeConv[uVolL] * (AUDIOMIXBUF_VOL_0DB >> 16);
- pVolDst->uRight = s_aVolumeConv[uVolR] * (AUDIOMIXBUF_VOL_0DB >> 16);
- }
- pVolDst->fMuted = pVolSrc->fMuted;
-
- return VINF_SUCCESS;
+ return NULL;
}
/**
@@ -749,22 +788,21 @@ static int audioMixBufConvVol(PPDMAUDMIXBUFVOL pVolDst, PPDMAUDIOVOLUME pVolSrc)
* @param pProps PCM audio properties to use for the mixing buffer.
* @param cSamples Maximum number of audio samples the mixing buffer can hold.
*/
-int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMAUDIOPCMPROPS pProps, uint32_t cSamples)
+int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMPCMPROPS pProps, uint32_t cSamples)
{
AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
AssertPtrReturn(pszName, VERR_INVALID_POINTER);
AssertPtrReturn(pProps, VERR_INVALID_POINTER);
pMixBuf->pParent = NULL;
- RTListInit(&pMixBuf->lstChildren);
+ RTListInit(&pMixBuf->lstBuffers);
pMixBuf->pSamples = NULL;
pMixBuf->cSamples = 0;
- pMixBuf->offRead = 0;
- pMixBuf->offWrite = 0;
- pMixBuf->cMixed = 0;
- pMixBuf->cUsed = 0;
+ pMixBuf->offReadWrite = 0;
+ pMixBuf->cMixed = 0;
+ pMixBuf->cProcessed = 0;
/* Set initial volume to max. */
pMixBuf->Volume.fMuted = false;
@@ -781,10 +819,6 @@ int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMAUDIOPCMPR
pProps->cChannels,
pProps->cBits,
pProps->fSigned);
-
- pMixBuf->pfnConvFrom = audioMixBufConvFromLookup(pMixBuf->AudioFmt);
- pMixBuf->pfnConvTo = audioMixBufConvToLookup(pMixBuf->AudioFmt);
-
pMixBuf->cShift = pProps->cShift;
pMixBuf->pszName = RTStrDup(pszName);
if (!pMixBuf->pszName)
@@ -813,7 +847,7 @@ bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf)
if (pMixBuf->pParent)
return (pMixBuf->cMixed == 0);
- return (pMixBuf->cUsed == 0);
+ return (pMixBuf->cProcessed == 0);
}
/**
@@ -828,7 +862,7 @@ bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf)
* device emulation owns the child/children.
*
* The audio format of each mixing buffer can vary; the internal mixing code
- * then will automatically do the (needed) conversion.
+ * then will autiomatically do the (needed) conversion.
*
* @return IPRT status code.
* @param pMixBuf Mixing buffer to link parent to.
@@ -850,12 +884,12 @@ int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent)
if (pMixBuf->pParent) /* Already linked? */
{
- AUDMIXBUF_LOG(("%s: Already linked to parent '%s'\n",
+ AUDMIXBUF_LOG(("%s: Already linked to \"%s\"\n",
pMixBuf->pszName, pMixBuf->pParent->pszName));
return VERR_ACCESS_DENIED;
}
- RTListAppend(&pParent->lstChildren, &pMixBuf->Node);
+ RTListAppend(&pParent->lstBuffers, &pMixBuf->Node);
pMixBuf->pParent = pParent;
/* Calculate the frequency ratio. */
@@ -865,8 +899,6 @@ int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent)
if (pMixBuf->iFreqRatio == 0) /* Catch division by zero. */
pMixBuf->iFreqRatio = 1 << 20; /* Do a 1:1 conversion instead. */
- int rc = VINF_SUCCESS;
-#if 0
uint32_t cSamples = (uint32_t)RT_MIN( ((uint64_t)pParent->cSamples << 32)
/ pMixBuf->iFreqRatio, _64K /* 64K samples max. */);
if (!cSamples)
@@ -894,7 +926,6 @@ int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent)
RT_BZERO(pMixBuf->pSamples, cbSamples);
}
}
-#endif
if (RT_SUCCESS(rc))
{
@@ -927,46 +958,22 @@ int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent)
}
/**
- * Returns number of available live samples, that is, samples that
- * have been written into the mixing buffer but not have been processed yet.
- *
- * For a parent buffer, this simply returns the currently used number of samples
- * in the buffer.
- *
- * For a child buffer, this returns the number of samples which have been mixed
- * to the parent and were not processed by the parent yet.
+ * Returns the number of audio samples mixed (processed) by
+ * the parent mixing buffer.
*
- * @return uint32_t Number of live samples available.
- * @param pMixBuf Mixing buffer to return value for.
+ * @return uint32_t Number of audio samples mixed (processed).
+ * @param pMixBuf Mixing buffer to return number from.
*/
-uint32_t AudioMixBufLive(PPDMAUDIOMIXBUF pMixBuf)
+uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf)
{
AssertPtrReturn(pMixBuf, 0);
-#ifdef RT_STRICT
- uint32_t cSamples;
-#endif
- uint32_t cAvail;
- if (pMixBuf->pParent) /* Is this a child buffer? */
- {
-#ifdef RT_STRICT
- /* Use the sample count from the parent, as
- * pMixBuf->cMixed specifies the sample count
- * in parent samples. */
- cSamples = pMixBuf->pParent->cSamples;
-#endif
- cAvail = pMixBuf->cMixed;
- }
- else
- {
-#ifdef RT_STRICT
- cSamples = pMixBuf->cSamples;
-#endif
- cAvail = pMixBuf->cUsed;
- }
+ AssertMsgReturn(VALID_PTR(pMixBuf->pParent),
+ ("Buffer is not linked to a parent buffer\n"),
+ 0);
- Assert(cAvail <= cSamples);
- return cAvail;
+ AUDMIXBUF_LOG(("%s: cMixed=%RU32\n", pMixBuf->pszName, pMixBuf->cMixed));
+ return pMixBuf->cMixed;
}
/**
@@ -975,148 +982,132 @@ uint32_t AudioMixBufLive(PPDMAUDIOMIXBUF pMixBuf)
* @return IPRT status code.
* @param pDst Destination mixing buffer.
* @param pSrc Source mixing buffer.
- * @param cSrcSamples Number of source audio samples to mix.
+ * @param cSamples Number of source audio samples to mix.
* @param pcProcessed Number of audio samples successfully mixed.
*/
-static int audioMixBufMixTo(PPDMAUDIOMIXBUF pDst, PPDMAUDIOMIXBUF pSrc, uint32_t cSrcSamples, uint32_t *pcProcessed)
+static int audioMixBufMixTo(PPDMAUDIOMIXBUF pDst, PPDMAUDIOMIXBUF pSrc, uint32_t cSamples, uint32_t *pcProcessed)
{
- AssertPtrReturn(pDst, VERR_INVALID_POINTER);
- AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
+ AssertPtrReturn(pDst, VERR_INVALID_POINTER);
+ AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
+ AssertReturn(cSamples, VERR_INVALID_PARAMETER);
/* pcProcessed is optional. */
- AssertMsgReturn(pDst == pSrc->pParent, ("Source buffer '%s' is not a child of destination '%s'\n",
- pSrc->pszName, pDst->pszName), VERR_INVALID_PARAMETER);
- uint32_t cReadTotal = 0;
- uint32_t cWrittenTotal = 0;
-
- if (pSrc->cMixed >= pDst->cSamples)
- {
- AUDMIXBUF_LOG(("Warning: Destination buffer '%s' full (%RU32 samples max), got %RU32 mixed samples\n",
- pDst->pszName, pDst->cSamples, pSrc->cMixed));
- if (pcProcessed)
- *pcProcessed = 0;
- return VINF_SUCCESS;
- }
+ /* Live samples indicate how many samples there are in the source buffer
+ * which have not been processed yet by the destination buffer. */
+ uint32_t cLive = pSrc->cMixed;
+ if (cLive >= pDst->cSamples)
+ AUDMIXBUF_LOG(("Destination buffer \"%s\" full (%RU32 samples max), live samples = %RU32\n",
+ pDst->pszName, pDst->cSamples, cLive));
- Assert(pSrc->cUsed >= pDst->cMixed);
+ /* Dead samples are the number of samples in the destination buffer which
+ * will not be needed, that is, are not needed in order to process the live
+ * samples of the source buffer. */
+ uint32_t cDead = pDst->cSamples - cLive;
- uint32_t cSrcAvail = RT_MIN(cSrcSamples, pSrc->cUsed - pDst->cMixed);
- uint32_t offSrcRead = pSrc->offRead;
- uint32_t cDstMixed = pSrc->cMixed;
+ uint32_t cToReadTotal = (uint32_t)RT_MIN(cSamples, AUDIOMIXBUF_S2S_RATIO(pSrc, cDead));
+ uint32_t offRead = 0;
- Assert(pDst->cUsed <= pDst->cSamples);
- uint32_t cDstAvail = pDst->cSamples - pDst->cUsed;
- uint32_t offDstWrite = pDst->offWrite;
+ uint32_t cReadTotal = 0;
+ uint32_t cWrittenTotal = 0;
+ uint32_t offWrite = (pDst->offReadWrite + cLive) % pDst->cSamples;
- if ( !cSrcAvail
- || !cDstAvail)
- {
- if (pcProcessed)
- *pcProcessed = 0;
- return VINF_SUCCESS;
- }
+ AUDMIXBUF_LOG(("pSrc=%s (%RU32 samples), pDst=%s (%RU32 samples), cLive=%RU32, cDead=%RU32, cToReadTotal=%RU32, offWrite=%RU32\n",
+ pSrc->pszName, pSrc->cSamples, pDst->pszName, pDst->cSamples, cLive, cDead, cToReadTotal, offWrite));
- AUDMIXBUF_LOG(("cSrcSamples=%RU32, cSrcAvail=%RU32 -> cDstAvail=%RU32\n", cSrcSamples, cSrcAvail, cDstAvail));
+ uint32_t cToRead, cToWrite;
+ uint32_t cWritten, cRead;
-#ifdef DEBUG
- audioMixBufDbgPrintInternal(pDst);
-#endif
+ while (cToReadTotal)
+ {
+ cDead = pDst->cSamples - cLive;
- uint32_t cSrcToRead = 0;
- uint32_t cSrcRead;
+ cToRead = cToReadTotal;
+ cToWrite = RT_MIN(cDead, pDst->cSamples - offWrite);
+ if (!cToWrite)
+ {
+ AUDMIXBUF_LOG(("Warning: Destination buffer \"%s\" full\n", pDst->pszName));
+ break;
+ }
- uint32_t cDstToWrite;
- uint32_t cDstWritten;
+ Assert(offWrite + cToWrite <= pDst->cSamples);
+ Assert(offRead + cToRead <= pSrc->cSamples);
- int rc = VINF_SUCCESS;
+ AUDMIXBUF_LOG(("\t%RU32Hz -> %RU32Hz\n", AUDMIXBUF_FMT_SAMPLE_FREQ(pSrc->AudioFmt), AUDMIXBUF_FMT_SAMPLE_FREQ(pDst->AudioFmt)));
+ AUDMIXBUF_LOG(("\tcDead=%RU32, offWrite=%RU32, cToWrite=%RU32, offRead=%RU32, cToRead=%RU32\n",
+ cDead, offWrite, cToWrite, offRead, cToRead));
- while ( cSrcAvail
- && cDstAvail)
- {
- cSrcToRead = RT_MIN(cSrcAvail, pSrc->cSamples - offSrcRead);
- cDstToWrite = RT_MIN(cDstAvail, pDst->cSamples - offDstWrite);
+ audioMixBufOpBlend(pDst->pSamples + offWrite, cToWrite,
+ pSrc->pSamples + offRead, cToRead,
+ pSrc->pRate, &cWritten, &cRead);
- AUDMIXBUF_LOG(("\tSource: %RU32 samples available, %RU32 @ %RU32 -> reading %RU32\n", cSrcAvail, offSrcRead, pSrc->cSamples, cSrcToRead));
- AUDMIXBUF_LOG(("\tDest : %RU32 samples available, %RU32 @ %RU32 -> writing %RU32\n", cDstAvail, offDstWrite, pDst->cSamples, cDstToWrite));
+ AUDMIXBUF_LOG(("\t\tcWritten=%RU32, cRead=%RU32\n", cWritten, cRead));
- cDstWritten = cSrcRead = 0;
+ cReadTotal += cRead;
+ cWrittenTotal += cWritten;
- if ( cDstToWrite
- && cSrcToRead)
- {
- Assert(offSrcRead < pSrc->cSamples);
- Assert(offSrcRead + cSrcToRead <= pSrc->cSamples);
+ offRead += cRead;
+ Assert(cToReadTotal >= cRead);
+ cToReadTotal -= cRead;
- Assert(offDstWrite < pDst->cSamples);
- Assert(offDstWrite + cDstToWrite <= pDst->cSamples);
+ offWrite = (offWrite + cWritten) % pDst->cSamples;
- audioMixBufOpAssign(pDst->pSamples + offDstWrite, cDstToWrite,
- pSrc->pSamples + offSrcRead, cSrcToRead,
- pSrc->pRate, &cDstWritten, &cSrcRead);
- }
+ cLive += cWritten;
+ }
- cReadTotal += cSrcRead;
- cWrittenTotal += cDstWritten;
+ pSrc->cMixed += cWrittenTotal;
+ pDst->cProcessed += cWrittenTotal;
+#ifdef DEBUG
+ s_cSamplesMixedTotal += cWrittenTotal;
+ audioMixBufPrint(pDst);
+#endif
- offSrcRead = (offSrcRead + cSrcRead) % pSrc->cSamples;
- offDstWrite = (offDstWrite + cDstWritten) % pDst->cSamples;
+ if (pcProcessed)
+ *pcProcessed = cReadTotal;
- cDstMixed += cDstWritten;
+ AUDMIXBUF_LOG(("cReadTotal=%RU32 (pcProcessed), cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstProc=%RU32\n",
+ cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cProcessed));
+ return VINF_SUCCESS;
+}
- Assert(cSrcAvail >= cSrcRead);
- cSrcAvail -= cSrcRead;
- Assert(cDstAvail >= cDstWritten);
- cDstAvail -= cDstWritten;
+/**
+ * Mixes (multiplexes) audio samples to all connected mixing buffer children.
+ *
+ * @return IPRT status code.
+ * @param pMixBuf Mixing buffer to use.
+ * @param cSamples Number of audio samples to mix to children.
+ * @param pcProcessed Maximum number of audio samples successfully mixed
+ * to all children. Optional.
+ */
+int AudioMixBufMixToChildren(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples,
+ uint32_t *pcProcessed)
+{
+ AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AUDMIXBUF_LOG(("\t%RU32 read (%RU32 left), %RU32 written (%RU32 left)\n", cSrcRead, cSrcAvail, cDstWritten, cDstAvail));
+ if (!cSamples)
+ {
+ if (pcProcessed)
+ *pcProcessed = 0;
+ return VINF_SUCCESS;
}
- pSrc->offRead = offSrcRead;
- Assert(pSrc->cUsed >= cReadTotal);
- pSrc->cUsed -= cReadTotal;
-
- /* Note: Always count in parent samples, as the rate can differ! */
- pSrc->cMixed = RT_MIN(cDstMixed, pDst->cSamples);
+ int rc = VINF_SUCCESS;
- pDst->offWrite = offDstWrite;
- Assert(pDst->offWrite <= pDst->cSamples);
- Assert((pDst->cUsed + cWrittenTotal) <= pDst->cSamples);
- pDst->cUsed += cWrittenTotal;
+ uint32_t cProcessed;
+ uint32_t cProcessedMax = 0;
- /* If there are more used samples than fitting in the destination buffer,
- * adjust the values accordingly.
- *
- * This can happen if this routine has been called too often without
- * actually processing the destination buffer in between. */
- if (pDst->cUsed > pDst->cSamples)
+ PPDMAUDIOMIXBUF pIter;
+ RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
{
- LogFlowFunc(("Warning: Destination buffer used %RU32 / %RU32 samples\n", pDst->cUsed, pDst->cSamples));
- pDst->offWrite = 0;
- pDst->cUsed = pDst->cSamples;
+ rc = audioMixBufMixTo(pIter, pMixBuf, cSamples, &cProcessed);
+ if (RT_FAILURE(rc))
+ break;
- rc = VERR_BUFFER_OVERFLOW;
+ cProcessedMax = RT_MAX(cProcessedMax, cProcessed);
}
- else if (!cSrcToRead && cDstAvail)
- {
- AUDMIXBUF_LOG(("Warning: Source buffer '%s' ran out of data\n", pSrc->pszName));
- rc = VERR_BUFFER_UNDERFLOW;
- }
- else if (cSrcAvail && !cDstAvail)
- {
- AUDMIXBUF_LOG(("Warning: Destination buffer '%s' full (%RU32 source samples left)\n", pDst->pszName, cSrcAvail));
- rc = VERR_BUFFER_OVERFLOW;
- }
-
-#ifdef DEBUG
- s_cSamplesMixedTotal += cWrittenTotal;
- audioMixBufDbgPrintInternal(pDst);
-#endif
if (pcProcessed)
- *pcProcessed = cReadTotal;
+ *pcProcessed = cProcessedMax;
- AUDMIXBUF_LOG(("cReadTotal=%RU32 (pcProcessed), cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstUsed=%RU32, rc=%Rrc\n",
- cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cUsed, rc));
return rc;
}
@@ -1125,8 +1116,7 @@ static int audioMixBufMixTo(PPDMAUDIOMIXBUF pDst, PPDMAUDIOMIXBUF pSrc, uint32_t
*
* @return IPRT status code.
* @param pMixBuf Mixing buffer to mix samples down to parent.
- * @param cSamples Number of audio samples of specified mixing buffer to to mix
- * to its attached parent mixing buffer (if any).
+ * @param cSamples Number of audio samples to mix down.
* @param pcProcessed Number of audio samples successfully processed. Optional.
*/
int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples,
@@ -1140,128 +1130,50 @@ int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples,
}
#ifdef DEBUG
-
-/**
- * Prints a single mixing buffer.
- * Internal helper function for debugging. Do not use directly.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to print.
- * @param fIsParent Whether this is a parent buffer or not.
- * @param uIdtLvl Indention level to use.
- */
-DECL_FORCE_INLINE(void) audioMixBufDbgPrintSingle(PPDMAUDIOMIXBUF pMixBuf, bool fIsParent, uint16_t uIdtLvl)
-{
- AUDMIXBUF_LOG(("%*s[%s] %s: offRead=%RU32, offWrite=%RU32, cMixed=%RU32 -> %RU32/%RU32\n",
- uIdtLvl * 4, "", fIsParent ? "PARENT" : "CHILD",
- pMixBuf->pszName, pMixBuf->offRead, pMixBuf->offWrite, pMixBuf->cMixed, pMixBuf->cUsed, pMixBuf->cSamples));
-}
-
-/**
- * Internal helper function for audioMixBufPrintChain().
- * Do not use directly.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to print.
- * @param uIdtLvl Indention level to use.
- * @param pcChildren Pointer to children counter.
- */
-DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainHelper(PPDMAUDIOMIXBUF pMixBuf, uint16_t uIdtLvl, size_t *pcChildren)
-{
- PPDMAUDIOMIXBUF pIter;
- RTListForEach(&pMixBuf->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
- {
- audioMixBufDbgPrintSingle(pIter, false /* ifIsParent */, uIdtLvl + 1);
- *pcChildren++;
- }
-}
-
-DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainInternal(PPDMAUDIOMIXBUF pMixBuf)
-{
- PPDMAUDIOMIXBUF pParent = pMixBuf->pParent;
- while (pParent)
- {
- if (!pParent->pParent)
- break;
-
- pParent = pParent->pParent;
- }
-
- if (!pParent)
- pParent = pMixBuf;
-
- AUDMIXBUF_LOG(("********************************************\n"));
-
- audioMixBufDbgPrintSingle(pParent, true /* fIsParent */, 0 /* uIdtLvl */);
-
- /* Recursively iterate children. */
- size_t cChildren = 0;
- audioMixBufDbgPrintChainHelper(pParent, 0 /* uIdtLvl */, &cChildren);
-
- AUDMIXBUF_LOG(("Children: %zu - Total samples mixed: %RU64\n", cChildren, s_cSamplesMixedTotal));
- AUDMIXBUF_LOG(("********************************************\n"));
-}
-
/**
- * Prints statistics and status of the full chain of a mixing buffer to the logger,
- * starting from the top root mixing buffer.
+ * Prints statistics and status of a mixing buffer to the logger.
* For debug versions only.
*
* @return IPRT status code.
* @param pMixBuf Mixing buffer to print.
*/
-void AudioMixBufDbgPrintChain(PPDMAUDIOMIXBUF pMixBuf)
-{
- audioMixBufDbgPrintChainInternal(pMixBuf);
-}
-
-DECL_FORCE_INLINE(void) audioMixBufDbgPrintInternal(PPDMAUDIOMIXBUF pMixBuf)
+static inline void audioMixBufPrint(PPDMAUDIOMIXBUF pMixBuf)
{
PPDMAUDIOMIXBUF pParent = pMixBuf;
if (pMixBuf->pParent)
pParent = pMixBuf->pParent;
- AUDMIXBUF_LOG(("***************************************************************************************\n"));
-
- audioMixBufDbgPrintSingle(pMixBuf, pParent == pMixBuf /* fIsParent */, 0 /* iIdtLevel */);
+ AUDMIXBUF_LOG(("********************************************\n"));
+ AUDMIXBUF_LOG(("%s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
+ pParent->pszName,
+ pParent->offReadWrite, pParent->cProcessed, pParent->cMixed,
+ AUDIOMIXBUF_S2B(pParent, 1)));
PPDMAUDIOMIXBUF pIter;
- RTListForEach(&pParent->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
+ RTListForEach(&pParent->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
{
- if (pIter == pMixBuf)
- continue;
- audioMixBufDbgPrintSingle(pIter, false /* fIsParent */, 1 /* iIdtLevel */);
+ AUDMIXBUF_LOG(("\t%s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
+ pIter->pszName,
+ pIter->offReadWrite, pIter->cProcessed, pIter->cMixed,
+ AUDIOMIXBUF_S2B(pIter, 1)));
}
-
- AUDMIXBUF_LOG(("***************************************************************************************\n"));
-}
-
-/**
- * Prints statistics and status of a mixing buffer to the logger.
- * For debug versions only.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to print.
- */
-void AudioMixBufDbgPrint(PPDMAUDIOMIXBUF pMixBuf)
-{
- audioMixBufDbgPrintInternal(pMixBuf);
+ AUDMIXBUF_LOG(("Total samples mixed: %RU64\n", s_cSamplesMixedTotal));
+ AUDMIXBUF_LOG(("********************************************\n"));
}
-
-#endif /* DEBUG */
+#endif
/**
- * Returns the total number of samples used.
+ * Returns the total number of samples processed.
*
* @return uint32_t
* @param pMixBuf
*/
-uint32_t AudioMixBufUsed(PPDMAUDIOMIXBUF pMixBuf)
+uint32_t AudioMixBufProcessed(PPDMAUDIOMIXBUF pMixBuf)
{
AssertPtrReturn(pMixBuf, 0);
- AUDMIXBUF_LOG(("%s: cUsed=%RU32\n", pMixBuf->pszName, pMixBuf->cUsed));
- return pMixBuf->cUsed;
+ AUDMIXBUF_LOG(("%s: cProcessed=%RU32\n", pMixBuf->pszName, pMixBuf->cProcessed));
+ return pMixBuf->cProcessed;
}
/**
@@ -1306,7 +1218,7 @@ int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
/* pcbRead is optional. */
uint32_t cDstSamples = pMixBuf->cSamples;
- uint32_t cLive = pMixBuf->cUsed;
+ uint32_t cLive = pMixBuf->cProcessed;
uint32_t cDead = cDstSamples - cLive;
uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_S2S_RATIO(pMixBuf, cDead);
@@ -1318,32 +1230,20 @@ int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
int rc;
if (cToProcess)
{
- PFNPDMAUDIOMIXBUFCONVTO pfnConvTo = NULL;
- if (pMixBuf->AudioFmt != enmFmt)
- pfnConvTo = audioMixBufConvToLookup(enmFmt);
- else
- pfnConvTo = pMixBuf->pfnConvTo;
-
- if (pfnConvTo)
+ PAUDMIXBUF_FN_CONVTO pConv = audioMixBufConvToLookup(enmFmt);
+ if (pConv)
{
- PDMAUDMIXBUFCONVOPTS convOpts;
- RT_ZERO(convOpts);
- /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
-
- convOpts.cSamples = cToProcess;
-
- pfnConvTo(pvBuf, pMixBuf->pSamples + offSamples, &convOpts);
+ AUDMIXBUF_CONVOPTS convOpts = { cToProcess, pMixBuf->Volume };
+ pConv(pvBuf, pMixBuf->pSamples + offSamples, &convOpts);
-#ifdef DEBUG
- AudioMixBufDbgPrint(pMixBuf);
-#endif
rc = VINF_SUCCESS;
}
else
- {
- AssertFailed();
- rc = VERR_NOT_SUPPORTED;
- }
+ rc = VERR_INVALID_PARAMETER;
+
+#ifdef DEBUG
+ audioMixBufPrint(pMixBuf);
+#endif
}
else
rc = VINF_SUCCESS;
@@ -1367,9 +1267,11 @@ int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
* @param cbBuf Size (in bytes) of buffer to write to.
* @param pcRead Number of audio samples read. Optional.
*/
-int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
+int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf,
+ void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
{
- return AudioMixBufReadCircEx(pMixBuf, pMixBuf->AudioFmt, pvBuf, cbBuf, pcRead);
+ return AudioMixBufReadCircEx(pMixBuf, pMixBuf->AudioFmt,
+ pvBuf, cbBuf, pcRead);
}
/**
@@ -1384,20 +1286,17 @@ int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, ui
* @param cbBuf Size (in bytes) of buffer to write to.
* @param pcRead Number of audio samples read. Optional.
*/
-int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
+int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
+ void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
{
AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
/* pcbRead is optional. */
if (!cbBuf)
- {
- if (pcRead)
- *pcRead = 0;
return VINF_SUCCESS;
- }
- uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cUsed);
+ uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cProcessed);
AUDMIXBUF_LOG(("%s: pvBuf=%p, cbBuf=%zu (%RU32 samples), cToRead=%RU32\n",
pMixBuf->pszName, pvBuf, cbBuf, AUDIOMIXBUF_B2S(pMixBuf, cbBuf), cToRead));
@@ -1405,60 +1304,54 @@ int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, voi
if (!cToRead)
{
#ifdef DEBUG
- audioMixBufDbgPrintInternal(pMixBuf);
+ audioMixBufPrint(pMixBuf);
#endif
if (pcRead)
*pcRead = 0;
return VINF_SUCCESS;
}
- PFNPDMAUDIOMIXBUFCONVTO pfnConvTo = NULL;
- if (pMixBuf->AudioFmt != enmFmt)
- pfnConvTo = audioMixBufConvToLookup(enmFmt);
- else
- pfnConvTo = pMixBuf->pfnConvTo;
-
- if (!pfnConvTo) /* Audio format not supported. */
- {
- AssertFailed();
+ PAUDMIXBUF_FN_CONVTO pConv = audioMixBufConvToLookup(enmFmt);
+ if (!pConv) /* Audio format not supported. */
return VERR_NOT_SUPPORTED;
- }
- PPDMAUDIOSAMPLE pSamplesSrc1 = pMixBuf->pSamples + pMixBuf->offRead;
+ PPDMAUDIOSAMPLE pSamplesSrc1 = pMixBuf->pSamples + pMixBuf->offReadWrite;
uint32_t cLenSrc1 = cToRead;
PPDMAUDIOSAMPLE pSamplesSrc2 = NULL;
uint32_t cLenSrc2 = 0;
+ uint32_t offRead = pMixBuf->offReadWrite + cToRead;
+
/*
* Do we need to wrap around to read all requested data, that is,
* starting at the beginning of our circular buffer? This then will
* be the optional second part to do.
*/
- if ((pMixBuf->offRead + cToRead) > pMixBuf->cSamples)
+ if (offRead >= pMixBuf->cSamples)
{
- Assert(pMixBuf->offRead <= pMixBuf->cSamples);
- cLenSrc1 = pMixBuf->cSamples - pMixBuf->offRead;
+ Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
+ cLenSrc1 = pMixBuf->cSamples - pMixBuf->offReadWrite;
pSamplesSrc2 = pMixBuf->pSamples;
Assert(cToRead >= cLenSrc1);
cLenSrc2 = RT_MIN(cToRead - cLenSrc1, pMixBuf->cSamples);
+
+ /* Save new read offset. */
+ offRead = cLenSrc2;
}
- PDMAUDMIXBUFCONVOPTS convOpts;
- RT_ZERO(convOpts);
- /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
+ AUDMIXBUF_CONVOPTS convOpts;
+ convOpts.Volume = pMixBuf->Volume;
/* Anything to do at all? */
int rc = VINF_SUCCESS;
if (cLenSrc1)
{
- AssertPtr(pSamplesSrc1);
-
convOpts.cSamples = cLenSrc1;
- AUDMIXBUF_LOG(("P1: offRead=%RU32, cToRead=%RU32\n", pMixBuf->offRead, cLenSrc1));
- pfnConvTo(pvBuf, pSamplesSrc1, &convOpts);
+ AUDMIXBUF_LOG(("P1: offRead=%RU32, cToRead=%RU32\n", pMixBuf->offReadWrite, cLenSrc1));
+ pConv(pvBuf, pSamplesSrc1, &convOpts);
}
/* Second part present? */
@@ -1471,14 +1364,14 @@ int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, voi
AUDMIXBUF_LOG(("P2: cToRead=%RU32, offWrite=%RU32 (%zu bytes)\n", cLenSrc2, cLenSrc1,
AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1)));
- pfnConvTo((uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1), pSamplesSrc2, &convOpts);
+ pConv((uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1), pSamplesSrc2, &convOpts);
}
if (RT_SUCCESS(rc))
{
-#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
+#ifdef DEBUG_DUMP_PCM_DATA
RTFILE fh;
- rc = RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_readcirc.pcm",
+ rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_readcirc.pcm",
RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
if (RT_SUCCESS(rc))
{
@@ -1486,19 +1379,20 @@ int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, voi
RTFileClose(fh);
}
#endif
- pMixBuf->offRead = (pMixBuf->offRead + cToRead) % pMixBuf->cSamples;
- Assert(cToRead <= pMixBuf->cUsed);
- pMixBuf->cUsed -= RT_MIN(cToRead, pMixBuf->cUsed);
+ pMixBuf->offReadWrite = offRead % pMixBuf->cSamples;
+ pMixBuf->cProcessed -= RT_MIN(cLenSrc1 + cLenSrc2, pMixBuf->cProcessed);
if (pcRead)
- *pcRead = cToRead;
+ *pcRead = cLenSrc1 + cLenSrc2;
}
#ifdef DEBUG
- audioMixBufDbgPrintInternal(pMixBuf);
+ audioMixBufPrint(pMixBuf);
#endif
- AUDMIXBUF_LOG(("cRead=%RU32 (%zu bytes), rc=%Rrc\n", cToRead, AUDIOMIXBUF_S2B(pMixBuf, cToRead), rc));
+ AUDMIXBUF_LOG(("cRead=%RU32 (%zu bytes), rc=%Rrc\n",
+ cLenSrc1 + cLenSrc2,
+ AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1 + cLenSrc2), rc));
return rc;
}
@@ -1513,10 +1407,9 @@ void AudioMixBufReset(PPDMAUDIOMIXBUF pMixBuf)
AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
- pMixBuf->offRead = 0;
- pMixBuf->offWrite = 0;
- pMixBuf->cMixed = 0;
- pMixBuf->cUsed = 0;
+ pMixBuf->offReadWrite = 0;
+ pMixBuf->cMixed = 0;
+ pMixBuf->cProcessed = 0;
AudioMixBufClear(pMixBuf);
}
@@ -1532,10 +1425,14 @@ void AudioMixBufSetVolume(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOVOLUME pVol)
AssertPtrReturnVoid(pMixBuf);
AssertPtrReturnVoid(pVol);
- LogFlowFunc(("%s: lVol=%RU8, rVol=%RU8, fMuted=%RTbool\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight, pVol->fMuted));
+ LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight));
+
+ pMixBuf->Volume.fMuted = pVol->fMuted;
+ /** @todo Ensure that the input is in the correct range/initialized! */
+ pMixBuf->Volume.uLeft = s_aVolumeConv[pVol->uLeft & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
+ pMixBuf->Volume.uRight = s_aVolumeConv[pVol->uRight & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
- int rc2 = audioMixBufConvVol(&pMixBuf->Volume /* Dest */, pVol /* Source */);
- AssertRC(rc2);
+ LogFlowFunc(("\t-> lVol=%#RX32, rVol=%#RX32\n", pMixBuf->Volume.uLeft, pMixBuf->Volume.uRight));
}
/**
@@ -1588,23 +1485,19 @@ void AudioMixBufUnlink(PPDMAUDIOMIXBUF pMixBuf)
pMixBuf->pParent = NULL;
}
- PPDMAUDIOMIXBUF pChild, pChildNext;
- RTListForEachSafe(&pMixBuf->lstChildren, pChild, pChildNext, PDMAUDIOMIXBUF, Node)
+ PPDMAUDIOMIXBUF pIter;
+ while (!RTListIsEmpty(&pMixBuf->lstBuffers))
{
- AUDMIXBUF_LOG(("\tUnlinking \"%s\"\n", pChild->pszName));
+ pIter = RTListGetFirst(&pMixBuf->lstBuffers, PDMAUDIOMIXBUF, Node);
- AudioMixBufReset(pChild);
+ AUDMIXBUF_LOG(("\tUnlinking \"%s\"\n", pIter->pszName));
- Assert(pChild->pParent == pMixBuf);
- pChild->pParent = NULL;
+ AudioMixBufReset(pIter->pParent);
+ pIter->pParent = NULL;
- RTListNodeRemove(&pChild->Node);
+ RTListNodeRemove(&pIter->Node);
}
- Assert(RTListIsEmpty(&pMixBuf->lstChildren));
-
- AudioMixBufReset(pMixBuf);
-
if (pMixBuf->pRate)
{
pMixBuf->pRate->dstOffset = pMixBuf->pRate->srcOffset = 0;
@@ -1620,21 +1513,25 @@ void AudioMixBufUnlink(PPDMAUDIOMIXBUF pMixBuf)
*
* @return IPRT status code.
* @param pMixBuf Pointer to mixing buffer to write to.
+ * @param enmFmt Audio format supplied in the buffer.
* @param offSamples Offset (in samples) starting to write at.
* @param pvBuf Pointer to audio buffer to be written.
* @param cbBuf Size (in bytes) of audio buffer.
* @param pcWritten Returns number of audio samples written. Optional.
*/
-int AudioMixBufWriteAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
+int AudioMixBufWriteAt(PPDMAUDIOMIXBUF pMixBuf,
+ uint32_t offSamples,
+ const void *pvBuf, uint32_t cbBuf,
+ uint32_t *pcWritten)
{
- return AudioMixBufWriteAtEx(pMixBuf, pMixBuf->AudioFmt, offSamples, pvBuf, cbBuf, pcWritten);
+ return AudioMixBufWriteAtEx(pMixBuf, pMixBuf->AudioFmt,
+ offSamples, pvBuf, cbBuf, pcWritten);
}
/**
- * Writes audio samples at a specific offset.
- *
- * The audio sample format to be written can be different from the audio format
- * the mixing buffer operates on.
+ * Writes audio samples at a specific offset. The audio sample format
+ * to be written can be different from the audio format the mixing buffer
+ * operates on.
*
* @return IPRT status code.
* @param pMixBuf Pointer to mixing buffer to write to.
@@ -1650,103 +1547,72 @@ int AudioMixBufWriteAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
uint32_t *pcWritten)
{
AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
/* pcWritten is optional. */
- /*
- * Adjust cToWrite so we don't overflow our buffers.
- */
+ uint32_t cDstSamples = pMixBuf->pParent
+ ? pMixBuf->pParent->cSamples : pMixBuf->cSamples;
+ uint32_t cLive = pMixBuf->cProcessed;
+
+ uint32_t cDead = cDstSamples - cLive;
+ uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_S2S_RATIO(pMixBuf, cDead);
+ cToProcess = RT_MIN(cToProcess, AUDIOMIXBUF_B2S(pMixBuf, cbBuf));
+
+ AUDMIXBUF_LOG(("%s: offSamples=%RU32, cLive=%RU32, cDead=%RU32, cToProcess=%RU32\n",
+ pMixBuf->pszName, offSamples, cLive, cDead, cToProcess));
+
+ if (offSamples + cToProcess > pMixBuf->cSamples)
+ return VERR_BUFFER_OVERFLOW;
+
+ PAUDMIXBUF_FN_CONVFROM pConv = audioMixBufConvFromLookup(enmFmt, pMixBuf->Volume.fMuted);
+ if (!pConv)
+ return VERR_NOT_SUPPORTED;
+
int rc;
- uint32_t cToWrite = AUDIOMIXBUF_B2S(pMixBuf, cbBuf);
- if (offSamples <= pMixBuf->cSamples)
- {
- if (offSamples + cToWrite <= pMixBuf->cSamples)
- rc = VINF_SUCCESS;
- else
- {
- rc = VINF_BUFFER_OVERFLOW;
- cToWrite = pMixBuf->cSamples - offSamples;
- }
- }
- else
- {
- rc = VINF_BUFFER_OVERFLOW;
- cToWrite = 0;
- }
+ uint32_t cWritten;
-#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
- /*
- * Now that we know how much we'll be converting we can log it.
- */
- RTFILE hFile;
- int rc2 = RTFileOpen(&hFile, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeat.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- if (RT_SUCCESS(rc2))
+#ifdef DEBUG_DUMP_PCM_DATA
+ RTFILE fh;
+ rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeat.pcm",
+ RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+ if (RT_SUCCESS(rc))
{
- RTFileWrite(hFile, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cToWrite), NULL);
- RTFileClose(hFile);
+ RTFileWrite(fh, pvBuf, cbBuf, NULL);
+ RTFileClose(fh);
}
#endif
- /*
- * Pick the conversion function and do the conversion.
- */
- PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
- if (!pMixBuf->Volume.fMuted)
- {
- if (pMixBuf->AudioFmt != enmFmt)
- pfnConvFrom = audioMixBufConvFromLookup(enmFmt);
- else
- pfnConvFrom = pMixBuf->pfnConvFrom;
- }
- else
- pfnConvFrom = &audioMixBufConvFromSilence;
-
- uint32_t cWritten;
- if ( pfnConvFrom
- && cToWrite)
+ if (cToProcess)
{
- PDMAUDMIXBUFCONVOPTS convOpts;
+ AUDMIXBUF_CONVOPTS convOpts = { cToProcess, pMixBuf->Volume };
- convOpts.cSamples = cToWrite;
- convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
- convOpts.From.Volume.uLeft = pMixBuf->Volume.uLeft;
- convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
-
- cWritten = pfnConvFrom(pMixBuf->pSamples + offSamples, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cToWrite), &convOpts);
+ cWritten = pConv(pMixBuf->pSamples + offSamples, pvBuf, cbBuf, &convOpts);
+#ifdef DEBUG
+ audioMixBufPrint(pMixBuf);
+#endif
+ rc = cWritten ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Fudge! */
}
else
{
cWritten = 0;
- if (!pfnConvFrom)
- {
- AssertFailed();
- rc = VERR_NOT_SUPPORTED;
- }
+ rc = VINF_SUCCESS;
}
-#ifdef DEBUG
- audioMixBufDbgPrintInternal(pMixBuf);
-#endif
-
- AUDMIXBUF_LOG(("%s: offSamples=%RU32, cbBuf=%RU32, cToWrite=%RU32 (%zu bytes), cWritten=%RU32 (%zu bytes), rc=%Rrc\n",
- pMixBuf->pszName, offSamples, cbBuf,
- cToWrite, AUDIOMIXBUF_S2B(pMixBuf, cToWrite),
- cWritten, AUDIOMIXBUF_S2B(pMixBuf, cWritten), rc));
-
- if (RT_SUCCESS(rc) && pcWritten)
- *pcWritten = cWritten;
+ if (RT_SUCCESS(rc))
+ {
+ if (pcWritten)
+ *pcWritten = cWritten;
+ }
+ AUDMIXBUF_LOG(("cWritten=%RU32, rc=%Rrc\n", cWritten, rc));
return rc;
}
/**
- * Writes audio samples.
+ * Writes audio samples. The sample format being written must match the
+ * format of the mixing buffer.
*
- * The sample format being written must match the format of the mixing buffer.
- *
- * @return IPRT status code, or VINF_BUFFER_OVERFLOW if samples which not have
- * been processed yet have been overwritten (due to cyclic buffer).
+ * @return IPRT status code.
* @param pMixBuf Pointer to mixing buffer to write to.
* @param pvBuf Pointer to audio buffer to be written.
* @param cbBuf Size (in bytes) of audio buffer.
@@ -1762,8 +1628,7 @@ int AudioMixBufWriteCirc(PPDMAUDIOMIXBUF pMixBuf,
/**
* Writes audio samples of a specific format.
*
- * @return IPRT status code, or VINF_BUFFER_OVERFLOW if samples which not have
- * been processed yet have been overwritten (due to cyclic buffer).
+ * @return IPRT status code.
* @param pMixBuf Pointer to mixing buffer to write to.
* @param enmFmt Audio format supplied in the buffer.
* @param pvBuf Pointer to audio buffer to be written.
@@ -1771,10 +1636,11 @@ int AudioMixBufWriteCirc(PPDMAUDIOMIXBUF pMixBuf,
* @param pcWritten Returns number of audio samples written. Optional.
*/
int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
- const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
+ const void *pvBuf, uint32_t cbBuf,
+ uint32_t *pcWritten)
{
AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
/* pcbWritten is optional. */
if (!cbBuf)
@@ -1786,136 +1652,104 @@ int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
PPDMAUDIOMIXBUF pParent = pMixBuf->pParent;
- AUDMIXBUF_LOG(("%s: enmFmt=%d, pvBuf=%p, cbBuf=%RU32 (%RU32 samples)\n",
- pMixBuf->pszName, enmFmt, pvBuf, cbBuf, AUDIOMIXBUF_B2S(pMixBuf, cbBuf)));
+ AUDMIXBUF_LOG(("%s: enmFmt=%ld, pBuf=%p, cbBuf=%zu, pParent=%p (%RU32)\n",
+ pMixBuf->pszName, enmFmt, pvBuf, cbBuf, pParent, pParent ? pParent->cSamples : 0));
if ( pParent
- && pParent->cSamples < pMixBuf->cMixed)
+ && pParent->cSamples <= pMixBuf->cMixed)
{
if (pcWritten)
*pcWritten = 0;
- AUDMIXBUF_LOG(("%s: Parent buffer '%s' is full\n",
+ AUDMIXBUF_LOG(("%s: Parent buffer %s is full\n",
pMixBuf->pszName, pMixBuf->pParent->pszName));
- return VINF_BUFFER_OVERFLOW;
+ return VINF_SUCCESS;
}
- PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
- if (!pMixBuf->Volume.fMuted)
- {
- if (pMixBuf->AudioFmt != enmFmt)
- pfnConvFrom = audioMixBufConvFromLookup(enmFmt);
- else
- pfnConvFrom = pMixBuf->pfnConvFrom;
- }
- else
- pfnConvFrom = &audioMixBufConvFromSilence;
-
- if (!pfnConvFrom)
- {
- AssertFailed();
+ PAUDMIXBUF_FN_CONVFROM pConv = audioMixBufConvFromLookup(enmFmt, pMixBuf->Volume.fMuted);
+ if (!pConv)
return VERR_NOT_SUPPORTED;
- }
+
+ int rc = VINF_SUCCESS;
uint32_t cToWrite = AUDIOMIXBUF_B2S(pMixBuf, cbBuf);
AssertMsg(cToWrite, ("cToWrite is 0 (cbBuf=%zu)\n", cbBuf));
- PPDMAUDIOSAMPLE pSamplesDst1 = pMixBuf->pSamples + pMixBuf->offWrite;
+ PPDMAUDIOSAMPLE pSamplesDst1 = pMixBuf->pSamples + pMixBuf->offReadWrite;
uint32_t cLenDst1 = cToWrite;
PPDMAUDIOSAMPLE pSamplesDst2 = NULL;
uint32_t cLenDst2 = 0;
- uint32_t cOffWrite = pMixBuf->offWrite + cToWrite;
+ uint32_t offWrite = pMixBuf->offReadWrite + cToWrite;
/*
* Do we need to wrap around to write all requested data, that is,
* starting at the beginning of our circular buffer? This then will
* be the optional second part to do.
*/
- if (cOffWrite >= pMixBuf->cSamples)
+ if (offWrite >= pMixBuf->cSamples)
{
- Assert(pMixBuf->offWrite <= pMixBuf->cSamples);
- cLenDst1 = pMixBuf->cSamples - pMixBuf->offWrite;
+ Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
+ cLenDst1 = pMixBuf->cSamples - pMixBuf->offReadWrite;
pSamplesDst2 = pMixBuf->pSamples;
Assert(cToWrite >= cLenDst1);
cLenDst2 = RT_MIN(cToWrite - cLenDst1, pMixBuf->cSamples);
/* Save new read offset. */
- cOffWrite = cLenDst2;
+ offWrite = cLenDst2;
}
-#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writecirc_ex.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
-#endif
-
uint32_t cWrittenTotal = 0;
- PDMAUDMIXBUFCONVOPTS convOpts;
- convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
- convOpts.From.Volume.uLeft = pMixBuf->Volume.uLeft;
- convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
+ AUDMIXBUF_CONVOPTS convOpts;
+ convOpts.Volume = pMixBuf->Volume;
/* Anything to do at all? */
if (cLenDst1)
{
convOpts.cSamples = cLenDst1;
- cWrittenTotal = pfnConvFrom(pSamplesDst1, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), &convOpts);
- Assert(cWrittenTotal == cLenDst1);
-
-#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
- RTFileWrite(fh, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), NULL);
-#endif
+ cWrittenTotal = pConv(pSamplesDst1, pvBuf, cbBuf, &convOpts);
}
/* Second part present? */
- if (cLenDst2)
+ if ( RT_LIKELY(RT_SUCCESS(rc))
+ && cLenDst2)
{
AssertPtr(pSamplesDst2);
convOpts.cSamples = cLenDst2;
- cWrittenTotal += pfnConvFrom(pSamplesDst2,
- (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
- cbBuf - AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
- &convOpts);
- Assert(cWrittenTotal == cLenDst1 + cLenDst2);
-
-#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
- RTFileWrite(fh, (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1),
- cbBuf - AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), NULL);
-#endif
+ cWrittenTotal += pConv(pSamplesDst2, (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), cbBuf, &convOpts);
}
-#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
- RTFileClose(fh);
+#ifdef DEBUG_DUMP_PCM_DATA
+ RTFILE fh;
+ RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeex.pcm",
+ RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+ RTFileWrite(fh, pSamplesDst1, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), NULL);
+ RTFileClose(fh);
#endif
- pMixBuf->offWrite = (pMixBuf->offWrite + cWrittenTotal) % pMixBuf->cSamples;
- pMixBuf->cUsed += cWrittenTotal;
-
- int rc = VINF_SUCCESS;
+ AUDMIXBUF_LOG(("cLenDst1=%RU32, cLenDst2=%RU32, offWrite=%RU32\n",
+ cLenDst1, cLenDst2, offWrite));
- if (pMixBuf->cUsed > pMixBuf->cSamples)
+ if (RT_SUCCESS(rc))
{
- AUDMIXBUF_LOG(("Warning: %RU32 unprocessed samples overwritten\n", pMixBuf->cUsed - pMixBuf->cSamples));
- pMixBuf->cUsed = pMixBuf->cSamples;
-
- rc = VINF_BUFFER_OVERFLOW;
+ pMixBuf->offReadWrite = offWrite % pMixBuf->cSamples;
+ pMixBuf->cProcessed = RT_MIN(pMixBuf->cProcessed + cLenDst1 + cLenDst2,
+ pMixBuf->cSamples /* Max */);
+ if (pcWritten)
+ *pcWritten = cLenDst1 + cLenDst2;
}
- if (pcWritten)
- *pcWritten = cWrittenTotal;
-
#ifdef DEBUG
- audioMixBufDbgPrintInternal(pMixBuf);
+ audioMixBufPrint(pMixBuf);
#endif
- AUDMIXBUF_LOG(("offWrite=%RU32, cLenDst1=%RU32, cLenDst2=%RU32, cTotal=%RU32 (%zu bytes), rc=%Rrc\n",
- pMixBuf->offWrite, cLenDst1, cLenDst2, cLenDst1 + cLenDst2,
+ AUDMIXBUF_LOG(("cWritten=%RU32 (%zu bytes), rc=%Rrc\n",
+ cLenDst1 + cLenDst2,
AUDIOMIXBUF_S2B(pMixBuf, cLenDst1 + cLenDst2), rc));
return rc;
}
diff --git a/src/VBox/Devices/Audio/AudioMixBuffer.h b/src/VBox/Devices/Audio/AudioMixBuffer.h
index 4f1a244..11c5912 100644
--- a/src/VBox/Devices/Audio/AudioMixBuffer.h
+++ b/src/VBox/Devices/Audio/AudioMixBuffer.h
@@ -1,10 +1,11 @@
/* $Id: AudioMixBuffer.h $ */
/** @file
- * VBox audio - Mixing buffer to convert audio samples to/from different rates / formats.
+ * VBox audio: Mixing buffer to convert audio samples to/from different
+ * rates / formats.
*/
/*
- * Copyright (C) 2014-2016 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -49,18 +50,20 @@
int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead, PPDMAUDIOSAMPLE *ppvSamples, uint32_t *pcSamplesRead);
+uint32_t AudioMixBufAvail(PPDMAUDIOMIXBUF pMixBuf);
inline uint32_t AudioMixBufBytesToSamples(PPDMAUDIOMIXBUF pMixBuf);
void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf);
void AudioMixBufDestroy(PPDMAUDIOMIXBUF pMixBuf);
void AudioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear);
uint32_t AudioMixBufFree(PPDMAUDIOMIXBUF pMixBuf);
uint32_t AudioMixBufFreeBytes(PPDMAUDIOMIXBUF pMixBuf);
-int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMAUDIOPCMPROPS pProps, uint32_t cSamples);
+int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMPCMPROPS pProps, uint32_t cSamples);
bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf);
int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent);
-uint32_t AudioMixBufLive(PPDMAUDIOMIXBUF pMixBuf);
+uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf);
+int AudioMixBufMixToChildren(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
-uint32_t AudioMixBufUsed(PPDMAUDIOMIXBUF pMixBuf);
+uint32_t AudioMixBufProcessed(PPDMAUDIOMIXBUF pMixBuf);
int AudioMixBufReadAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead);
@@ -75,10 +78,5 @@ int AudioMixBufWriteAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, uint
int AudioMixBufWriteCirc(PPDMAUDIOMIXBUF pMixBuf, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
-#ifdef DEBUG
-void AudioMixBufDbgPrint(PPDMAUDIOMIXBUF pMixBuf);
-void AudioMixBufDbgPrintChain(PPDMAUDIOMIXBUF pMixBuf);
-#endif
-
-#endif
+#endif /* !AUDIO_MIXBUF_H */
diff --git a/src/VBox/Devices/Audio/AudioMixer.cpp b/src/VBox/Devices/Audio/AudioMixer.cpp
index d904fc1..83a082f 100644
--- a/src/VBox/Devices/Audio/AudioMixer.cpp
+++ b/src/VBox/Devices/Audio/AudioMixer.cpp
@@ -3,22 +3,6 @@
* VBox audio: Mixing routines, mainly used by the various audio device
* emulations to achieve proper multiplexing from/to attached
* devices LUNs.
- *
- * This mixer acts as a layer between the audio connector interface and
- * the actual device emulation, providing mechanisms for audio sources (input) and
- * audio sinks (output).
- *
- * As audio driver instances are handled as LUNs on the device level, this
- * audio mixer then can take care of e.g. mixing various inputs/outputs to/from
- * a specific source/sink.
- *
- * How and which audio streams are connected to sinks/sources depends on how
- * the audio mixer has been set up.
- *
- * A sink can connect multiple output streams together, whereas a source
- * does this with input streams. Each sink / source consists of one or more
- * so-called mixer streams, which then in turn have pointers to the actual
- * PDM audio input/output streams.
*/
/*
@@ -36,7 +20,6 @@
#include <VBox/log.h>
#include "AudioMixer.h"
#include "AudioMixBuffer.h"
-#include "DrvAudio.h"
#include <VBox/vmm/pdm.h>
#include <VBox/err.h>
@@ -48,37 +31,16 @@
#include <iprt/assert.h>
#include <iprt/string.h>
-static int audioMixerRemoveSinkInternal(PAUDIOMIXER pMixer, PAUDMIXSINK pSink);
+static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster);
-static void audioMixerSinkDestroyInternal(PAUDMIXSINK pSink);
-static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster);
-static void audioMixerSinkRemoveAllStreamsInternal(PAUDMIXSINK pSink);
-static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
-static void audioMixerSinkReset(PAUDMIXSINK pSink);
-static int audioMixerSinkUpdateInternal(PAUDMIXSINK pSink);
-int audioMixerStreamCtlInternal(PAUDMIXSTREAM pMixStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl);
-static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pStream);
-
-
-/**
- * Creates an audio sink and attaches it to the given mixer.
- *
- * @returns IPRT status code.
- * @param pMixer Mixer to attach created sink to.
- * @param pszName Name of the sink to create.
- * @param enmDir Direction of the sink to create.
- * @param ppSink Pointer which returns the created sink on success.
- */
-int AudioMixerCreateSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink)
+int AudioMixerAddSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink)
{
AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- /* ppSink is optional. */
+ /** ppSink is optional. */
- int rc = RTCritSectEnter(&pMixer->CritSect);
- if (RT_FAILURE(rc))
- return rc;
+ int rc = VINF_SUCCESS;
PAUDMIXSINK pSink = (PAUDMIXSINK)RTMemAllocZ(sizeof(AUDMIXSINK));
if (pSink)
@@ -88,23 +50,16 @@ int AudioMixerCreateSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR
rc = VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
- rc = RTCritSectInit(&pSink->CritSect);
-
- if (RT_SUCCESS(rc))
{
pSink->pParent = pMixer;
+ pSink->cStreams = 0;
pSink->enmDir = enmDir;
RTListInit(&pSink->lstStreams);
/* Set initial volume to max. */
pSink->Volume.fMuted = false;
- pSink->Volume.uLeft = PDMAUDIO_VOLUME_MAX;
- pSink->Volume.uRight = PDMAUDIO_VOLUME_MAX;
-
- /* Ditto for the combined volume. */
- pSink->VolumeCombined.fMuted = false;
- pSink->VolumeCombined.uLeft = PDMAUDIO_VOLUME_MAX;
- pSink->VolumeCombined.uRight = PDMAUDIO_VOLUME_MAX;
+ pSink->Volume.uLeft = 0x7F;
+ pSink->Volume.uRight = 0x7F;
RTListAppend(&pMixer->lstSinks, &pSink->Node);
pMixer->cSinks++;
@@ -115,40 +70,111 @@ int AudioMixerCreateSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR
if (ppSink)
*ppSink = pSink;
}
+ else
+ RTMemFree(pSink);
+ }
+ else
+ rc = VERR_NO_MEMORY;
- if (RT_FAILURE(rc))
- {
- RTCritSectDelete(&pSink->CritSect);
+ return rc;
+}
- if (pSink)
- {
- RTMemFree(pSink);
- pSink = NULL;
- }
- }
+int AudioMixerAddStreamIn(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMIN pStream,
+ uint32_t uFlags, PAUDMIXSTREAM *ppStream)
+{
+ RT_NOREF(uFlags);
+ AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ /** @todo Add flag validation. */
+ /* ppStream is optional. */
+
+ int rc;
+
+ if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
+ return VERR_TOO_MUCH_DATA;
+
+ PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
+ if (pMixStream)
+ {
+ pMixStream->pConn = pConnector;
+ pMixStream->pIn = pStream;
+ /** @todo Process flags. */
+
+ RTListAppend(&pSink->lstStreams, &pMixStream->Node);
+ pSink->cStreams++;
+
+ LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",
+ pSink->pszName, pMixStream, pSink->cStreams));
+
+ /* Increase the stream's reference count to let others know
+ * we're reyling on it to be around now. */
+ pStream->State.cRefs++;
+
+ if (ppStream)
+ *ppStream = pMixStream;
+
+ rc = VINF_SUCCESS;
}
else
rc = VERR_NO_MEMORY;
- int rc2 = RTCritSectLeave(&pMixer->CritSect);
- AssertRC(rc2);
+ return rc;
+}
+
+int AudioMixerAddStreamOut(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMOUT pStream,
+ uint32_t uFlags, PAUDMIXSTREAM *ppStream)
+{
+ RT_NOREF(uFlags);
+ AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ /** @todo Add flag validation. */
+ /* ppStream is optional. */
+
+ int rc;
+
+ if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
+ return VERR_TOO_MUCH_DATA;
+
+ PAUDMIXSTREAM pMixStream
+ = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
+ if (pMixStream)
+ {
+ pMixStream->pConn = pConnector;
+ pMixStream->pOut = pStream;
+ /** @todo Process flags. */
+
+ RTListAppend(&pSink->lstStreams, &pMixStream->Node);
+ pSink->cStreams++;
+
+ LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",
+ pSink->pszName, pMixStream, pSink->cStreams));
+
+ /* Increase the stream's reference count to let others know
+ * we're reyling on it to be around now. */
+ pStream->State.cRefs++;
+
+ if (ppStream)
+ *ppStream = pMixStream;
+
+ rc = VINF_SUCCESS;
+ }
+ else
+ rc = VERR_NO_MEMORY;
return rc;
}
-/**
- * Creates an audio mixer.
- *
- * @returns IPRT status code.
- * @param pszName Name of the audio mixer.
- * @param fFlags Creation flags. Not used at the moment and must be 0.
- * @param ppMixer Pointer which returns the created mixer object.
- */
-int AudioMixerCreate(const char *pszName, uint32_t fFlags, PAUDIOMIXER *ppMixer)
+int AudioMixerControlStream(PAUDIOMIXER pMixer, PAUDMIXSTREAM pHandle)
+{
+ RT_NOREF(pMixer, pHandle);
+ return VERR_NOT_IMPLEMENTED;
+}
+
+int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer)
{
- RT_NOREF(fFlags);
+ RT_NOREF(uFlags);
AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- /** @todo Add fFlags validation. */
+ /** @todo Add flag validation. */
AssertPtrReturn(ppMixer, VERR_INVALID_POINTER);
int rc = VINF_SUCCESS;
@@ -161,19 +187,15 @@ int AudioMixerCreate(const char *pszName, uint32_t fFlags, PAUDIOMIXER *ppMixer)
rc = VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
- rc = RTCritSectInit(&pMixer->CritSect);
-
- if (RT_SUCCESS(rc))
{
pMixer->cSinks = 0;
RTListInit(&pMixer->lstSinks);
- /* Set master volume to the max. */
pMixer->VolMaster.fMuted = false;
- pMixer->VolMaster.uLeft = PDMAUDIO_VOLUME_MAX;
- pMixer->VolMaster.uRight = PDMAUDIO_VOLUME_MAX;
+ pMixer->VolMaster.uLeft = UINT32_MAX;
+ pMixer->VolMaster.uRight = UINT32_MAX;
- LogFlowFunc(("Created mixer '%s'\n", pMixer->pszName));
+ LogFlowFunc(("Created %p ...\n", pMixer));
*ppMixer = pMixer;
}
@@ -187,67 +209,18 @@ int AudioMixerCreate(const char *pszName, uint32_t fFlags, PAUDIOMIXER *ppMixer)
return rc;
}
-#ifdef DEBUG
-/**
- * Helper function for the internal debugger to print the mixer's current
- * state, along with the attached sinks.
- *
- * @param pMixer Mixer to print debug output for.
- * @param pHlp Debug info helper to use.
- * @param pszArgs Optional arguments. Not being used at the moment.
- */
-void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- RT_NOREF(pszArgs);
- PAUDMIXSINK pSink;
- unsigned iSink = 0;
-
- int rc2 = RTCritSectEnter(&pMixer->CritSect);
- if (RT_FAILURE(rc2))
- return;
-
- pHlp->pfnPrintf(pHlp, "[Master] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", pMixer->pszName,
- pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight, pMixer->VolMaster.fMuted);
-
- RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
- {
- pHlp->pfnPrintf(pHlp, "[Sink %u] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", iSink, pSink->pszName,
- pSink->Volume.uLeft, pSink->Volume.uRight, pSink->Volume.fMuted);
- ++iSink;
- }
-
- rc2 = RTCritSectLeave(&pMixer->CritSect);
- AssertRC(rc2);
-}
-#endif
-
-/**
- * Destroys an audio mixer.
- *
- * @param pMixer Audio mixer to destroy.
- */
void AudioMixerDestroy(PAUDIOMIXER pMixer)
{
if (!pMixer)
return;
- int rc2 = RTCritSectEnter(&pMixer->CritSect);
- AssertRC(rc2);
-
LogFlowFunc(("Destroying %s ...\n", pMixer->pszName));
PAUDMIXSINK pSink, pSinkNext;
RTListForEachSafe(&pMixer->lstSinks, pSink, pSinkNext, AUDMIXSINK, Node)
- {
- /* Save a pointer to the sink to remove, as pSink
- * will not be valid anymore after calling audioMixerRemoveSinkInternal(). */
- PAUDMIXSINK pSinkToRemove = pSink;
-
- audioMixerRemoveSinkInternal(pMixer, pSinkToRemove);
- audioMixerSinkDestroyInternal(pSinkToRemove);
- }
+ AudioMixerRemoveSink(pMixer, pSink);
- pMixer->cSinks = 0;
+ Assert(pMixer->cSinks == 0);
if (pMixer->pszName)
{
@@ -255,1493 +228,293 @@ void AudioMixerDestroy(PAUDIOMIXER pMixer)
pMixer->pszName = NULL;
}
- rc2 = RTCritSectLeave(&pMixer->CritSect);
- AssertRC(rc2);
+ RTMemFree(pMixer);
+}
- RTCritSectDelete(&pMixer->CritSect);
+static void audioMixerDestroySink(PAUDMIXSINK pSink)
+{
+ AssertPtrReturnVoid(pSink);
+ if (!pSink)
+ return;
- RTMemFree(pMixer);
- pMixer = NULL;
+ if (pSink->pszName)
+ RTStrFree(pSink->pszName);
+
+ RTMemFree(pSink);
}
-/**
- * Invalidates all internal data, internal version.
- *
- * @returns IPRT status code.
- * @param pMixer Mixer to invalidate data for.
- */
-int audioMixerInvalidateInternal(PAUDIOMIXER pMixer)
+static void audioMixerDestroyStream(PAUDMIXSTREAM pStream)
+{
+ AssertPtrReturnVoid(pStream);
+ if (!pStream)
+ return;
+
+ RTMemFree(pStream);
+}
+
+int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
{
AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+ /** @todo Perform a deep copy, if needed. */
+ *pCfg = pMixer->devFmt;
+
+ return VINF_SUCCESS;
+}
+
+uint32_t AudioMixerGetStreamCount(PAUDIOMIXER pMixer)
+{
+ AssertPtrReturn(pMixer, 0);
+
+ uint32_t cStreams = 0;
+
+ PAUDMIXSINK pSink;
+ RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
+ cStreams += pSink->cStreams;
+
+ return cStreams;
+}
- LogFlowFunc(("[%s]\n", pMixer->pszName));
+void AudioMixerInvalidate(PAUDIOMIXER pMixer)
+{
+ AssertPtrReturnVoid(pMixer);
+
+ LogFlowFunc(("%s: Invalidating ...\n", pMixer->pszName));
/* Propagate new master volume to all connected sinks. */
PAUDMIXSINK pSink;
RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
{
- int rc2 = audioMixerSinkUpdateVolume(pSink, &pMixer->VolMaster);
+ int rc2 = audioMixerUpdateSinkVolume(pSink, &pMixer->VolMaster);
AssertRC(rc2);
}
-
- return VINF_SUCCESS;
}
-/**
- * Invalidates all internal data.
- *
- * @returns IPRT status code.
- * @param pMixer Mixer to invalidate data for.
- */
-void AudioMixerInvalidate(PAUDIOMIXER pMixer)
+int AudioMixerProcessSinkIn(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed)
{
- AssertPtrReturnVoid(pMixer);
+ RT_NOREF(enmOp);
+ AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
+ /* pcbProcessed is optional. */
- int rc2 = RTCritSectEnter(&pMixer->CritSect);
- AssertRC(rc2);
+ /** @todo Handle mixing operation enmOp! */
- LogFlowFunc(("[%s]\n", pMixer->pszName));
+ uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf);
+ if (!pvMixBuf)
+ return VERR_NO_MEMORY;
- rc2 = audioMixerInvalidateInternal(pMixer);
- AssertRC(rc2);
+ int rc = VERR_NOT_FOUND;
+ uint32_t cbProcessed = 0;
- rc2 = RTCritSectLeave(&pMixer->CritSect);
- AssertRC(rc2);
-}
+ LogFlowFunc(("%s: pvBuf=%p, cbBuf=%zu\n", pSink->pszName, pvBuf, cbBuf));
-/**
- * Removes a formerly attached audio sink for an audio mixer, internal version.
- *
- * @returns IPRT status code.
- * @param pMixer Mixer to remove sink from.
- * @param pSink Sink to remove.
- */
-static int audioMixerRemoveSinkInternal(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
-{
- AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
- if (!pSink)
- return VERR_NOT_FOUND;
+ PAUDMIXSTREAM pStream;
+ RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
+ {
+ /** @todo Support output sinks as well! */
+ if (!pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->pIn))
+ continue;
- AssertMsgReturn(pSink->pParent == pMixer, ("Sink '%s' is not part of mixer '%s'\n",
- pSink->pszName, pMixer->pszName), VERR_NOT_FOUND);
+ uint32_t cbTotalRead = 0;
+ uint32_t cbToRead = cbBuf;
- LogFlowFunc(("[%s]: pSink=%s, cSinks=%RU8\n",
- pMixer->pszName, pSink->pszName, pMixer->cSinks));
+ while (cbToRead)
+ {
+ uint32_t cbRead;
+ AssertPtr(pStream->pConn);
+ rc = pStream->pConn->pfnRead(pStream->pConn, pStream->pIn,
+ (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbRead);
+ if ( RT_FAILURE(rc)
+ || !cbRead)
+ break;
- /* Remove sink from mixer. */
- RTListNodeRemove(&pSink->Node);
- Assert(pMixer->cSinks);
- pMixer->cSinks--;
+ AssertBreakStmt(cbRead <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
+ cbToRead -= cbRead;
+ cbTotalRead += cbRead;
+ }
- /* Set mixer to NULL so that we know we're not part of any mixer anymore. */
- pSink->pParent = NULL;
+ if (RT_FAILURE(rc))
+ continue;
- return VINF_SUCCESS;
-}
+ cbProcessed = RT_MAX(cbProcessed, cbTotalRead);
+ }
-/**
- * Removes a formerly attached audio sink for an audio mixer.
- *
- * @returns IPRT status code.
- * @param pMixer Mixer to remove sink from.
- * @param pSink Sink to remove.
- */
+ if (RT_SUCCESS(rc))
+ {
+ memcpy(pvBuf, pvMixBuf, cbProcessed); /* @todo Use an intermediate mixing buffer per sink! */
-void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
-{
- int rc2 = RTCritSectEnter(&pMixer->CritSect);
- AssertRC(rc2);
+ if (pcbProcessed)
+ *pcbProcessed = cbProcessed;
+ }
- audioMixerSinkRemoveAllStreamsInternal(pSink);
- audioMixerRemoveSinkInternal(pMixer, pSink);
+ RTMemFree(pvMixBuf);
- rc2 = RTCritSectLeave(&pMixer->CritSect);
+ LogFlowFunc(("cbProcessed=%RU32, rc=%Rrc\n", cbProcessed, rc));
+ return rc;
}
-/**
- * Sets the mixer's master volume.
- *
- * @returns IPRT status code.
- * @param pMixer Mixer to set master volume for.
- * @param pVol Volume to set.
- */
-int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol)
+int AudioMixerProcessSinkOut(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed)
{
- AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
- AssertPtrReturn(pVol, VERR_INVALID_POINTER);
+ RT_NOREF(pSink, enmOp, pvBuf, cbBuf, pcbProcessed);
+ return VERR_NOT_IMPLEMENTED;
+}
- int rc = RTCritSectEnter(&pMixer->CritSect);
- if (RT_FAILURE(rc))
- return rc;
+void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
+{
+ AssertPtrReturnVoid(pMixer);
+ if (!pSink)
+ return;
- memcpy(&pMixer->VolMaster, pVol, sizeof(PDMAUDIOVOLUME));
+ PAUDMIXSTREAM pStream, pStreamNext;
+ RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
+ AudioMixerRemoveStream(pSink, pStream);
- LogFlowFunc(("[%s]: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
- pMixer->pszName, pVol->uLeft, pVol->uRight,
- pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
+ Assert(pSink->cStreams == 0);
- rc = audioMixerInvalidateInternal(pMixer);
+ RTListNodeRemove(&pSink->Node);
+ Assert(pMixer->cSinks);
+ pMixer->cSinks--;
- int rc2 = RTCritSectLeave(&pMixer->CritSect);
- AssertRC(rc2);
+ LogFlowFunc(("%s: pSink=%s, cSinks=%RU8\n",
+ pMixer->pszName, pSink->pszName, pMixer->cSinks));
- return rc;
+ audioMixerDestroySink(pSink);
}
-/*********************************************************************************************************************************
- * Mixer Sink implementation.
- ********************************************************************************************************************************/
-
-/**
- * Adds an audio stream to a specific audio sink.
- *
- * @returns IPRT status code.
- * @param pSink Sink to add audio stream to.
- * @param pStream Stream to add.
- */
-int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
+void AudioMixerRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
- {
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
+ AssertPtrReturnVoid(pSink);
+ if (!pStream)
+ return;
- return VERR_NO_MORE_HANDLES;
- }
+ Assert(pSink->cStreams);
+ RTListNodeRemove(&pStream->Node);
+ pSink->cStreams--;
- LogFlowFuncEnter();
+#ifdef DEBUG
+ const char *pszStream = pSink->enmDir == AUDMIXSINKDIR_INPUT
+ ? pStream->pIn->MixBuf.pszName : pStream->pOut->MixBuf.pszName;
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- /* Make sure only compatible streams are added. */
- if (pStream->enmDir == PDMAUDIODIR_IN)
- {
- if (DrvAudioHlpPCMPropsAreEqual(&pSink->PCMProps, &pStream->InOut.pIn->Props))
- {
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- /* Chain: Stream (Child) -> Sink (Child) -> Guest (Parent). */
- PPDMAUDIOMIXBUF pHstIn = &pStream->InOut.pIn->pHstStrmIn->MixBuf;
- PPDMAUDIOMIXBUF pGstIn = &pStream->InOut.pIn->MixBuf;
-
- /* Unlink any former parent from host input. */
- AudioMixBufUnlink(pHstIn);
-
- /* Link host input to this sink as a parent. */
- rc = AudioMixBufLinkTo(pHstIn, &pSink->MixBuf);
- AssertRC(rc);
-
- /* Unlink any former parent from this sink. */
- AudioMixBufUnlink(&pSink->MixBuf);
-
- /* Link guest input to this sink as a parent. */
- rc = AudioMixBufLinkTo(&pSink->MixBuf, pGstIn);
- AssertRC(rc);
-# ifdef DEBUG
- AudioMixBufDbgPrintChain(&pStream->InOut.pIn->MixBuf);
-# endif
-#endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */
- }
- else
- AssertFailedStmt(rc = VERR_WRONG_TYPE);
- }
- else if (pStream->enmDir == PDMAUDIODIR_OUT)
- {
- if (DrvAudioHlpPCMPropsAreEqual(&pSink->PCMProps, &pStream->InOut.pOut->Props))
- {
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- /* Chain: Guest (Child) -> Sink (Child) -> Stream (Parent). */
- rc = AudioMixBufLinkTo(&pStream->InOut.pOut->pHstStrmOut->MixBuf, &pSink->MixBuf);
-# ifdef DEBUG
- AudioMixBufDbgPrintChain(&pSink->MixBuf);
-# endif
-#endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */
- }
- else
- AssertFailedStmt(rc = VERR_WRONG_TYPE);
- }
- else
- AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
-#else
- rc = VINF_SUCCESS;
+ LogFlowFunc(("%s: pStream=%s, cStreams=%RU8\n",
+ pSink->pszName, pszStream ? pszStream : "<Unnamed>", pSink->cStreams));
#endif
- if (RT_SUCCESS(rc))
+ /* Decrease the reference count again. */
+ switch (pSink->enmDir)
{
- /** @todo Check if stream already is assigned to (another) sink. */
-
- /* If the sink is running, make sure that the added stream also is enabled. */
- if (pSink->fStatus & AUDMIXSINK_STS_RUNNING)
- rc = audioMixerStreamCtlInternal(pStream, PDMAUDIOSTREAMCMD_ENABLE, AUDMIXSTRMCTL_FLAG_NONE);
-
- if (RT_SUCCESS(rc))
+ case AUDMIXSINKDIR_INPUT:
{
- /* Apply the sink's combined volume to the stream. */
- rc = pStream->pConn->pfnStreamSetVolume(pStream->pConn, pStream->pStream, &pSink->VolumeCombined);
- AssertRC(rc);
+ Assert(pStream->pIn->State.cRefs);
+ pStream->pIn->State.cRefs--;
+ break;
}
- if (RT_SUCCESS(rc))
+ case AUDMIXSINKDIR_OUTPUT:
{
- /* Save pointer to sink the stream is attached to. */
- pStream->pSink = pSink;
-
- /* Append stream to sink's list. */
- RTListAppend(&pSink->lstStreams, &pStream->Node);
- pSink->cStreams++;
+ Assert(pStream->pOut->State.cRefs);
+ pStream->pOut->State.cRefs--;
+ break;
}
+
+ default:
+ AssertMsgFailed(("Not implemented\n"));
+ break;
}
- LogFlowFunc(("[%s]: cStreams=%RU8, rc=%Rrc\n", pSink->pszName, pSink->cStreams, rc));
+ audioMixerDestroyStream(pStream);
+}
+
+int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
+{
+ AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
+ /** @todo Perform a deep copy, if needed. */
+ pMixer->devFmt = *pCfg;
- return rc;
+ return VINF_SUCCESS;
}
-/**
- * Creates an audio mixer stream.
- *
- * @returns IPRT status code.
- * @param pSink Sink to use for creating the stream.
- * @param pConn Audio connector interface to use.
- * @param pCfg Audio stream configuration to use.
- * @param fFlags Stream creation flags. Currently unused, set to 0.
- * @param ppStream Pointer which receives the newly created audio stream.
- */
-int AudioMixerSinkCreateStream(PAUDMIXSINK pSink,
- PPDMIAUDIOCONNECTOR pConn, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream)
+static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster)
{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pConn, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- /** @todo Validate fFlags. */
- /* ppStream is optional. */
+ AssertPtrReturn(pSink, VERR_INVALID_POINTER);
+ AssertPtrReturn(pVolMaster, VERR_INVALID_POINTER);
- PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
- if (!pMixStream)
- return VERR_NO_MEMORY;
+ LogFlowFunc(("Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+ pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
+ LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+ pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
- pMixStream->pszName = RTStrDup(pCfg->szName);
- if (!pMixStream->pszName)
- {
- RTMemFree(pMixStream);
- return VERR_NO_MEMORY;
- }
+ /** @todo Very crude implementation for now -- needs more work! */
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return rc;
+ PDMAUDIOVOLUME volSink;
+ volSink.fMuted = pVolMaster->fMuted || pSink->Volume.fMuted;
+ volSink.uLeft = (pSink->Volume.uLeft * pVolMaster->uLeft) / UINT8_MAX;
+ volSink.uRight = (pSink->Volume.uRight * pVolMaster->uRight) / UINT8_MAX;
- LogFlowFunc(("[%s]: fFlags=0x%x (enmDir=%d, %s, %RU8 channels, %RU32Hz)\n",
- pSink->pszName, fFlags, pCfg->enmDir, DrvAudioHlpAudFmtToStr(pCfg->enmFormat), pCfg->cChannels, pCfg->uHz));
+ LogFlowFunc(("\t-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+ volSink.fMuted, volSink.uLeft, volSink.uRight));
- /*
- * Initialize the host-side configuration for the stream to be created.
- * Always use the sink's PCM audio format as the host side when creating a stream for it.
- */
- PDMAUDIOSTREAMCFG CfgHost;
- rc = DrvAudioHlpPCMPropsToStreamCfg(&pSink->PCMProps, &CfgHost);
- AssertRCReturn(rc, rc);
+ bool fOut = pSink->enmDir == AUDMIXSINKDIR_OUTPUT;
- /* Apply the sink's direction for the configuration to use to
- * create the stream. */
- if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
- {
- CfgHost.DestSource.Source = pCfg->DestSource.Source;
- CfgHost.enmDir = PDMAUDIODIR_IN;
- }
- else
+ /* Propagate new sink volume to all streams in the sink. */
+ PAUDMIXSTREAM pStream;
+ RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
{
- CfgHost.DestSource.Dest = pCfg->DestSource.Dest;
- CfgHost.enmDir = PDMAUDIODIR_OUT;
+ if (fOut)
+ AudioMixBufSetVolume(&pStream->pOut->MixBuf, &volSink);
+ else
+ AudioMixBufSetVolume(&pStream->pIn->MixBuf, &volSink);
}
- RTStrPrintf(CfgHost.szName, sizeof(CfgHost.szName), "%s", pCfg->szName);
-
- rc = RTCritSectInit(&pMixStream->CritSect);
- if (RT_SUCCESS(rc))
- {
- PPDMAUDIOSTREAM pStream;
- rc = pConn->pfnStreamCreate(pConn, &CfgHost, pCfg, &pStream);
- if (RT_SUCCESS(rc))
- {
- /* Save the audio stream pointer to this mixing stream. */
- pMixStream->pStream = pStream;
-
- /* Increase the stream's reference count to let others know
- * we're reyling on it to be around now. */
- pConn->pfnStreamRetain(pConn, pStream);
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- pMixStream->fFlags = fFlags;
- pMixStream->pConn = pConn;
-
- if (ppStream)
- *ppStream = pMixStream;
- }
- else if (pMixStream)
- {
- int rc2 = RTCritSectDelete(&pMixStream->CritSect);
- AssertRC(rc2);
-
- if (pMixStream->pszName)
- {
- RTStrFree(pMixStream->pszName);
- pMixStream->pszName = NULL;
- }
-
- RTMemFree(pMixStream);
- pMixStream = NULL;
- }
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return rc;
-}
-
-/**
- * Static helper function to translate a sink command
- * to a PDM audio stream command.
- *
- * @returns PDM audio stream command, or PDMAUDIOSTREAMCMD_UNKNOWN if not found.
- * @param enmCmd Mixer sink command to translate.
- */
-static PDMAUDIOSTREAMCMD audioMixerSinkToStreamCmd(AUDMIXSINKCMD enmCmd)
-{
- switch (enmCmd)
- {
- case AUDMIXSINKCMD_ENABLE: return PDMAUDIOSTREAMCMD_ENABLE;
- case AUDMIXSINKCMD_DISABLE: return PDMAUDIOSTREAMCMD_DISABLE;
- case AUDMIXSINKCMD_PAUSE: return PDMAUDIOSTREAMCMD_PAUSE;
- case AUDMIXSINKCMD_RESUME: return PDMAUDIOSTREAMCMD_RESUME;
- default: break;
- }
-
- AssertMsgFailed(("Unsupported sink command %d\n", enmCmd));
- return PDMAUDIOSTREAMCMD_UNKNOWN;
-}
-
-/**
- * Controls a mixer sink.
- *
- * @returns IPRT status code.
- * @param pSink Mixer sink to control.
- * @param enmSinkCmd Sink command to set.
- */
-int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmSinkCmd)
-{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
-
- PDMAUDIOSTREAMCMD enmCmdStream = audioMixerSinkToStreamCmd(enmSinkCmd);
- if (enmCmdStream == PDMAUDIOSTREAMCMD_UNKNOWN)
- return VERR_NOT_SUPPORTED;
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- PAUDMIXSTREAM pStream;
- RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
- {
- int rc2 = audioMixerStreamCtlInternal(pStream, enmCmdStream, AUDMIXSTRMCTL_FLAG_NONE);
- if (RT_SUCCESS(rc))
- rc = rc2;
- /* Keep going. Flag? */
- }
-
- if (enmSinkCmd == AUDMIXSINKCMD_ENABLE)
- {
- pSink->fStatus |= AUDMIXSINK_STS_RUNNING;
- }
- else if (enmSinkCmd == AUDMIXSINKCMD_DISABLE)
- {
- /* Set the sink in a pending disable state first.
- * The final status (disabled) will be set in the sink's iteration. */
- pSink->fStatus |= AUDMIXSINK_STS_PENDING_DISABLE;
- }
-
- LogFlowFunc(("[%s]: enmCmd=%d, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, enmSinkCmd, pSink->fStatus, rc));
-
- /* Not running anymore? Reset. */
- if (!(pSink->fStatus & AUDMIXSINK_STS_RUNNING))
- audioMixerSinkReset(pSink);
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return rc;
-}
-
-/**
- * Destroys a mixer sink and removes it from the attached mixer (if any).
- *
- * @param pSink Mixer sink to destroy.
- */
-void AudioMixerSinkDestroy(PAUDMIXSINK pSink)
-{
- if (!pSink)
- return;
-
- int rc2 = RTCritSectEnter(&pSink->CritSect);
- AssertRC(rc2);
-
- if (pSink->pParent)
- {
- /* Save sink pointer, as after audioMixerRemoveSinkInternal() the
- * pointer will be gone from the stream. */
- PAUDIOMIXER pMixer = pSink->pParent;
-
- audioMixerRemoveSinkInternal(pMixer, pSink);
-
- Assert(pMixer->cSinks);
- pMixer->cSinks--;
- }
-
- rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- audioMixerSinkDestroyInternal(pSink);
-}
-
-/**
- * Destroys a mixer sink.
- *
- * @param pSink Mixer sink to destroy.
- */
-static void audioMixerSinkDestroyInternal(PAUDMIXSINK pSink)
-{
- AssertPtrReturnVoid(pSink);
-
- LogFunc(("%s\n", pSink->pszName));
-
- PAUDMIXSTREAM pStream, pStreamNext;
- RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
- {
- /* Save a pointer to the stream to remove, as pStream
- * will not be valid anymore after calling audioMixerSinkRemoveStreamInternal(). */
- PAUDMIXSTREAM pStreamToRemove = pStream;
-
- audioMixerSinkRemoveStreamInternal(pSink, pStreamToRemove);
- audioMixerStreamDestroyInternal(pStreamToRemove);
- }
-
- if (pSink->pszName)
- {
- RTStrFree(pSink->pszName);
- pSink->pszName = NULL;
- }
-
- RTMemFree(pSink);
- pSink = NULL;
-}
-
-/**
- * Returns the amount of bytes ready to be read from a sink since the last call
- * to AudioMixerSinkUpdate().
- *
- * @returns Amount of bytes ready to be read from the sink.
- * @param pSink Sink to return number of available samples for.
- */
-uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink)
-{
- AssertPtrReturn(pSink, 0);
-
- AssertMsg(pSink->enmDir == AUDMIXSINKDIR_INPUT, ("Can't read from a non-input sink\n"));
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return 0;
-
- uint32_t cbReadable;
-
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-# error "Implement me!"
-#else
- cbReadable = pSink->In.cbReadable;
-#endif
-
- Log3Func(("[%s]: cbReadable=%RU32\n", pSink->pszName, cbReadable));
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return cbReadable;
-}
-
-/**
- * Returns the amount of bytes ready to be written to a sink since the last call
- * to AudioMixerSinkUpdate().
- *
- * @returns Amount of bytes ready to be written to the sink.
- * @param pSink Sink to return number of available samples for.
- */
-uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink)
-{
- AssertPtrReturn(pSink, 0);
-
- AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT, ("Can't write to a non-output sink\n"));
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return 0;
-
- uint32_t cbWritable;
-
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-# error "Implement me!"
-#else
- cbWritable = pSink->Out.cbWritable;
-#endif
-
- Log3Func(("[%s]: cbWritable=%RU32\n", pSink->pszName, cbWritable));
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return cbWritable;
-}
-
-/**
- * Returns the sink's mixing direction.
- *
- * @returns Mixing direction.
- * @param pSink Sink to return direction for.
- */
-AUDMIXSINKDIR AudioMixerSinkGetDir(PAUDMIXSINK pSink)
-{
- AssertPtrReturn(pSink, AUDMIXSINKDIR_UNKNOWN);
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return AUDMIXSINKDIR_UNKNOWN;
-
- AUDMIXSINKDIR enmDir = pSink->enmDir;
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return enmDir;
-}
-
-/**
- * Returns a specific mixer stream from a sink, based on its index.
- *
- * @returns Mixer stream if found, or NULL if not found.
- * @param pSink Sink to retrieve mixer stream from.
- * @param uIndex Index of the mixer stream to return.
- */
-PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex)
-{
- AssertPtrReturn(pSink, NULL);
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return NULL;
-
- AssertMsgReturn(uIndex < pSink->cStreams,
- ("Index %RU8 exceeds stream count (%RU8)", uIndex, pSink->cStreams), NULL);
-
- /* Slow lookup, d'oh. */
- PAUDMIXSTREAM pStream = RTListGetFirst(&pSink->lstStreams, AUDMIXSTREAM, Node);
- while (uIndex)
- {
- pStream = RTListGetNext(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node);
- uIndex--;
- }
-
- /** @todo Do we need to raise the stream's reference count here? */
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- AssertPtr(pStream);
- return pStream;
-}
-
-/**
- * Returns the current status of a mixer sink.
- *
- * @returns The sink's current status.
- * @param pSink Mixer sink to return status for.
- */
-AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink)
-{
- if (!pSink)
- return AUDMIXSINK_STS_NONE;
-
- int rc2 = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc2))
- return AUDMIXSINK_STS_NONE;
-
- LogFlowFunc(("[%s]: fStatus=0x%x\n", pSink->pszName, pSink->fStatus));
-
- /* If the dirty flag is set, there is unprocessed data in the sink. */
- AUDMIXSINKSTS stsSink = pSink->fStatus;
-
- rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return stsSink;
-}
-
-/**
- * Returns the number of attached mixer streams to a mixer sink.
- *
- * @returns The number of attached mixer streams.
- * @param pSink Mixer sink to return number for.
- */
-uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink)
-{
- if (!pSink)
- return 0;
-
- int rc2 = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc2))
- return 0;
-
- uint8_t cStreams = pSink->cStreams;
-
- rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return cStreams;
-}
-
-/**
- * Reads audio data from a mixer sink.
- *
- * @returns IPRT status code.
- * @param pSink Mixer sink to read data from.
- * @param enmOp Mixer operation to use for reading the data.
- * @param pvBuf Buffer where to store the read data.
- * @param cbBuf Buffer size (in bytes) where to store the data.
- * @param pcbRead Number of bytes read. Optional.
- */
-int AudioMixerSinkRead(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
-{
- RT_NOREF(enmOp);
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
- /* pcbRead is optional. */
-
- /** @todo Handle mixing operation enmOp! */
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- AssertMsg(pSink->enmDir == AUDMIXSINKDIR_INPUT,
- ("Can't read from a sink which is not an input sink\n"));
-
-#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
- uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf);
- if (!pvMixBuf)
- {
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return VERR_NO_MEMORY;
- }
-#endif
-
- uint32_t cbRead = 0;
-
- /* Flag indicating whether this sink is in a 'clean' state,
- * e.g. there is no more data to read from. */
- bool fClean = true;
-
- PAUDMIXSTREAM pMixStream;
- RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
- {
- if (!(pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream) & PDMAUDIOSTRMSTS_FLAG_ENABLED))
- {
- Log3Func(("[%s] Stream '%s' disabled, skipping ...\n", pSink->pszName, pMixStream->pszName));
- continue;
- }
-
- uint32_t cbTotalRead = 0;
- uint32_t cbToRead = cbBuf;
-
- int rc2 = VINF_SUCCESS;
-
- while (cbToRead)
- {
- uint32_t cbReadStrm;
- AssertPtr(pMixStream->pConn);
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-# error "Implement me!"
-#else
- rc2 = pMixStream->pConn->pfnStreamRead(pMixStream->pConn, pMixStream->pStream,
- (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbReadStrm);
-#endif
- if (RT_FAILURE(rc2))
- Log3Func(("[%s] Failed reading from stream '%s': %Rrc\n", pSink->pszName, pMixStream->pszName, rc2));
-
- if ( RT_FAILURE(rc2)
- || !cbReadStrm)
- break;
-
- /** @todo Right now we only handle one stream (the last one added in fact). */
-
- AssertBreakStmt(cbReadStrm <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
- cbToRead -= cbReadStrm;
- cbTotalRead += cbReadStrm;
- }
-
- if (RT_FAILURE(rc2))
- continue;
-
- cbRead = RT_MAX(cbRead, cbTotalRead);
-
- PDMAUDIOSTRMSTS strmSts = pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream);
-
- /* Still some data available? Then sink is not clean (yet). */
- if (strmSts & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE)
- fClean = false;
- }
-
- if (RT_SUCCESS(rc))
- {
- if (fClean)
- pSink->fStatus &= ~AUDMIXSINK_STS_DIRTY;
-
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-# error "Implement me!"
-#else
- if (cbRead)
- memcpy(pvBuf, pvMixBuf, cbRead);
-#endif
- if (pcbRead)
- *pcbRead = cbRead;
- }
-
-#ifndef VBOX_AUDIO_MIXER_WITH_MIXBUF
- RTMemFree(pvMixBuf);
-#endif
-
- Log3Func(("[%s] cbRead=%RU32, fClean=%RTbool, fStatus=0x%x, rc=%Rrc\n", pSink->pszName, cbRead, fClean, pSink->fStatus, rc));
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return rc;
-}
-
-/**
- * Removes a mixer stream from a mixer sink, internal version.
- *
- * @returns IPRT status code.
- * @param pSink Sink to remove mixer stream from.
- * @param pStream Stream to remove.
- */
-static int audioMixerSinkRemoveStreamInternal(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
-{
- AssertPtrReturn(pSink, VERR_INVALID_PARAMETER);
- if ( !pStream
- || !pStream->pSink) /* Not part of a sink anymore? */
- {
- return VERR_NOT_FOUND;
- }
-
- AssertMsgReturn(pStream->pSink == pSink, ("Stream '%s' is not part of sink '%s'\n",
- pStream->pszName, pSink->pszName), VERR_NOT_FOUND);
-
- LogFlowFunc(("[%s]: (Stream = %s), cStreams=%RU8\n",
- pSink->pszName, pStream->pStream->szName, pSink->cStreams));
-
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- /* Unlink mixing buffer. */
- AudioMixBufUnlink(&pStream->pStream->MixBuf);
-#endif
-
- /* Remove stream from sink. */
- RTListNodeRemove(&pStream->Node);
-
- /* Set sink to NULL so that we know we're not part of any sink anymore. */
- pStream->pSink = NULL;
-
return VINF_SUCCESS;
}
-/**
- * Removes a mixer stream from a mixer sink.
- *
- * @param pSink Sink to remove mixer stream from.
- * @param pStream Stream to remove.
- */
-void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
-{
- int rc2 = RTCritSectEnter(&pSink->CritSect);
- AssertRC(rc2);
-
- rc2 = audioMixerSinkRemoveStreamInternal(pSink, pStream);
- if (RT_SUCCESS(rc2))
- {
- Assert(pSink->cStreams);
- pSink->cStreams--;
- }
-
- rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-}
-
-/**
- * Removes all attached streams from a given sink.
- *
- * @param pSink Sink to remove attached streams from.
- */
-static void audioMixerSinkRemoveAllStreamsInternal(PAUDMIXSINK pSink)
-{
- if (!pSink)
- return;
-
- LogFunc(("%s\n", pSink->pszName));
-
- PAUDMIXSTREAM pStream, pStreamNext;
- RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
- audioMixerSinkRemoveStreamInternal(pSink, pStream);
-}
-
-/**
- * Resets the sink's state.
- *
- * @param pSink Sink to reset.
- */
-static void audioMixerSinkReset(PAUDMIXSINK pSink)
-{
- if (!pSink)
- return;
-
- LogFunc(("[%s]\n", pSink->pszName));
-
- if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
- {
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- AudioMixBufReset(&pSink->MixBuf);
-#else
- pSink->In.cbReadable = 0;
-#endif
- }
- else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
- {
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- AudioMixBufReset(&pSink->MixBuf);
-#else
- pSink->Out.cbWritable = 0;
-#endif
- }
-
- /* Update last updated timestamp. */
- pSink->tsLastUpdatedMS = RTTimeMilliTS();
-
- /* Reset status. */
- pSink->fStatus = AUDMIXSINK_STS_NONE;
-}
-
-/**
- * Removes all attached streams from a given sink.
- *
- * @param pSink Sink to remove attached streams from.
- */
-void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink)
-{
- if (!pSink)
- return;
-
- int rc2 = RTCritSectEnter(&pSink->CritSect);
- AssertRC(rc2);
-
- audioMixerSinkRemoveAllStreamsInternal(pSink);
-
- pSink->cStreams = 0;
-
- rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-}
-
-/**
- * Sets the audio format of a mixer sink.
- *
- * @returns IPRT status code.
- * @param pSink Sink to set audio format for.
- * @param pPCMProps Audio format (PCM properties) to set.
- */
-int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMAUDIOPCMPROPS pPCMProps)
+/** Set the master volume of the mixer. */
+int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol)
{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER);
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- if (DrvAudioHlpPCMPropsAreEqual(&pSink->PCMProps, pPCMProps)) /* Bail out early if PCM properties are equal. */
- {
- rc = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc);
-
- return rc;
- }
-
- if (pSink->PCMProps.uHz)
- LogFlowFunc(("[%s]: Old format: %RU8 bit, %RU8 channels, %RU32Hz\n",
- pSink->pszName, pSink->PCMProps.cBits, pSink->PCMProps.cChannels, pSink->PCMProps.uHz));
-
- memcpy(&pSink->PCMProps, pPCMProps, sizeof(PDMAUDIOPCMPROPS));
-
- LogFlowFunc(("[%s]: New format %RU8 bit, %RU8 channels, %RU32Hz\n",
- pSink->pszName, pSink->PCMProps.cBits, pSink->PCMProps.cChannels, pSink->PCMProps.uHz));
+ AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
+ AssertPtrReturn(pVol, VERR_INVALID_POINTER);
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- /* Also update the sink's mixing buffer format. */
- AudioMixBufDestroy(&pSink->MixBuf);
- rc = AudioMixBufInit(&pSink->MixBuf, pSink->pszName, pPCMProps, _4K /** @todo Make configurable? */);
- if (RT_SUCCESS(rc))
- {
- PAUDMIXSTREAM pStream;
- RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
- {
- /** @todo Invalidate mix buffers! */
- }
- }
-#endif /* VBOX_AUDIO_MIXER_WITH_MIXBUF */
+ pMixer->VolMaster = *pVol;
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
+ LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
+ pMixer->pszName, pVol->uLeft, pVol->uRight,
+ pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
- LogFlowFuncLeaveRC(rc);
- return rc;
+ AudioMixerInvalidate(pMixer);
+ return VINF_SUCCESS;
}
-/**
- * Set the volume of an individual sink.
- *
- * @returns IPRT status code.
- * @param pSink Sink to set volume for.
- * @param pVol Volume to set.
- */
-int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol)
+/** Set the volume of an individual sink. */
+int AudioMixerSetSinkVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol)
{
AssertPtrReturn(pSink, VERR_INVALID_POINTER);
AssertPtrReturn(pVol, VERR_INVALID_POINTER);
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- memcpy(&pSink->Volume, pVol, sizeof(PDMAUDIOVOLUME));
-
- LogFlowFunc(("[%s]: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
- pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
-
AssertPtr(pSink->pParent);
- rc = audioMixerSinkUpdateVolume(pSink, &pSink->pParent->VolMaster);
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
+ LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
- return rc;
-}
+ pSink->Volume = *pVol;
-/**
- * Updates a mixer sink, internal version.
- *
- * @returns IPRT status code.
- * @param pSink Mixer sink to update.
- */
-static int audioMixerSinkUpdateInternal(PAUDMIXSINK pSink)
-{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
-
- int rc = VINF_SUCCESS;
-
- Log3Func(("[%s] fStatus=0x%x\n", pSink->pszName, pSink->fStatus));
-
- /* Sink disabled? Take a shortcut. */
- if (!(pSink->fStatus & AUDMIXSINK_STS_RUNNING))
- return rc;
-
- /* Number of detected disabled streams of this sink. */
- uint8_t cStreamsDisabled = 0;
-
- /* Get the time delta and calculate the bytes that need to be processed. */
- uint64_t tsDeltaMS = RTTimeMilliTS() - pSink->tsLastUpdatedMS;
- uint32_t cbDelta = (pSink->PCMProps.cbBitrate / 1000 /* s to ms */) * tsDeltaMS;
-
- Log3Func(("[%s] Bitrate is %RU32 bytes/s -> %RU64ms / %RU32 bytes elapsed\n",
- pSink->pszName, pSink->PCMProps.cbBitrate, tsDeltaMS, cbDelta));
-
- if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
- {
- pSink->In.cbReadable = cbDelta;
- }
- else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
- {
- pSink->Out.cbWritable = cbDelta;
- }
-
- uint8_t uCurLUN = 0;
-
- PAUDMIXSTREAM pMixStream, pMixStreamNext;
- RTListForEachSafe(&pSink->lstStreams, pMixStream, pMixStreamNext, AUDMIXSTREAM, Node)
- {
- PPDMAUDIOSTREAM pStream = pMixStream->pStream;
- AssertPtr(pStream);
-
- PPDMIAUDIOCONNECTOR pConn = pMixStream->pConn;
- AssertPtr(pConn);
-
- uint32_t cProc = 0;
-
- int rc2 = pConn->pfnStreamIterate(pConn, pStream);
- if (RT_SUCCESS(rc2))
- {
- if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
- {
- rc = pConn->pfnStreamCapture(pConn, pStream, &cProc);
- if (RT_FAILURE(rc2))
- {
- LogFlowFunc(("%s: Failed capturing stream '%s', rc=%Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
- if (RT_SUCCESS(rc))
- rc = rc2;
- continue;
- }
-
- if (cProc)
- pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
- }
- else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
- {
- rc2 = pConn->pfnStreamPlay(pConn, pStream, &cProc);
- if (RT_FAILURE(rc2))
- {
- LogFlowFunc(("%s: Failed playing stream '%s', rc=%Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
- if (RT_SUCCESS(rc))
- rc = rc2;
- continue;
- }
- }
- else
- {
- AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
- continue;
- }
-
- rc2 = pConn->pfnStreamIterate(pConn, pStream);
- if (RT_FAILURE(rc2))
- {
- LogFlowFunc(("%s: Failed re-iterating stream '%s', rc=%Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
- if (RT_SUCCESS(rc))
- rc = rc2;
- continue;
- }
-
- PDMAUDIOSTRMSTS strmSts = pConn->pfnStreamGetStatus(pConn, pMixStream->pStream);
-
- /* Is the stream not enabled and also is not in a pending disable state anymore? */
- if ( !(strmSts & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- && !(strmSts & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE))
- {
- cStreamsDisabled++;
- }
-
- if (pSink->enmDir == AUDMIXSINKDIR_INPUT)
- {
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-# error "Implement me!"
-#else
- if (uCurLUN == 0)
- {
- pSink->In.cbReadable = pConn->pfnStreamGetReadable(pConn, pMixStream->pStream);
- Log3Func(("\t%s: cbReadable=%RU32\n", pMixStream->pStream->szName, pSink->In.cbReadable));
- uCurLUN++;
- }
-#endif
- }
- else if (pSink->enmDir == AUDMIXSINKDIR_OUTPUT)
- {
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
-# error "Implement me!"
-#else
- if (uCurLUN == 0)
- {
- pSink->Out.cbWritable = pConn->pfnStreamGetWritable(pConn, pMixStream->pStream);
- Log3Func(("\t%s: cbWritable=%RU32\n", pMixStream->pStream->szName, pSink->Out.cbWritable));
- uCurLUN++;
- }
-#endif
- }
- }
-
- Log3Func(("\t%s: cProc=%RU32, rc2=%Rrc\n", pStream->szName, cProc, rc2));
- }
-
- Log3Func(("[%s] fPendingDisable=%RTbool, %RU8/%RU8 streams disabled\n",
- RT_BOOL(pSink->fStatus & AUDMIXSINK_STS_PENDING_DISABLE), pSink->pszName, cStreamsDisabled, pSink->cStreams));
-
- /* Update last updated timestamp. */
- pSink->tsLastUpdatedMS = RTTimeMilliTS();
-
- /* All streams disabled and the sink is in pending disable mode? */
- if ( cStreamsDisabled == pSink->cStreams
- && (pSink->fStatus & AUDMIXSINK_STS_PENDING_DISABLE))
- {
- audioMixerSinkReset(pSink);
- }
-
- Log3Func(("[%s] cbReadable=%RU32, cbWritable=%RU32, rc=%Rrc\n",
- pSink->pszName, pSink->In.cbReadable, pSink->Out.cbWritable, rc));
-
- return rc;
-}
-
-/**
- * Updates (invalidates) a mixer sink.
- *
- * @returns IPRT status code.
- * @param pSink Mixer sink to update.
- */
-int AudioMixerSinkUpdate(PAUDMIXSINK pSink)
-{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- /*
- * Note: Hz elapsed = cTicksElapsed / cTimerTicks
- * Bytes / second = Sample rate (Hz) * Audio channels * Bytes per sample
- */
-// uint32_t cSamples = (int)((pSink->PCMProps.cChannels * cTicksElapsed * pSink->PCMProps.uHz + cTimerTicks) / cTimerTicks / pSink->PCMProps.cChannels);
-
-// LogFlowFunc(("[%s]: cTimerTicks=%RU64, cTicksElapsed=%RU64\n", pSink->pszName, cTimerTicks, cTicksElapsed));
-// LogFlowFunc(("\t%zuHz elapsed, %RU32 samples (%RU32 bytes)\n", cTicksElapsed / cTimerTicks, cSamples, cSamples << 1));
-
- rc = audioMixerSinkUpdateInternal(pSink);
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return rc;
+ return audioMixerUpdateSinkVolume(pSink, &pSink->pParent->VolMaster);
}
-/**
- * Updates the (master) volume of a mixer sink.
- *
- * @returns IPRT status code.
- * @param pSink Mixer sink to update volume for.
- * @param pVolMaster Master volume to set.
- */
-static int audioMixerSinkUpdateVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster)
-{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pVolMaster, VERR_INVALID_POINTER);
-
- LogFlowFunc(("[%s] Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
- pSink->pszName, pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
- LogFlowFunc(("[%s] fMuted=%RTbool, lVol=%RU32, rVol=%RU32 ",
- pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
-
- /** @todo Very crude implementation for now -- needs more work! */
-
- pSink->VolumeCombined.fMuted = pVolMaster->fMuted || pSink->Volume.fMuted;
-
- pSink->VolumeCombined.uLeft = ( (pSink->Volume.uLeft ? pSink->Volume.uLeft : 1)
- * (pVolMaster->uLeft ? pVolMaster->uLeft : 1)) / PDMAUDIO_VOLUME_MAX;
-
- pSink->VolumeCombined.uRight = ( (pSink->Volume.uRight ? pSink->Volume.uRight : 1)
- * (pVolMaster->uRight ? pVolMaster->uRight : 1)) / PDMAUDIO_VOLUME_MAX;
-
- LogFlow(("-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
- pSink->VolumeCombined.fMuted, pSink->VolumeCombined.uLeft, pSink->VolumeCombined.uRight));
-
- /* Propagate new sink volume to all streams in the sink. */
- PAUDMIXSTREAM pMixStream;
- RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
- {
- int rc2 = pMixStream->pConn->pfnStreamSetVolume(pMixStream->pConn, pMixStream->pStream, &pSink->VolumeCombined);
- AssertRC(rc2);
- }
-
- return VINF_SUCCESS;
-}
-
-/**
- * Writes data to a mixer sink.
- *
- * @returns IPRT status code.
- * @param pSink Sink to write data to.
- * @param enmOp Mixer operation to use when writing data to the sink.
- * @param pvBuf Buffer containing the audio data to write.
- * @param cbBuf Size (in bytes) of the buffer containing the audio data.
- * @param pcbWritten Number of bytes written. Optional.
- */
-int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
-{
- RT_NOREF(enmOp);
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- /* pcbWritten is optional. */
-
- if (!pvBuf || !cbBuf)
- {
- if (pcbWritten)
- *pcbWritten = 0;
- return VINF_SUCCESS;
- }
-
- int rc = RTCritSectEnter(&pSink->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- AssertMsg(pSink->enmDir == AUDMIXSINKDIR_OUTPUT,
- ("Can't write to a sink which is not an output sink\n"));
-
- Log3Func(("[%s] enmOp=%d, cbBuf=%RU32\n", pSink->pszName, enmOp, cbBuf));
-
- uint32_t cbProcessed;
-
- PAUDMIXSTREAM pMixStream;
- RTListForEach(&pSink->lstStreams, pMixStream, AUDMIXSTREAM, Node)
- {
- if (!(pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream) & PDMAUDIOSTRMSTS_FLAG_ENABLED))
- {
- Log3Func(("\t%s: Stream '%s' disabled, skipping ...\n", pMixStream->pszName, pMixStream->pStream->szName));
- continue;
- }
-
- int rc2 = pMixStream->pConn->pfnStreamWrite(pMixStream->pConn, pMixStream->pStream, pvBuf, cbBuf, &cbProcessed);
- if (RT_FAILURE(rc2))
- LogFlowFunc(("[%s] Failed writing to stream '%s': %Rrc\n", pSink->pszName, pMixStream->pStream->szName, rc2));
-
- if (cbProcessed < cbBuf)
- {
- Log3Func(("[%s] Only written %RU32/%RU32 bytes for stream '%s'\n",
- pSink->pszName, cbProcessed, cbBuf, pMixStream->pStream->szName));
- }
- }
-
- if (cbBuf)
- {
- /* Set dirty bit. */
- pSink->fStatus |= AUDMIXSINK_STS_DIRTY;
- }
-
- if (pcbWritten)
- *pcbWritten = cbBuf; /* Always report back a complete write for now. */
-
- int rc2 = RTCritSectLeave(&pSink->CritSect);
- AssertRC(rc2);
-
- return rc;
-}
-
-/*********************************************************************************************************************************
- * Mixer Stream implementation.
- ********************************************************************************************************************************/
-
-/**
- * Controls a mixer stream, internal version.
- *
- * @returns IPRT status code.
- * @param pMixStream Mixer stream to control.
- * @param enmCmd Mixer stream command to use.
- * @param fCtl Additional control flags. Pass 0.
- */
-int audioMixerStreamCtlInternal(PAUDMIXSTREAM pMixStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl)
-{
- AssertPtr(pMixStream->pConn);
- AssertPtr(pMixStream->pStream);
-
- RT_NOREF(fCtl);
-
- int rc = pMixStream->pConn->pfnStreamControl(pMixStream->pConn, pMixStream->pStream, enmCmd);
-
- LogFlowFunc(("[%s] enmCmd=%ld, rc=%Rrc\n", pMixStream->pszName, enmCmd, rc));
-
- return rc;
-}
-
-/**
- * Controls a mixer stream.
- *
- * @returns IPRT status code.
- * @param pMixStream Mixer stream to control.
- * @param enmCmd Mixer stream command to use.
- * @param fCtl Additional control flags. Pass 0.
- */
-int AudioMixerStreamCtl(PAUDMIXSTREAM pMixStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl)
-{
- RT_NOREF(fCtl);
- AssertPtrReturn(pMixStream, VERR_INVALID_POINTER);
- /** @todo Validate fCtl. */
-
- int rc = RTCritSectEnter(&pMixStream->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- rc = audioMixerStreamCtlInternal(pMixStream, enmCmd, fCtl);
-
- int rc2 = RTCritSectLeave(&pMixStream->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- return rc;
-}
-
-/**
- * Destroys a mixer stream, internal version.
- *
- * @param pMixStream Mixer stream to destroy.
- */
-static void audioMixerStreamDestroyInternal(PAUDMIXSTREAM pMixStream)
-{
- AssertPtrReturnVoid(pMixStream);
-
- LogFunc(("%s\n", pMixStream->pszName));
-
- if (pMixStream->pConn) /* Stream has a connector interface present? */
- {
- if (pMixStream->pStream)
- {
- pMixStream->pConn->pfnStreamRelease(pMixStream->pConn, pMixStream->pStream);
- pMixStream->pConn->pfnStreamDestroy(pMixStream->pConn, pMixStream->pStream);
-
- pMixStream->pStream = NULL;
- }
-
- pMixStream->pConn = NULL;
- }
-
- if (pMixStream->pszName)
- {
- RTStrFree(pMixStream->pszName);
- pMixStream->pszName = NULL;
- }
-
- int rc2 = RTCritSectDelete(&pMixStream->CritSect);
- AssertRC(rc2);
-
- RTMemFree(pMixStream);
- pMixStream = NULL;
-}
-
-/**
- * Destroys a mixer stream.
- *
- * @param pMixStream Mixer stream to destroy.
- */
-void AudioMixerStreamDestroy(PAUDMIXSTREAM pMixStream)
-{
- if (!pMixStream)
- return;
-
- int rc2 = RTCritSectEnter(&pMixStream->CritSect);
- AssertRC(rc2);
-
- LogFunc(("%s\n", pMixStream->pszName));
-
- if (pMixStream->pSink) /* Is the stream part of a sink? */
- {
- /* Save sink pointer, as after audioMixerSinkRemoveStreamInternal() the
- * pointer will be gone from the stream. */
- PAUDMIXSINK pSink = pMixStream->pSink;
-
- rc2 = audioMixerSinkRemoveStreamInternal(pSink, pMixStream);
- if (RT_SUCCESS(rc2))
- {
- Assert(pSink->cStreams);
- pSink->cStreams--;
- }
- }
- else
- rc2 = VINF_SUCCESS;
-
- int rc3 = RTCritSectLeave(&pMixStream->CritSect);
- AssertRC(rc3);
-
- if (RT_SUCCESS(rc2))
- {
- audioMixerStreamDestroyInternal(pMixStream);
- pMixStream = NULL;
- }
-
- LogFlowFunc(("Returning %Rrc\n", rc2));
-}
-
-/**
- * Returns whether a mixer stream currently is active (playing/recording) or not.
- *
- * @returns @true if playing/recording, @false if not.
- * @param pMixStream Mixer stream to return status for.
- */
-bool AudioMixerStreamIsActive(PAUDMIXSTREAM pMixStream)
-{
- int rc2 = RTCritSectEnter(&pMixStream->CritSect);
- if (RT_FAILURE(rc2))
- return false;
-
- AssertPtr(pMixStream->pConn);
- AssertPtr(pMixStream->pStream);
-
- bool fIsActive;
-
- if ( pMixStream->pConn
- && pMixStream->pStream
- && RT_BOOL(pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream) & PDMAUDIOSTRMSTS_FLAG_ENABLED))
- {
- fIsActive = true;
- }
- else
- fIsActive = false;
-
- rc2 = RTCritSectLeave(&pMixStream->CritSect);
- AssertRC(rc2);
-
- return fIsActive;
-}
-
-/**
- * Returns whether a mixer stream is valid (e.g. initialized and in a working state) or not.
- *
- * @returns @true if valid, @false if not.
- * @param pMixStream Mixer stream to return status for.
- */
-bool AudioMixerStreamIsValid(PAUDMIXSTREAM pMixStream)
+void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
- if (!pMixStream)
- return false;
-
- int rc2 = RTCritSectEnter(&pMixStream->CritSect);
- if (RT_FAILURE(rc2))
- return false;
+ RT_NOREF(pszArgs);
+ PAUDMIXSINK pSink;
+ unsigned iSink = 0;
- bool fIsValid;
+ pHlp->pfnPrintf(pHlp, "[Master] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", pMixer->pszName,
+ pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight, pMixer->VolMaster.fMuted);
- if ( pMixStream->pConn
- && pMixStream->pStream
- && RT_BOOL(pMixStream->pConn->pfnStreamGetStatus(pMixStream->pConn, pMixStream->pStream) & PDMAUDIOSTRMSTS_FLAG_INITIALIZED))
+ RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
{
- fIsValid = true;
+ pHlp->pfnPrintf(pHlp, "[Sink %u] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", iSink, pSink->pszName,
+ pSink->Volume.uLeft, pSink->Volume.uRight, pSink->Volume.fMuted);
+ ++iSink;
}
- else
- fIsValid = false;
-
- rc2 = RTCritSectLeave(&pMixStream->CritSect);
- AssertRC(rc2);
-
- return fIsValid;
}
-
diff --git a/src/VBox/Devices/Audio/AudioMixer.h b/src/VBox/Devices/Audio/AudioMixer.h
index 6b64609..e22f475 100644
--- a/src/VBox/Devices/Audio/AudioMixer.h
+++ b/src/VBox/Devices/Audio/AudioMixer.h
@@ -21,228 +21,93 @@
#define AUDIO_MIXER_H
#include <iprt/cdefs.h>
-#include <iprt/critsect.h>
-
#include <VBox/vmm/pdmaudioifs.h>
-/**
- * Structure for maintaining an audio mixer instance.
- */
typedef struct AUDIOMIXER
{
- /** The mixer's name. */
+ /** Mixer name. */
char *pszName;
- /** The mixer's critical section. */
- RTCRITSECT CritSect;
+ /** Format the mixer should convert/output
+ * data to so that the underlying device emulation
+ * can work with it. */
+ PDMAUDIOSTREAMCFG devFmt;
/** The master volume of this mixer. */
PDMAUDIOVOLUME VolMaster;
- /** List of audio mixer sinks. */
+ /* List of audio mixer sinks. */
RTLISTANCHOR lstSinks;
/** Number of used audio sinks. */
uint8_t cSinks;
} AUDIOMIXER, *PAUDIOMIXER;
-/** No flags specified. */
-#define AUDMIXSTREAM_FLAG_NONE 0
-
-/** Prototype needed for AUDMIXSTREAM struct definition. */
-typedef struct AUDMIXSINK *PAUDMIXSINK;
-
-/**
- * Structure for maintaining an audio mixer stream.
- */
typedef struct AUDMIXSTREAM
{
- /** List node. */
RTLISTNODE Node;
- /** Name of this stream. */
- char *pszName;
- /** The streams's critical section. */
- RTCRITSECT CritSect;
- /** Sink this stream is attached to. */
- PAUDMIXSINK pSink;
- /** Stream flags of type AUDMIXSTREAM_FLAG_. */
- uint32_t fFlags;
- /** Pointer to audio connector being used. */
PPDMIAUDIOCONNECTOR pConn;
- /** Pointer to PDM audio stream this mixer stream handles. */
- PPDMAUDIOSTREAM pStream;
+ union
+ {
+ PPDMAUDIOGSTSTRMIN pIn;
+ PPDMAUDIOGSTSTRMOUT pOut;
+ };
} AUDMIXSTREAM, *PAUDMIXSTREAM;
-/** Defines an audio sink's current status. */
-#define AUDMIXSINKSTS uint32_t
-
-/** No status specified. */
-#define AUDMIXSINK_STS_NONE 0
-/** The sink is active and running. */
-#define AUDMIXSINK_STS_RUNNING RT_BIT(0)
-/** The sink is in a pending disable state. */
-#define AUDMIXSINK_STS_PENDING_DISABLE RT_BIT(1)
-/** Dirty flag.
- * For output sinks this means that there is data in the
- * sink which has not been played yet.
- * For input sinks this means that there is data in the
- * sink which has been recorded but not transferred to the
- * destination yet. */
-#define AUDMIXSINK_STS_DIRTY RT_BIT(2)
-
-/**
- * Audio mixer sink direction.
- */
typedef enum AUDMIXSINKDIR
{
- /** Unknown direction. */
AUDMIXSINKDIR_UNKNOWN = 0,
- /** Input (capturing from a device). */
AUDMIXSINKDIR_INPUT,
- /** Output (playing to a device). */
AUDMIXSINKDIR_OUTPUT,
/** The usual 32-bit hack. */
AUDMIXSINKDIR_32BIT_HACK = 0x7fffffff
} AUDMIXSINKDIR;
-/**
- * Audio mixer sink command.
- */
-typedef enum AUDMIXSINKCMD
-{
- /** Unknown command, do not use. */
- AUDMIXSINKCMD_UNKNOWN = 0,
- /** Enables the sink. */
- AUDMIXSINKCMD_ENABLE,
- /** Disables the sink. */
- AUDMIXSINKCMD_DISABLE,
- /** Pauses the sink. */
- AUDMIXSINKCMD_PAUSE,
- /** Resumes the sink. */
- AUDMIXSINKCMD_RESUME,
- /** Hack to blow the type up to 32-bit. */
- AUDMIXSINKCMD_32BIT_HACK = 0x7fffffff
-} AUDMIXSINKCMD;
-
-/**
- * Structure for keeping audio input sink specifics.
- * Do not use directly. Instead, use AUDMIXSINK.
- */
-typedef struct AUDMIXSINKIN
-{
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- /** This sink's mixing buffer, acting as
- * a parent buffer for all streams this sink owns. */
- PDMAUDIOMIXBUF MixBuf;
-#else
- /** Number of bytes available to read from the sink. */
- uint32_t cbReadable;
-#endif
-} AUDMIXSINKIN;
-
-/**
- * Structure for keeping audio output sink specifics.
- * Do not use directly. Instead, use AUDMIXSINK.
- */
-typedef struct AUDMIXSINKOUT
-{
-#ifdef VBOX_AUDIO_MIXER_WITH_MIXBUF
- /** This sink's mixing buffer, acting as
- * a parent buffer for all streams this sink owns. */
- PDMAUDIOMIXBUF MixBuf;
-#else
- /** Number of bytes available to write to the sink. */
- uint32_t cbWritable;
-#endif
-} AUDMIXSINKOUT;
-
-/**
- * Structure for maintaining an audio mixer sink.
- */
typedef struct AUDMIXSINK
{
RTLISTNODE Node;
- /** Pointer to mixer object this sink is bound to. */
- PAUDIOMIXER pParent;
/** Name of this sink. */
char *pszName;
/** The sink direction, that is,
* if this sink handles input or output. */
AUDMIXSINKDIR enmDir;
- /** The sink's critical section. */
- RTCRITSECT CritSect;
- /** Union for input/output specifics. */
- union
- {
- AUDMIXSINKIN In;
- AUDMIXSINKOUT Out;
- };
- /** Sink status of type AUDMIXSINK_STS_XXX. */
- AUDMIXSINKSTS fStatus;
- /** The sink's PCM format. */
- PDMAUDIOPCMPROPS PCMProps;
+ /** Pointer to mixer object this sink is bound
+ * to. */
+ PAUDIOMIXER pParent;
/** Number of streams assigned. */
uint8_t cStreams;
- /** List of assigned streams.
- * Note: All streams have the same PCM properties, so the
- * mixer does not do any conversion. */
- /** @todo Use something faster -- vector maybe? */
+ /** List of assigned streams. */
RTLISTANCHOR lstStreams;
+ /** This sink's mixing buffer. */
+ PDMAUDIOMIXBUF MixBuf;
/** The volume of this sink. The volume always will
* be combined with the mixer's master volume. */
PDMAUDIOVOLUME Volume;
- /** The volume of this sink, combined with the last set master volume. */
- PDMAUDIOVOLUME VolumeCombined;
- /** Timestamp (in ms) since last update. */
- uint64_t tsLastUpdatedMS;
} AUDMIXSINK, *PAUDMIXSINK;
-/**
- * Audio mixer operation.
- */
typedef enum AUDMIXOP
{
- /** Invalid operation, do not use. */
- AUDMIXOP_INVALID = 0,
- /** Copy data from A to B, overwriting data in B. */
+ AUDMIXOP_NONE = 0,
AUDMIXOP_COPY,
- /** Blend data from A with (existing) data in B. */
AUDMIXOP_BLEND,
/** The usual 32-bit hack. */
AUDMIXOP_32BIT_HACK = 0x7fffffff
} AUDMIXOP;
-/** No flags specified. */
-#define AUDMIXSTRMCTL_FLAG_NONE 0
+int AudioMixerAddSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink);
+int AudioMixerAddStreamIn(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMIN pStream, uint32_t uFlags, PAUDMIXSTREAM *ppStream);
+int AudioMixerAddStreamOut(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMOUT pStream, uint32_t uFlags, PAUDMIXSTREAM *ppStream);
+int AudioMixerControlStream(AUDMIXSTREAM pHandle); /** @todo Implement me. */
int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer);
-int AudioMixerCreateSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink);
void AudioMixerDestroy(PAUDIOMIXER pMixer);
+int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg);
+uint32_t AudioMixerGetStreamCount(PAUDIOMIXER pMixer);
void AudioMixerInvalidate(PAUDIOMIXER pMixer);
+int AudioMixerProcessSinkIn(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed);
+int AudioMixerProcessSinkOut(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed);
void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink);
+void AudioMixerRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
+int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg);
int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol);
-#ifdef DEBUG
+int AudioMixerSetSinkVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs);
-#endif
-
-int AudioMixerSinkAddStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
-int AudioMixerSinkCreateStream(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOSTREAMCFG pCfg, uint32_t fFlags, PAUDMIXSTREAM *ppStream);
-int AudioMixerSinkCtl(PAUDMIXSINK pSink, AUDMIXSINKCMD enmCmd);
-void AudioMixerSinkDestroy(PAUDMIXSINK pSink);
-uint32_t AudioMixerSinkGetReadable(PAUDMIXSINK pSink);
-uint32_t AudioMixerSinkGetWritable(PAUDMIXSINK pSink);
-AUDMIXSINKDIR AudioMixerSinkGetDir(PAUDMIXSINK pSink);
-PAUDMIXSTREAM AudioMixerSinkGetStream(PAUDMIXSINK pSink, uint8_t uIndex);
-AUDMIXSINKSTS AudioMixerSinkGetStatus(PAUDMIXSINK pSink);
-uint8_t AudioMixerSinkGetStreamCount(PAUDMIXSINK pSink);
-int AudioMixerSinkRead(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
-void AudioMixerSinkRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
-void AudioMixerSinkRemoveAllStreams(PAUDMIXSINK pSink);
-int AudioMixerSinkSetFormat(PAUDMIXSINK pSink, PPDMAUDIOPCMPROPS pPCMProps);
-int AudioMixerSinkSetVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
-int AudioMixerSinkWrite(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten);
-int AudioMixerSinkUpdate(PAUDMIXSINK pSink);
-
-int AudioMixerStreamCtl(PAUDMIXSTREAM pStream, PDMAUDIOSTREAMCMD enmCmd, uint32_t fCtl);
-void AudioMixerStreamDestroy(PAUDMIXSTREAM pStream);
-bool AudioMixerStreamIsActive(PAUDMIXSTREAM pStream);
-bool AudioMixerStreamIsValid(PAUDMIXSTREAM pStream);
#endif /* AUDIO_MIXER_H */
diff --git a/src/VBox/Devices/Audio/DevHDA.cpp b/src/VBox/Devices/Audio/DevHDA.cpp
index 2f154c6..2c619d6 100644
--- a/src/VBox/Devices/Audio/DevHDA.cpp
+++ b/src/VBox/Devices/Audio/DevHDA.cpp
@@ -1,6 +1,6 @@
/* $Id: DevHDA.cpp $ */
/** @file
- * DevHDA - VBox HD Audio Controller.
+ * DevIchHda - VBox ICH Intel HD Audio Controller.
*
* Implemented against the specifications found in "High Definition Audio
* Specification", Revision 1.0a June 17, 2010, and "Intel I/O Controller
@@ -32,7 +32,6 @@
#include <iprt/assert.h>
#include <iprt/asm.h>
#include <iprt/asm-math.h>
-#include <iprt/file.h>
#include <iprt/list.h>
#ifdef IN_RING3
# include <iprt/mem.h>
@@ -45,8 +44,7 @@
#include "AudioMixBuffer.h"
#include "AudioMixer.h"
-#include "HDACodec.h"
-#include "DevHDACommon.h"
+#include "DevIchHdaCodec.h"
#include "DrvAudio.h"
@@ -57,18 +55,6 @@
#define VBOX_WITH_INTEL_HDA
#ifdef DEBUG_andy
-/*
- * HDA_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
- * to a file on the host. Be sure to adjust HDA_DEBUG_DUMP_PCM_DATA_PATH
- * to your needs before using this!
- */
-# define HDA_DEBUG_DUMP_PCM_DATA
-# ifdef RT_OS_WINDOWS
-# define HDA_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
-# else
-# define HDA_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
-# endif
-
/* Enables experimental support for separate mic-in handling.
Do not enable this yet for regular builds, as this needs more testing first! */
//# define VBOX_WITH_HDA_MIC_IN
@@ -98,39 +84,17 @@
* writes 1, hw sets it to 1 (after completion), sw reads 1, sw writes 0). */
#define BIRD_THINKS_CORBRP_IS_MOSTLY_RO
-/* Make sure that interleaving streams support is enabled if the 5.1 code is being used. */
-#if defined (VBOX_WITH_HDA_51_SURROUND) && !defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT)
-# define VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
-#endif
-
-/**
- * At the moment we support 4 input + 4 output streams max, which is 8 in total.
- * Bidirectional streams are currently *not* supported.
- *
- * Note: When changing any of those values, be prepared for some saved state
- * fixups / trouble!
- */
-#define HDA_MAX_SDI 4
-#define HDA_MAX_SDO 4
-#define HDA_MAX_STREAMS (HDA_MAX_SDI + HDA_MAX_SDO)
-AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
-
-/** Number of general registers. */
-#define HDA_NUM_GENERAL_REGS 34
-/** Number of total registers in the HDA's register map. */
-#define HDA_NUM_REGS (HDA_NUM_GENERAL_REGS + (HDA_MAX_STREAMS * 10 /* Each stream descriptor has 10 registers */))
-/** Total number of stream tags (channels). Index 0 is reserved / invalid. */
-#define HDA_MAX_TAGS 16
+#define HDA_NREGS 114
+#define HDA_NREGS_SAVED 112
/**
- * NB: Register values stored in memory (au32Regs[]) are indexed through
- * the HDA_RMX_xxx macros (also HDA_MEM_IND_NAME()). On the other hand, the
- * register descriptors in g_aHdaRegMap[] are indexed through the
- * HDA_REG_xxx macros (also HDA_REG_IND_NAME()).
+ * NB: Register values stored in memory (au32Regs[]) are indexed through
+ * the HDA_RMX_xxx macros (also HDA_MEM_IND_NAME()). On the other hand, the
+ * register descriptors in g_aHdaRegMap[] are indexed through the
+ * HDA_REG_xxx macros (also HDA_REG_IND_NAME()).
*
- * The au32Regs[] layout is kept unchanged for saved state
- * compatibility.
- */
+ * The au32Regs[] layout is kept unchanged for saved state
+ * compatibility. */
/* Registers */
#define HDA_REG_IND_NAME(x) HDA_REG_##x
@@ -149,14 +113,14 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
* oss (15:12) - number of output streams supported
* iss (11:8) - number of input streams supported
* bss (7:3) - number of bidirectional streams supported
- * bds (2:1) - number of serial data out (SDO) signals supported
+ * bds (2:1) - number of serial data out signals supported
* b64sup (0) - 64 bit addressing supported.
*/
#define HDA_MAKE_GCAP(oss, iss, bss, bds, b64sup) \
- ( (((oss) & 0xF) << 12) \
- | (((iss) & 0xF) << 8) \
- | (((bss) & 0x1F) << 3) \
- | (((bds) & 0x3) << 1) \
+ ( (((oss) & 0xF) << 12) \
+ | (((iss) & 0xF) << 8) \
+ | (((bss) & 0x1F) << 3) \
+ | (((bds) & 0x3) << 2) \
| ((b64sup) & 1))
#define HDA_REG_VMIN 1 /* 0x02 */
@@ -222,14 +186,14 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
#define HDA_INTSTS_S7_SHIFT 7
#define HDA_INTSTS_S_MASK(num) RT_BIT(HDA_REG_FIELD_SHIFT(S##num))
-#define HDA_REG_WALCLK 13 /* 0x30 */
+#define HDA_REG_WALCLK 13 /* 0x24 */
#define HDA_RMX_WALCLK /* Not defined! */
/* Note: The HDA specification defines a SSYNC register at offset 0x38. The
* ICH6/ICH9 datahseet defines SSYNC at offset 0x34. The Linux HDA driver matches
* the datasheet.
*/
-#define HDA_REG_SSYNC 14 /* 0x38 */
+#define HDA_REG_SSYNC 14 /* 0x34 */
#define HDA_RMX_SSYNC 12
#define HDA_REG_CORBLBASE 15 /* 0x40 */
@@ -325,16 +289,14 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
#define HDA_SD_NUM_FROM_REG(pThis, func, reg) ((reg - HDA_STREAM_REG_DEF(func, 0)) / 10)
-/** @todo Condense marcos! */
-
-#define HDA_REG_SD0CTL HDA_NUM_GENERAL_REGS /* 0x80 */
-#define HDA_REG_SD1CTL (HDA_STREAM_REG_DEF(CTL, 0) + 10) /* 0xA0 */
-#define HDA_REG_SD2CTL (HDA_STREAM_REG_DEF(CTL, 0) + 20) /* 0xC0 */
-#define HDA_REG_SD3CTL (HDA_STREAM_REG_DEF(CTL, 0) + 30) /* 0xE0 */
-#define HDA_REG_SD4CTL (HDA_STREAM_REG_DEF(CTL, 0) + 40) /* 0x100 */
-#define HDA_REG_SD5CTL (HDA_STREAM_REG_DEF(CTL, 0) + 50) /* 0x120 */
-#define HDA_REG_SD6CTL (HDA_STREAM_REG_DEF(CTL, 0) + 60) /* 0x140 */
-#define HDA_REG_SD7CTL (HDA_STREAM_REG_DEF(CTL, 0) + 70) /* 0x160 */
+#define HDA_REG_SD0CTL 34 /* 0x80 */
+#define HDA_REG_SD1CTL (HDA_STREAM_REG_DEF(CTL, 0) + 10) /* 0xA0 */
+#define HDA_REG_SD2CTL (HDA_STREAM_REG_DEF(CTL, 0) + 20) /* 0xC0 */
+#define HDA_REG_SD3CTL (HDA_STREAM_REG_DEF(CTL, 0) + 30) /* 0xE0 */
+#define HDA_REG_SD4CTL (HDA_STREAM_REG_DEF(CTL, 0) + 40) /* 0x100 */
+#define HDA_REG_SD5CTL (HDA_STREAM_REG_DEF(CTL, 0) + 50) /* 0x120 */
+#define HDA_REG_SD6CTL (HDA_STREAM_REG_DEF(CTL, 0) + 60) /* 0x140 */
+#define HDA_REG_SD7CTL (HDA_STREAM_REG_DEF(CTL, 0) + 70) /* 0x160 */
#define HDA_RMX_SD0CTL 32
#define HDA_RMX_SD1CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 10)
#define HDA_RMX_SD2CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 20)
@@ -480,15 +442,15 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
* formula: size - 1
* Other values not listed are not supported.
*/
-#define HDA_SDIFIFO_120B 0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
-#define HDA_SDIFIFO_160B 0x9F /* 20-, 24-bit Input Streams Streams */
-
-#define HDA_SDOFIFO_16B 0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_32B 0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_64B 0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_128B 0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_192B 0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDOFIFO_256B 0xFF /* 20-, 24-bit Output Streams */
+#define HDA_SDINFIFO_120B 0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
+#define HDA_SDINFIFO_160B 0x9F /* 20-, 24-bit Input Streams Streams */
+
+#define HDA_SDONFIFO_16B 0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_32B 0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_64B 0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_128B 0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_192B 0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
+#define HDA_SDONFIFO_256B 0xFF /* 20-, 24-bit Output Streams */
#define SDFIFOS(pThis, num) HDA_REG((pThis), SD(FIFOS, num))
#define HDA_REG_SD0FMT 41 /* 0x92 */
@@ -508,10 +470,17 @@ AssertCompile(HDA_MAX_SDI <= HDA_MAX_SDO);
#define HDA_RMX_SD6FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 60)
#define HDA_RMX_SD7FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 70)
-#define SDFMT(pThis, num) (HDA_REG((pThis), SD(FMT, num)))
-#define HDA_SDFMT_BASE_RATE(pThis, num) ((SDFMT(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDFMT, BASE_RATE)) >> HDA_REG_FIELD_SHIFT(SDFMT, BASE_RATE))
-#define HDA_SDFMT_MULT(pThis, num) ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,MULT)) >> HDA_REG_FIELD_SHIFT(SDFMT, MULT))
-#define HDA_SDFMT_DIV(pThis, num) ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,DIV)) >> HDA_REG_FIELD_SHIFT(SDFMT, DIV))
+#define SDFMT(pThis, num) (HDA_REG((pThis), SD(FMT, num)))
+#define HDA_SDFMT_BASE_RATE_SHIFT 14
+#define HDA_SDFMT_MULT_SHIFT 11
+#define HDA_SDFMT_MULT_MASK 0x7
+#define HDA_SDFMT_DIV_SHIFT 8
+#define HDA_SDFMT_DIV_MASK 0x7
+#define HDA_SDFMT_BITS_SHIFT 4
+#define HDA_SDFMT_BITS_MASK 0x7
+#define SDFMT_BASE_RATE(pThis, num) ((SDFMT(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDFMT, BASE_RATE)) >> HDA_REG_FIELD_SHIFT(SDFMT, BASE_RATE))
+#define SDFMT_MULT(pThis, num) ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,MULT)) >> HDA_REG_FIELD_SHIFT(SDFMT, MULT))
+#define SDFMT_DIV(pThis, num) ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,DIV)) >> HDA_REG_FIELD_SHIFT(SDFMT, DIV))
#define HDA_REG_SD0BDPL 42 /* 0x98 */
#define HDA_REG_SD1BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 10) /* 0xB8 */
@@ -570,7 +539,7 @@ typedef struct HDABDLESTATE
* Used to check if we need fill up the FIFO again. */
uint32_t cbBelowFIFOW;
/** The buffer descriptor's internal DMA buffer. */
- uint8_t au8FIFO[HDA_SDOFIFO_256B + 1];
+ uint8_t au8FIFO[HDA_SDONFIFO_256B + 1];
/** Current offset in DMA buffer (in bytes).*/
uint32_t u32BufOff;
uint32_t Padding;
@@ -598,70 +567,30 @@ typedef struct HDABDLE
} HDABDLE, *PHDABDLE;
/**
- * Structure for keeping an audio stream data mapping.
- */
-typedef struct HDASTREAMMAPPING
-{
- /** The stream's layout. */
- PDMAUDIOSTREAMLAYOUT enmLayout;
- /** Number of audio channels in this stream. */
- uint8_t cChannels;
- /** Array audio channels. */
- R3PTRTYPE(PPDMAUDIOSTREAMCHANNEL) paChannels;
- R3PTRTYPE(PRTCIRCBUF) pCircBuf;
-} HDASTREAMMAPPING, *PHDASTREAMMAPPING;
-
-/**
* Internal state of a HDA stream.
*/
typedef struct HDASTREAMSTATE
{
/** Current BDLE to use. Wraps around to 0 if
* maximum (cBDLE) is reached. */
- uint16_t uCurBDLE;
+ uint16_t uCurBDLE;
/** Stop indicator. */
- volatile bool fDoStop;
+ volatile bool fDoStop;
/** Flag indicating whether this stream is in an
* active (operative) state or not. */
- volatile bool fActive;
+ volatile bool fActive;
/** Flag indicating whether this stream currently is
* in reset mode and therefore not acccessible by the guest. */
- volatile bool fInReset;
+ volatile bool fInReset;
/** Unused, padding. */
- bool fPadding;
- /** Critical section to serialize access. */
- RTCRITSECT CritSect;
+ bool fPadding;
/** Event signalling that the stream's state has been changed. */
- RTSEMEVENT hStateChangedEvent;
- /** This stream's data mapping. */
- HDASTREAMMAPPING Mapping;
+ RTSEMEVENT hStateChangedEvent;
/** Current BDLE (Buffer Descriptor List Entry). */
- HDABDLE BDLE;
+ HDABDLE BDLE;
} HDASTREAMSTATE, *PHDASTREAMSTATE;
/**
- * Structure defining an HDA mixer sink.
- * Its purpose is to know which audio mixer sink is bound to
- * which SDn (SDI/SDO) device stream.
- *
- * This is needed in order to handle interleaved streams
- * (that is, multiple channels in one stream) or non-interleaved
- * streams (each channel has a dedicated stream).
- *
- * This is only known to the actual device emulation level.
- */
-typedef struct HDAMIXERSINK
-{
- /** SDn ID this sink is assigned to. 0 if not assigned. */
- uint8_t uSD;
- /** Channel ID of SDn ID. Only valid if SDn ID is valid. */
- uint8_t uChannel;
- uint8_t Padding[3];
- /** Pointer to the actual audio mixer sink. */
- R3PTRTYPE(PAUDMIXSINK) pMixSink;
-} HDAMIXERSINK, *PHDAMIXERSINK;
-
-/**
* Structure for keeping a HDA stream state.
*
* Contains only register values which do *not* change until a
@@ -669,60 +598,44 @@ typedef struct HDAMIXERSINK
*/
typedef struct HDASTREAM
{
- /** Stream descriptor number (SDn). */
- uint8_t u8SD;
- uint8_t Padding0[7];
+ /** Stream number (SDn). */
+ uint8_t u8Strm;
+ uint8_t Padding0[7];
/** DMA base address (SDnBDPU - SDnBDPL). */
- uint64_t u64BDLBase;
+ uint64_t u64BDLBase;
/** Cyclic Buffer Length (SDnCBL).
* Represents the size of the ring buffer. */
- uint32_t u32CBL;
+ uint32_t u32CBL;
/** Format (SDnFMT). */
- uint16_t u16FMT;
+ uint16_t u16FMT;
/** FIFO Size (FIFOS).
* Maximum number of bytes that may have been DMA'd into
* memory but not yet transmitted on the link.
*
* Must be a power of two. */
- uint16_t u16FIFOS;
+ uint16_t u16FIFOS;
/** Last Valid Index (SDnLVI). */
- uint16_t u16LVI;
- uint16_t Padding1[3];
- /** Pointer to HDA sink this stream is attached to. */
- R3PTRTYPE(PHDAMIXERSINK) pMixSink;
+ uint16_t u16LVI;
+ uint16_t Padding1[3];
/** Internal state of this stream. */
- HDASTREAMSTATE State;
+ HDASTREAMSTATE State;
} HDASTREAM, *PHDASTREAM;
-/**
- * Structure for mapping a stream tag to an HDA stream.
- */
-typedef struct HDATAG
+typedef struct HDAINPUTSTREAM
{
- /** Own stream tag. */
- uint8_t uTag;
- uint8_t Padding[7];
- /** Pointer to associated stream. */
- R3PTRTYPE(PHDASTREAM) pStrm;
-} HDATAG, *PHDATAG;
+ /** PCM line input stream. */
+ R3PTRTYPE(PPDMAUDIOGSTSTRMIN) pStrmIn;
+ /** Mixer handle for line input stream. */
+ R3PTRTYPE(PAUDMIXSTREAM) phStrmIn;
+} HDAINPUTSTREAM, *PHDAINPUTSTREAM;
-/**
- * Structure defining an HDA mixer stream.
- * This is being used together with an audio mixer instance.
- */
-typedef struct HDAMIXERSTREAM
+typedef struct HDAOUTPUTSTREAM
{
- union
- {
- /** Desired playback destination (for an output stream). */
- PDMAUDIOPLAYBACKDEST Dest;
- /** Desired recording source (for an input stream). */
- PDMAUDIORECSOURCE Source;
- } DestSource;
- uint8_t Padding1[4];
- /** Associated mixer handle. */
- R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
-} HDAMIXERSTREAM, *PHDAMIXERSTREAM;
+ /** PCM output stream. */
+ R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
+ /** Mixer handle for line output stream. */
+ R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
+} HDAOUTPUTSTREAM, *PHDAOUTPUTSTREAM;
/**
* Struct for maintaining a host backend driver.
@@ -750,20 +663,12 @@ typedef struct HDADRIVER
R3PTRTYPE(PPDMIBASE) pDrvBase;
/** Audio connector interface to the underlying host backend. */
R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
- /** Mixer stream for line input. */
- HDAMIXERSTREAM LineIn;
-#ifdef VBOX_WITH_HDA_MIC_IN
- /** Mixer stream for mic input. */
- HDAMIXERSTREAM MicIn;
-#endif
- /** Mixer stream for front output. */
- HDAMIXERSTREAM Front;
-#ifdef VBOX_WITH_HDA_51_SURROUND
- /** Mixer stream for center/LFE output. */
- HDAMIXERSTREAM CenterLFE;
- /** Mixer stream for rear output. */
- HDAMIXERSTREAM Rear;
-#endif
+ /** Stream for line input. */
+ HDAINPUTSTREAM LineIn;
+ /** Stream for mic input. */
+ HDAINPUTSTREAM MicIn;
+ /** Stream for output. */
+ HDAOUTPUTSTREAM Out;
} HDADRIVER;
/**
@@ -785,11 +690,13 @@ typedef struct HDASTATE
PDMIBASE IBase;
RTGCPHYS MMIOBaseAddr;
/** The HDA's register set. */
- uint32_t au32Regs[HDA_NUM_REGS];
- /** Internal stream states. */
- HDASTREAM aStreams[HDA_MAX_STREAMS];
- /** Mapping table between stream tags and stream states. */
- HDATAG aTags[HDA_MAX_TAGS];
+ uint32_t au32Regs[HDA_NREGS];
+ /** Stream state for line-in. */
+ HDASTREAM StrmStLineIn;
+ /** Stream state for microphone-in. */
+ HDASTREAM StrmStMicIn;
+ /** Stream state for output. */
+ HDASTREAM StrmStOut;
/** CORB buffer base address. */
uint64_t u64CORBBase;
/** RIRB buffer base address. */
@@ -800,7 +707,7 @@ typedef struct HDASTATE
/** DMA position buffer enable bit. */
bool fDMAPosition;
/** Padding for alignment. */
- uint8_t u8Padding0[7];
+ uint8_t u32Padding0[7];
/** Pointer to CORB buffer. */
R3PTRTYPE(uint32_t *) pu32CorbBuf;
/** Size in bytes of CORB buffer. */
@@ -811,21 +718,16 @@ typedef struct HDASTATE
R3PTRTYPE(uint64_t *) pu64RirbBuf;
/** Size in bytes of RIRB buffer. */
uint32_t cbRirbBuf;
- /** Indicates if HDA controller is in reset mode. */
+ /** Indicates if HDA is in reset. */
bool fInReset;
/** Flag whether the R0 part is enabled. */
bool fR0Enabled;
/** Flag whether the RC part is enabled. */
bool fRCEnabled;
- /** Number of active (running) SDn streams. */
- uint8_t cStreamsActive;
#ifndef VBOX_WITH_AUDIO_CALLBACKS
/** The timer for pumping data thru the attached LUN drivers. */
PTMTIMERR3 pTimer;
- /** Flag indicating whether the timer is active or not. */
- bool fTimerActive;
- uint8_t u8Padding1[7];
- /** Timer ticks per Hz. */
+ /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
uint64_t cTimerTicks;
/** Timestamp of the last timer callback (hdaTimer).
* Used to calculate the time actually elapsed between two timer callbacks. */
@@ -844,20 +746,12 @@ typedef struct HDASTATE
RTLISTANCHORR3 lstDrv;
/** The device' software mixer. */
R3PTRTYPE(PAUDIOMIXER) pMixer;
- /** HDA sink for (front) output. */
- HDAMIXERSINK SinkFront;
-#ifdef VBOX_WITH_HDA_51_SURROUND
- /** HDA sink for center / LFE output. */
- HDAMIXERSINK SinkCenterLFE;
- /** HDA sink for rear output. */
- HDAMIXERSINK SinkRear;
-#endif
- /** HDA mixer sink for line input. */
- HDAMIXERSINK SinkLineIn;
-#ifdef VBOX_WITH_HDA_MIC_IN
+ /** Audio sink for PCM output. */
+ R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
+ /** Audio mixer sink for line input. */
+ R3PTRTYPE(PAUDMIXSINK) pSinkLineIn;
/** Audio mixer sink for microphone input. */
- HDAMIXERSINK SinkMicIn;
-#endif
+ R3PTRTYPE(PAUDMIXSINK) pSinkMicIn;
uint64_t u64BaseTS;
/** Response Interrupt Count (RINTCNT). */
uint8_t u8RespIntCnt;
@@ -875,110 +769,79 @@ typedef struct HDACALLBACKCTX
} HDACALLBACKCTX, *PHDACALLBACKCTX;
#endif
-
/*********************************************************************************************************************************
* Internal Functions *
*********************************************************************************************************************************/
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-#ifdef IN_RING3
+# ifdef IN_RING3
static FNPDMDEVRESET hdaReset;
#endif
-/** @name Register read/write stubs.
- * @{
+/*
+ * Stubs.
*/
static int hdaRegReadUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
static int hdaRegWriteUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-/** @} */
-/** @name Global register set read/write functions.
- * @{
+/*
+ * Global register set read/write functions.
*/
-static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
static int hdaRegReadLPIB(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-//static int hdaRegReadSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value); - unused
-//static int hdaRegWriteSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); - unused
-//static int hdaRegWriteINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); - implementation not found.
-static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-/** @} */
-/** @name {IOB}SDn write functions.
- * @{
+/*
+ * {IOB}SDn read/write functions.
*/
-static int hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-//static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); - unused
-//static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value); - unused
-static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-/** @} */
-
-/* Locking + logging. */
-#ifdef IN_RING3
-DECLINLINE(int) hdaRegWriteSDLock(PHDASTATE pThis, PHDASTREAM pStream, uint32_t iReg, uint32_t u32Value);
-DECLINLINE(void) hdaRegWriteSDUnlock(PHDASTREAM pStream);
-#endif
+static int hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+inline bool hdaRegWriteSDIsAllowed(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-/** @name Generic register read/write functions.
- * @{
+/*
+ * Generic register read/write functions.
*/
static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-#ifdef IN_RING3
-static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-#endif
+static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
static int hdaRegReadU16(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
+static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-/** @} */
-
-#ifdef IN_RING3
-static void hdaStreamDestroy(PHDASTREAM pStream);
-static int hdaStreamSetActive(PHDASTATE pThis, PHDASTREAM pStream, bool fActive);
-//static int hdaStreamStart(PHDASTREAM pStream); - unused
-static int hdaStreamStop(PHDASTREAM pStream);
-/*static int hdaStreamWaitForStateChange(PHDASTREAM pStream, RTMSINTERVAL msTimeout); - currently unused */
-static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
-#endif
+static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
#ifdef IN_RING3
-static int hdaStreamMapInit(PHDASTREAMMAPPING pMapping, PPDMAUDIOSTREAMCFG pCfg);
-static void hdaStreamMapDestroy(PHDASTREAMMAPPING pMapping);
-static void hdaStreamMapReset(PHDASTREAMMAPPING pMapping);
+static void hdaStreamDestroy(PHDASTREAM pStrmSt);
+//static int hdaStreamStart(PHDASTREAM pStrmSt);
+static int hdaStreamStop(PHDASTREAM pStrmSt);
+//static int hdaStreamWaitForStateChange(PHDASTREAM pStrmSt, RTMSINTERVAL msTimeout);
+static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbToProcess, uint32_t *pcbProcessed);
#endif
#ifdef IN_RING3
-static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
-DECLINLINE(uint32_t) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStream, uint32_t u32LPIB);
+static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
+DECLINLINE(void) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t u32LPIB);
# ifdef LOG_ENABLED
-static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BaseDMA, uint16_t cBDLE);
+static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BaseDMA, uint16_t cBDLE);
# endif
#endif
-static int hdaProcessInterrupt(PHDASTATE pThis);
-
-/*
- * Timer routines.
- */
-#if !defined(VBOX_WITH_AUDIO_CALLBACKS) && defined(IN_RING3)
-static void hdaTimerMaybeStart(PHDASTATE pThis);
-static void hdaTimerMaybeStop(PHDASTATE pThis);
-#endif
/*********************************************************************************************************************************
@@ -1012,9 +875,9 @@ static void hdaTimerMaybeStop(PHDASTATE pThis);
/* Offset 0x8C (SD0) */ \
{ offset + 0xC, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16, hdaRegWriteSDLVI , HDA_REG_IDX_STRM(name, LVI) , #name " Last Valid Index" }, \
/* Reserved: FIFO Watermark. ** @todo Document this! */ \
- { offset + 0xE, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16, hdaRegWriteU16, HDA_REG_IDX_STRM(name, FIFOW), #name " FIFO Watermark" }, \
+ { offset + 0xE, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16, hdaRegWriteSDFIFOW, HDA_REG_IDX_STRM(name, FIFOW), #name " FIFO Watermark" }, \
/* Offset 0x90 (SD0) */ \
- { offset + 0x10, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16, hdaRegWriteU16, HDA_REG_IDX_STRM(name, FIFOS), #name " FIFO Size" }, \
+ { offset + 0x10, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16, hdaRegWriteSDFIFOS, HDA_REG_IDX_STRM(name, FIFOS), #name " FIFO Size" }, \
/* Offset 0x92 (SD0) */ \
{ offset + 0x12, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16, hdaRegWriteSDFMT , HDA_REG_IDX_STRM(name, FMT) , #name " Stream Format" }, \
/* Reserved: 0x94 - 0x98. */ \
@@ -1048,7 +911,7 @@ static const struct HDAREGDESC
const char *abbrev;
/** Descripton. */
const char *desc;
-} g_aHdaRegMap[HDA_NUM_REGS] =
+} g_aHdaRegMap[HDA_NREGS] =
{
/* offset size read mask write mask read callback write callback index + abbrev */
@@ -1056,13 +919,13 @@ static const struct HDAREGDESC
{ 0x00000, 0x00002, 0x0000FFFB, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(GCAP) }, /* Global Capabilities */
{ 0x00002, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimpl , HDA_REG_IDX(VMIN) }, /* Minor Version */
{ 0x00003, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimpl , HDA_REG_IDX(VMAJ) }, /* Major Version */
- { 0x00004, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , HDA_REG_IDX(OUTPAY) }, /* Output Payload Capabilities */
+ { 0x00004, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(OUTPAY) }, /* Output Payload Capabilities */
{ 0x00006, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(INPAY) }, /* Input Payload Capabilities */
{ 0x00008, 0x00004, 0x00000103, 0x00000103, hdaRegReadU32 , hdaRegWriteGCTL , HDA_REG_IDX(GCTL) }, /* Global Control */
{ 0x0000c, 0x00002, 0x00007FFF, 0x00007FFF, hdaRegReadU16 , hdaRegWriteU16 , HDA_REG_IDX(WAKEEN) }, /* Wake Enable */
{ 0x0000e, 0x00002, 0x00000007, 0x00000007, hdaRegReadU8 , hdaRegWriteSTATESTS , HDA_REG_IDX(STATESTS) }, /* State Change Status */
{ 0x00010, 0x00002, 0xFFFFFFFF, 0x00000000, hdaRegReadUnimpl , hdaRegWriteUnimpl , HDA_REG_IDX(GSTS) }, /* Global Status */
- { 0x00018, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteU16 , HDA_REG_IDX(OUTSTRMPAY) }, /* Output Stream Payload Capability */
+ { 0x00018, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(OUTSTRMPAY) }, /* Output Stream Payload Capability */
{ 0x0001A, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(INSTRMPAY) }, /* Input Stream Payload Capability */
{ 0x00020, 0x00004, 0xC00000FF, 0xC00000FF, hdaRegReadU32 , hdaRegWriteU32 , HDA_REG_IDX(INTCTL) }, /* Interrupt Control */
{ 0x00024, 0x00004, 0xC00000FF, 0x00000000, hdaRegReadINTSTS , hdaRegWriteUnimpl , HDA_REG_IDX(INTSTS) }, /* Interrupt Status */
@@ -1087,12 +950,12 @@ static const struct HDAREGDESC
{ 0x00068, 0x00002, 0x00000002, 0x00000002, hdaRegReadIRS , hdaRegWriteIRS , HDA_REG_IDX(IRS) }, /* Immediate Command Status */
{ 0x00070, 0x00004, 0xFFFFFFFF, 0xFFFFFF81, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(DPLBASE) }, /* DMA Position Lower Base */
{ 0x00074, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(DPUBASE) }, /* DMA Position Upper Base */
- /* 4 Serial Data In (SDI). */
+ /* 4 Input Stream Descriptors (ISD). */
HDA_REG_MAP_DEF_STREAM(0, SD0),
HDA_REG_MAP_DEF_STREAM(1, SD1),
HDA_REG_MAP_DEF_STREAM(2, SD2),
HDA_REG_MAP_DEF_STREAM(3, SD3),
- /* 4 Serial Data Out (SDO). */
+ /* 4 Output Stream Descriptors (OSD). */
HDA_REG_MAP_DEF_STREAM(4, SD4),
HDA_REG_MAP_DEF_STREAM(5, SD5),
HDA_REG_MAP_DEF_STREAM(6, SD6),
@@ -1162,33 +1025,34 @@ static uint32_t const g_afMasks[5] =
};
#ifdef IN_RING3
-
-DECLINLINE(uint32_t) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStream, uint32_t u32LPIB)
+DECLINLINE(void) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t u32LPIB)
{
- AssertPtrReturn(pThis, 0);
- AssertPtrReturn(pStream, 0);
+ AssertPtrReturnVoid(pThis);
+ AssertPtrReturnVoid(pStrmSt);
- Assert(u32LPIB <= pStream->u32CBL);
+ Assert(u32LPIB <= pStrmSt->u32CBL);
LogFlowFunc(("[SD%RU8]: LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
- pStream->u8SD, u32LPIB, pThis->fDMAPosition));
+ pStrmSt->u8Strm, u32LPIB, pThis->fDMAPosition));
/* Update LPIB in any case. */
- HDA_STREAM_REG(pThis, LPIB, pStream->u8SD) = u32LPIB;
+ HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) = u32LPIB;
/* Do we need to tell the current DMA position? */
if (pThis->fDMAPosition)
{
int rc2 = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
- (pThis->u64DPBase & DPBASE_ADDR_MASK) + (pStream->u8SD * 2 * sizeof(uint32_t)),
+ (pThis->u64DPBase & DPBASE_ADDR_MASK) + (pStrmSt->u8Strm * 2 * sizeof(uint32_t)),
(void *)&u32LPIB, sizeof(uint32_t));
AssertRC(rc2);
+#ifdef DEBUG
+ hdaBDLEDumpAll(pThis, pStrmSt->u64BDLBase, pStrmSt->State.uCurBDLE);
+#endif
}
-
- return u32LPIB;
}
+#endif
-
+#if defined(IN_RING3) || defined(LOG_ENABLED)
/**
* Retrieves the number of bytes of a FIFOS register.
*
@@ -1200,16 +1064,16 @@ DECLINLINE(uint16_t) hdaSDFIFOSToBytes(uint32_t u32RegFIFOS)
switch (u32RegFIFOS)
{
/* Input */
- case HDA_SDIFIFO_120B: cb = 120; break;
- case HDA_SDIFIFO_160B: cb = 160; break;
+ case HDA_SDINFIFO_120B: cb = 120; break;
+ case HDA_SDINFIFO_160B: cb = 160; break;
/* Output */
- case HDA_SDOFIFO_16B: cb = 16; break;
- case HDA_SDOFIFO_32B: cb = 32; break;
- case HDA_SDOFIFO_64B: cb = 64; break;
- case HDA_SDOFIFO_128B: cb = 128; break;
- case HDA_SDOFIFO_192B: cb = 192; break;
- case HDA_SDOFIFO_256B: cb = 256; break;
+ case HDA_SDONFIFO_16B: cb = 16; break;
+ case HDA_SDONFIFO_32B: cb = 32; break;
+ case HDA_SDONFIFO_64B: cb = 64; break;
+ case HDA_SDONFIFO_128B: cb = 128; break;
+ case HDA_SDONFIFO_192B: cb = 192; break;
+ case HDA_SDONFIFO_256B: cb = 256; break;
default:
{
cb = 0; /* Can happen on stream reset. */
@@ -1219,9 +1083,9 @@ DECLINLINE(uint16_t) hdaSDFIFOSToBytes(uint32_t u32RegFIFOS)
return cb;
}
+#endif
-
-# if defined(IN_RING3) && (defined(DEBUG) || defined(VBOX_HDA_WITH_FIFO))
+#if defined(IN_RING3) && (defined(VBOX_HDA_WITH_FIFO) || defined(DEBUG))
/**
* Retrieves the number of bytes of a FIFOW register.
*
@@ -1238,111 +1102,92 @@ DECLINLINE(uint8_t) hdaSDFIFOWToBytes(uint32_t u32RegFIFOW)
default: cb = 0; break;
}
+#ifdef RT_STRICT
Assert(RT_IS_POWER_OF_TWO(cb));
+#endif
return cb;
}
#endif
-
+#ifdef IN_RING3
/**
* Fetches the next BDLE to use for a stream.
*
* @return IPRT status code.
*/
-DECLINLINE(int) hdaStreamGetNextBDLE(PHDASTATE pThis, PHDASTREAM pStream)
+DECLINLINE(int) hdaStreamGetNextBDLE(PHDASTATE pThis, PHDASTREAM pStrmSt)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
NOREF(pThis);
- Assert(pStream->State.uCurBDLE < pStream->u16LVI + 1);
-
- LogFlowFuncEnter();
-
-# ifdef LOG_ENABLED
- uint32_t const uOldBDLE = pStream->State.uCurBDLE;
-# endif
+ Assert(pStrmSt->State.uCurBDLE < pStrmSt->u16LVI + 1);
- PHDABDLE pBDLE = &pStream->State.BDLE;
+#ifdef DEBUG
+ uint32_t uOldBDLE = pStrmSt->State.uCurBDLE;
+#endif
/*
* Switch to the next BDLE entry and do a wrap around
* if we reached the end of the Buffer Descriptor List (BDL).
*/
- pStream->State.uCurBDLE++;
- if (pStream->State.uCurBDLE == pStream->u16LVI + 1)
+ pStrmSt->State.uCurBDLE++;
+ if (pStrmSt->State.uCurBDLE == pStrmSt->u16LVI + 1)
{
- pStream->State.uCurBDLE = 0;
+ pStrmSt->State.uCurBDLE = 0;
- hdaStreamUpdateLPIB(pThis, pStream, 0);
+ hdaStreamUpdateLPIB(pThis, pStrmSt, 0);
}
- Assert(pStream->State.uCurBDLE < pStream->u16LVI + 1);
+ Assert(pStrmSt->State.uCurBDLE < pStrmSt->u16LVI + 1);
- /* Fetch the next BDLE entry. */
- int rc = hdaBDLEFetch(pThis, pBDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
+ int rc = hdaBDLEFetch(pThis, &pStrmSt->State.BDLE, pStrmSt->u64BDLBase, pStrmSt->State.uCurBDLE);
- LogFlowFunc(("[SD%RU8]: uOldBDLE=%RU16, uCurBDLE=%RU16, LVI=%RU32, rc=%Rrc, %R[bdle]\n",
- pStream->u8SD, uOldBDLE, pStream->State.uCurBDLE, pStream->u16LVI, rc, pBDLE));
+#ifdef DEBUG
+ LogFlowFunc(("[SD%RU8]: uOldBDLE=%RU16, uCurBDLE=%RU16, LVI=%RU32, %R[bdle]\n",
+ pStrmSt->u8Strm, uOldBDLE, pStrmSt->State.uCurBDLE, pStrmSt->u16LVI, &pStrmSt->State.BDLE));
+#endif
return rc;
}
+#endif
-
-/**
- * Returns the audio direction of a specified stream descriptor.
- *
- * The register layout specifies that input streams (SDI) come first,
- * followed by the output streams (SDO). So every stream ID below HDA_MAX_SDI
- * is an input stream, whereas everything >= HDA_MAX_SDI is an output stream.
- *
- * Note: SDnFMT register does not provide that information, so we have to judge
- * for ourselves.
- *
- * @return Audio direction.
- */
-DECLINLINE(PDMAUDIODIR) hdaGetDirFromSD(uint8_t uSD)
-{
- AssertReturn(uSD <= HDA_MAX_STREAMS, PDMAUDIODIR_UNKNOWN);
-
- if (uSD < HDA_MAX_SDI)
- return PDMAUDIODIR_IN;
-
- return PDMAUDIODIR_OUT;
-}
-
-
-/**
- * Returns the HDA stream of specified stream descriptor number.
- *
- * @return Pointer to HDA stream, or NULL if none found.
- */
-DECLINLINE(PHDASTREAM) hdaStreamFromSD(PHDASTATE pThis, uint8_t uSD)
+DECLINLINE(PHDASTREAM) hdaStreamFromID(PHDASTATE pThis, uint8_t uStreamID)
{
- AssertPtrReturn(pThis, NULL);
- AssertReturn(uSD <= HDA_MAX_STREAMS, NULL);
-
- if (uSD >= HDA_MAX_STREAMS)
- return NULL;
-
- return &pThis->aStreams[uSD];
-}
+ PHDASTREAM pStrmSt;
+ switch (uStreamID)
+ {
+ case 0: /** @todo Use dynamic indices, based on stream assignment. */
+ {
+ pStrmSt = &pThis->StrmStLineIn;
+ break;
+ }
+# ifdef VBOX_WITH_HDA_MIC_IN
+ case 2: /** @todo Use dynamic indices, based on stream assignment. */
+ {
+ pStrmSt = &pThis->StrmStMicIn;
+ break;
+ }
+# endif
+ case 4: /** @todo Use dynamic indices, based on stream assignment. */
+ {
+ pStrmSt = &pThis->StrmStOut;
+ break;
+ }
-/**
- * Returns the HDA stream of specified HDA sink.
- *
- * @return Pointer to HDA stream, or NULL if none found.
- */
-DECLINLINE(PHDASTREAM) hdaGetStreamFromSink(PHDASTATE pThis, PHDAMIXERSINK pSink)
-{
- AssertPtrReturn(pThis, NULL);
- AssertPtrReturn(pSink, NULL);
+ default:
+ {
+ pStrmSt = NULL;
+ LogFunc(("Warning: Stream with ID=%RU8 not handled\n", uStreamID));
+ break;
+ }
+ }
- /** @todo Do something with the channel mapping here? */
- return hdaStreamFromSD(pThis, pSink->uSD);
+ return pStrmSt;
}
+#ifdef IN_RING3
/**
* Retrieves the minimum number of bytes accumulated/free in the
* FIFO before the controller will start a fetch/eviction of data.
@@ -1351,19 +1196,18 @@ DECLINLINE(PHDASTREAM) hdaGetStreamFromSink(PHDASTATE pThis, PHDAMIXERSINK pSink
*
* @return Number of bytes accumulated/free in the FIFO.
*/
-DECLINLINE(uint8_t) hdaStreamGetFIFOW(PHDASTATE pThis, PHDASTREAM pStream)
+DECLINLINE(uint8_t) hdaStreamGetFIFOW(PHDASTATE pThis, PHDASTREAM pStrmSt)
{
AssertPtrReturn(pThis, 0);
- AssertPtrReturn(pStream, 0);
+ AssertPtrReturn(pStrmSt, 0);
# ifdef VBOX_HDA_WITH_FIFO
- return hdaSDFIFOWToBytes(HDA_STREAM_REG(pThis, FIFOW, pStream->u8SD));
+ return hdaSDFIFOWToBytes(HDA_STREAM_REG(pThis, FIFOW, pStrmSt->u8Strm));
# else
return 0;
# endif
}
-
-#endif /* IN_RING3 */
+#endif
static int hdaProcessInterrupt(PHDASTATE pThis)
{
@@ -1371,35 +1215,29 @@ static int hdaProcessInterrupt(PHDASTATE pThis)
( INTCTL_SX((pThis), num) \
&& (SDSTS(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
- int iLevel = 0;
-
- /** @todo Optimize IRQ handling. */
+ bool fIrq = false;
if (/* Controller Interrupt Enable (CIE). */
HDA_REG_FLAG_VALUE(pThis, INTCTL, CIE)
&& ( HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RINTFL)
|| HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RIRBOIS)
|| (HDA_REG(pThis, STATESTS) & HDA_REG(pThis, WAKEEN))))
- {
- iLevel = 1;
- }
+ fIrq = true;
+ /** @todo Don't hardcode stream numbers here. */
if ( IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 0)
- || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 1)
- || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 2)
- || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 3)
- || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 4)
- || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 5)
- || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 6)
- || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 7))
+ || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 4))
{
- iLevel = 1;
+#ifdef IN_RING3
+ LogFunc(("BCIS\n"));
+#endif
+ fIrq = true;
}
if (HDA_REG_FLAG_VALUE(pThis, INTCTL, GIE))
{
- Log3Func(("Level=%d\n", iLevel));
- PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , iLevel);
+ LogFunc(("%s\n", fIrq ? "Asserted" : "Deasserted"));
+ PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , fIrq);
}
#undef IS_INTERRUPT_OCCURED_AND_ENABLED
@@ -1411,10 +1249,13 @@ static int hdaProcessInterrupt(PHDASTATE pThis)
* Looks up a register at the exact offset given by @a offReg.
*
* @returns Register index on success, -1 if not found.
+ * @param pThis The HDA device state.
* @param offReg The register offset.
*/
-static int hdaRegLookup(uint32_t offReg)
+static int hdaRegLookup(PHDASTATE pThis, uint32_t offReg)
{
+ RT_NOREF(pThis);
+
/*
* Aliases.
*/
@@ -1462,10 +1303,13 @@ static int hdaRegLookup(uint32_t offReg)
* Looks up a register covering the offset given by @a offReg.
*
* @returns Register index on success, -1 if not found.
+ * @param pThis The HDA device state.
* @param offReg The register offset.
*/
-static int hdaRegLookupWithin(uint32_t offReg)
+static int hdaRegLookupWithin(PHDASTATE pThis, uint32_t offReg)
{
+ RT_NOREF(pThis);
+
/*
* Aliases.
*/
@@ -1513,21 +1357,16 @@ static int hdaRegLookupWithin(uint32_t offReg)
}
#ifdef IN_RING3
-
static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
{
int rc = VINF_SUCCESS;
if (fLocal)
{
Assert((HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)));
- Assert(pThis->u64CORBBase);
- AssertPtr(pThis->pu32CorbBuf);
- Assert(pThis->cbCorbBuf);
-
rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pThis->u64CORBBase, pThis->pu32CorbBuf, pThis->cbCorbBuf);
if (RT_FAILURE(rc))
AssertRCReturn(rc, rc);
-# ifdef DEBUG_CMD_BUFFER
+#ifdef DEBUG_CMD_BUFFER
uint8_t i = 0;
do
{
@@ -1548,7 +1387,7 @@ static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
LogFunc(("\n"));
i += 8;
} while(i != 0);
-# endif
+#endif
}
else
{
@@ -1556,7 +1395,7 @@ static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pThis->u64RIRBBase, pThis->pu64RirbBuf, pThis->cbRirbBuf);
if (RT_FAILURE(rc))
AssertRCReturn(rc, rc);
-# ifdef DEBUG_CMD_BUFFER
+#ifdef DEBUG_CMD_BUFFER
uint8_t i = 0;
do {
LogFunc(("RIRB%02x: ", i));
@@ -1572,13 +1411,15 @@ static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
LogFunc(("\n"));
i += 8;
} while (i != 0);
-# endif
+#endif
}
return rc;
}
static int hdaCORBCmdProcess(PHDASTATE pThis)
{
+ PFNHDACODECVERBPROCESSOR pfn = (PFNHDACODECVERBPROCESSOR)NULL;
+
int rc = hdaCmdSync(pThis, true);
if (RT_FAILURE(rc))
AssertRCReturn(rc, rc);
@@ -1588,41 +1429,47 @@ static int hdaCORBCmdProcess(PHDASTATE pThis)
uint8_t rirbWp = HDA_REG(pThis, RIRBWP);
Assert((corbWp != corbRp));
- Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
+ LogFlowFunc(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
while (corbRp != corbWp)
{
- uint64_t uResp;
- uint32_t uCmd = pThis->pu32CorbBuf[++corbRp];
+ uint32_t cmd;
+ uint64_t resp = 0;
+ pfn = NULL;
+ corbRp++;
+ cmd = pThis->pu32CorbBuf[corbRp];
- int rc2 = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(uCmd, 0 /* Codec index */), &uResp);
- if (RT_FAILURE(rc2))
- LogFunc(("Codec lookup failed with rc=%Rrc\n", rc2));
+ rc = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(cmd, 0 /* Codec index */), &pfn);
+ if (RT_SUCCESS(rc))
+ {
+ AssertPtr(pfn);
+ rc = pfn(pThis->pCodec, HDA_CODEC_CMD(cmd, 0 /* LUN */), &resp);
+ }
+ if (RT_FAILURE(rc))
+ AssertRCReturn(rc, rc);
(rirbWp)++;
- if ( (uResp & CODEC_RESPONSE_UNSOLICITED)
+ LogFunc(("verb:%08x->%016lx\n", cmd, resp));
+ if ( (resp & CODEC_RESPONSE_UNSOLICITED)
&& !HDA_REG_FLAG_VALUE(pThis, GCTL, UR))
{
- LogFunc(("Unexpected unsolicited response\n"));
+ LogFunc(("unexpected unsolicited response.\n"));
HDA_REG(pThis, CORBRP) = corbRp;
return rc;
}
- pThis->pu64RirbBuf[rirbWp] = uResp;
+ pThis->pu64RirbBuf[rirbWp] = resp;
pThis->u8RespIntCnt++;
if (pThis->u8RespIntCnt == RINTCNT_N(pThis))
break;
}
-
HDA_REG(pThis, CORBRP) = corbRp;
HDA_REG(pThis, RIRBWP) = rirbWp;
-
rc = hdaCmdSync(pThis, false);
-
- Log3Func(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
-
+ LogFunc(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP),
+ HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
if (HDA_REG_FLAG_VALUE(pThis, RIRBCTL, RIC))
{
HDA_REG(pThis, RIRBSTS) |= HDA_REG_FIELD_FLAG_MASK(RIRBSTS,RINTFL);
@@ -1630,263 +1477,164 @@ static int hdaCORBCmdProcess(PHDASTATE pThis)
pThis->u8RespIntCnt = 0;
rc = hdaProcessInterrupt(pThis);
}
-
if (RT_FAILURE(rc))
AssertRCReturn(rc, rc);
return rc;
}
-static int hdaStreamCreate(PHDASTREAM pStream, uint8_t uSD)
+static int hdaStreamCreate(PHDASTREAM pStrmSt)
{
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertReturn(uSD <= HDA_MAX_STREAMS, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- int rc = RTSemEventCreate(&pStream->State.hStateChangedEvent);
- if (RT_SUCCESS(rc))
- rc = RTCritSectInit(&pStream->State.CritSect);
+ int rc = RTSemEventCreate(&pStrmSt->State.hStateChangedEvent);
+ AssertRC(rc);
- if (RT_SUCCESS(rc))
- {
- pStream->u8SD = uSD;
- pStream->pMixSink = NULL;
+ pStrmSt->u8Strm = UINT8_MAX;
- pStream->State.fActive = false;
- pStream->State.fInReset = false;
- pStream->State.fDoStop = false;
- }
+ pStrmSt->State.fActive = false;
+ pStrmSt->State.fInReset = false;
+ pStrmSt->State.fDoStop = false;
- LogFlowFunc(("uSD=%RU8\n", uSD));
+ LogFlowFuncLeaveRC(rc);
return rc;
}
-static void hdaStreamDestroy(PHDASTREAM pStream)
+static void hdaStreamDestroy(PHDASTREAM pStrmSt)
{
- AssertPtrReturnVoid(pStream);
-
- LogFlowFunc(("[SD%RU8]: Destroying ...\n", pStream->u8SD));
-
- int rc2 = hdaStreamStop(pStream);
- AssertRC(rc2);
+ AssertPtrReturnVoid(pStrmSt);
- hdaStreamMapDestroy(&pStream->State.Mapping);
+ LogFlowFunc(("[SD%RU8]: Destroy\n", pStrmSt->u8Strm));
- rc2 = RTCritSectDelete(&pStream->State.CritSect);
+ int rc2 = hdaStreamStop(pStrmSt);
AssertRC(rc2);
- if (pStream->State.hStateChangedEvent != NIL_RTSEMEVENT)
+ if (pStrmSt->State.hStateChangedEvent != NIL_RTSEMEVENT)
{
- rc2 = RTSemEventDestroy(pStream->State.hStateChangedEvent);
+ rc2 = RTSemEventDestroy(pStrmSt->State.hStateChangedEvent);
AssertRC(rc2);
- pStream->State.hStateChangedEvent = NIL_RTSEMEVENT;
}
LogFlowFuncLeave();
}
-static int hdaStreamInit(PHDASTATE pThis, PHDASTREAM pStream, uint8_t u8SD)
+static int hdaStreamInit(PHDASTATE pThis, PHDASTREAM pStrmSt, uint8_t u8Strm)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- pStream->u8SD = u8SD;
- pStream->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStream->u8SD),
- HDA_STREAM_REG(pThis, BDPU, pStream->u8SD));
- pStream->u16LVI = HDA_STREAM_REG(pThis, LVI, pStream->u8SD);
- pStream->u32CBL = HDA_STREAM_REG(pThis, CBL, pStream->u8SD);
- pStream->u16FIFOS = hdaSDFIFOSToBytes(HDA_STREAM_REG(pThis, FIFOS, pStream->u8SD));
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- RT_ZERO(pStream->State.BDLE);
- pStream->State.uCurBDLE = 0;
+ pStrmSt->u8Strm = u8Strm;
+ pStrmSt->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrmSt->u8Strm),
+ HDA_STREAM_REG(pThis, BDPU, pStrmSt->u8Strm));
+ pStrmSt->u16LVI = HDA_STREAM_REG(pThis, LVI, pStrmSt->u8Strm);
+ pStrmSt->u32CBL = HDA_STREAM_REG(pThis, CBL, pStrmSt->u8Strm);
+ pStrmSt->u16FIFOS = hdaSDFIFOSToBytes(HDA_STREAM_REG(pThis, FIFOS, pStrmSt->u8Strm));
- hdaStreamMapReset(&pStream->State.Mapping);
+ RT_ZERO(pStrmSt->State.BDLE);
+ pStrmSt->State.uCurBDLE = 0;
LogFlowFunc(("[SD%RU8]: DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16\n",
- pStream->u8SD, pStream->u64BDLBase, pStream->u32CBL, pStream->u16LVI, pStream->u16FIFOS));
+ pStrmSt->u8Strm, pStrmSt->u64BDLBase, pStrmSt->u32CBL, pStrmSt->u16LVI, pStrmSt->u16FIFOS));
-# ifdef DEBUG
- uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStream->u8SD),
- HDA_STREAM_REG(pThis, BDPU, pStream->u8SD));
- uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, pStream->u8SD);
- uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, pStream->u8SD);
+#ifdef DEBUG
+ uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
+ HDA_STREAM_REG(pThis, BDPU, u8Strm));
+ uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, u8Strm);
+ uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, u8Strm);
LogFlowFunc(("\t-> DMA @ 0x%x, LVI=%RU16, CBL=%RU32\n", u64BaseDMA, u16LVI, u32CBL));
hdaBDLEDumpAll(pThis, u64BaseDMA, u16LVI + 1);
-# endif
+#endif
return VINF_SUCCESS;
}
-static void hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStream)
+static void hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStrmSt, uint8_t u8Strm)
{
AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStream);
-
- const uint8_t uSD = pStream->u8SD;
-
-# ifdef VBOX_STRICT
- AssertReleaseMsg(!RT_BOOL(HDA_STREAM_REG(pThis, CTL, uSD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)),
- ("[SD%RU8] Cannot reset stream while in running state\n", uSD));
-# endif
+ AssertPtrReturnVoid(pStrmSt);
+ AssertReturnVoid(u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
- LogFunc(("[SD%RU8]: Reset\n", uSD));
+#ifdef VBOX_STRICT
+ AssertReleaseMsg(!RT_BOOL(HDA_STREAM_REG(pThis, CTL, u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)),
+ ("Cannot reset stream %RU8 while in running state\n", u8Strm));
+#endif
/*
* Set reset state.
*/
- Assert(ASMAtomicReadBool(&pStream->State.fInReset) == false); /* No nested calls. */
- ASMAtomicXchgBool(&pStream->State.fInReset, true);
+ Assert(ASMAtomicReadBool(&pStrmSt->State.fInReset) == false); /* No nested calls. */
+ ASMAtomicXchgBool(&pStrmSt->State.fInReset, true);
/*
* First, reset the internal stream state.
*/
- RT_ZERO(pStream->State.BDLE);
- pStream->State.uCurBDLE = 0;
+ RT_BZERO(pStrmSt, sizeof(HDASTREAM));
/*
* Second, initialize the registers.
*/
- HDA_STREAM_REG(pThis, STS, uSD) = HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+ HDA_STREAM_REG(pThis, STS, u8Strm) = 0;
/* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20
* bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */
- HDA_STREAM_REG(pThis, CTL, uSD) = 0x40000 | (HDA_STREAM_REG(pThis, CTL, uSD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
+ HDA_STREAM_REG(pThis, CTL, u8Strm) = 0x40000 | (HDA_STREAM_REG(pThis, CTL, u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
/* ICH6 defines default values (0x77 for input and 0xBF for output descriptors) of FIFO size. 18.2.39. */
- HDA_STREAM_REG(pThis, FIFOS, uSD) = hdaGetDirFromSD(uSD) == PDMAUDIODIR_IN ? HDA_SDIFIFO_120B : HDA_SDOFIFO_192B;
+ HDA_STREAM_REG(pThis, FIFOS, u8Strm) = u8Strm < 4 ? HDA_SDINFIFO_120B : HDA_SDONFIFO_192B;
/* See 18.2.38: Always defaults to 0x4 (32 bytes). */
- HDA_STREAM_REG(pThis, FIFOW, uSD) = HDA_SDFIFOW_32B;
- HDA_STREAM_REG(pThis, LPIB, uSD) = 0;
- HDA_STREAM_REG(pThis, CBL, uSD) = 0;
- HDA_STREAM_REG(pThis, LVI, uSD) = 0;
- HDA_STREAM_REG(pThis, FMT, uSD) = HDA_SDFMT_MAKE(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
- HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
- HDA_SDFMT_CHAN_STEREO);
- HDA_STREAM_REG(pThis, BDPU, uSD) = 0;
- HDA_STREAM_REG(pThis, BDPL, uSD) = 0;
-
- int rc2 = hdaStreamInit(pThis, pStream, uSD);
- AssertRC(rc2);
-
- /* Report that we're done resetting this stream. */
- HDA_STREAM_REG(pThis, CTL, uSD) = 0;
-
- /* Exit reset state. */
- ASMAtomicXchgBool(&pStream->State.fInReset, false);
-}
-
-# if 0 /* unused */
-static bool hdaStreamIsActive(PHDASTATE pThis, PHDASTREAM pStream)
-{
- AssertPtrReturn(pThis, false);
- AssertPtrReturn(pStream, false);
-
- bool fActive = pStream->State.fActive;
-
- LogFlowFunc(("SD=%RU8, fActive=%RTbool\n", pStream->u8SD, fActive));
- return fActive;
-}
-# endif
-
-static int hdaStreamSetActive(PHDASTATE pThis, PHDASTREAM pStream, bool fActive)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- LogFlowFunc(("[SD%RU8]: fActive=%RTbool, pMixSink=%p\n", pStream->u8SD, fActive, pStream->pMixSink));
-
- if (pStream->State.fActive == fActive) /* No change required? */
- {
- LogFlowFunc(("[SD%RU8]: No change\n", pStream->u8SD));
- return VINF_SUCCESS;
- }
-
- int rc = VINF_SUCCESS;
-
- if (pStream->pMixSink) /* Stream attached to a sink? */
- {
- AUDMIXSINKCMD enmCmd = fActive
- ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE;
-
- /* First, enable or disable the stream and the stream's sink, if any. */
- if (pStream->pMixSink->pMixSink)
- rc = AudioMixerSinkCtl(pStream->pMixSink->pMixSink, enmCmd);
- }
- else
- rc = VINF_SUCCESS;
-
- if (RT_FAILURE(rc))
- {
- LogFlowFunc(("Failed with rc=%Rrc\n", rc));
- return rc;
- }
-
- pStream->State.fActive = fActive;
+ HDA_STREAM_REG(pThis, FIFOW, u8Strm) = HDA_SDFIFOW_32B;
+ HDA_STREAM_REG(pThis, LPIB, u8Strm) = 0;
+ HDA_STREAM_REG(pThis, CBL, u8Strm) = 0;
+ HDA_STREAM_REG(pThis, LVI, u8Strm) = 0;
+ HDA_STREAM_REG(pThis, FMT, u8Strm) = 0;
+ HDA_STREAM_REG(pThis, BDPU, u8Strm) = 0;
+ HDA_STREAM_REG(pThis, BDPL, u8Strm) = 0;
- /* Second, see if we need to start or stop the timer. */
- if (!fActive)
- {
- if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */
- pThis->cStreamsActive--;
-
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- hdaTimerMaybeStop(pThis);
-# endif
- }
- else
- {
- pThis->cStreamsActive++;
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- hdaTimerMaybeStart(pThis);
-# endif
- }
+ /*
+ * Third, set the internal state according to the just set registers.
+ */
+ pStrmSt->u8Strm = u8Strm;
+ pStrmSt->u16FIFOS = HDA_STREAM_REG(pThis, FIFOS, u8Strm);
- LogFlowFunc(("u8Strm=%RU8, fActive=%RTbool, cStreamsActive=%RU8\n", pStream->u8SD, fActive, pThis->cStreamsActive));
- return VINF_SUCCESS;
-}
-static void hdaStreamAssignToSink(PHDASTREAM pStream, PHDAMIXERSINK pMixSink)
-{
- AssertPtrReturnVoid(pStream);
+ /* Report that we're done resetting this stream. */
+ HDA_STREAM_REG(pThis, CTL, u8Strm) = 0;
- int rc2 = RTCritSectEnter(&pStream->State.CritSect);
- if (RT_SUCCESS(rc2))
- {
- pStream->pMixSink = pMixSink;
+ LogFunc(("[SD%RU8]: Reset\n", u8Strm));
- rc2 = RTCritSectLeave(&pStream->State.CritSect);
- AssertRC(rc2);
- }
+ /* Exit reset mode. */
+ ASMAtomicXchgBool(&pStrmSt->State.fInReset, false);
}
-# if 0 /** @todo hdaStreamStart is unused */
-static int hdaStreamStart(PHDASTREAM pStream)
+#if 0 // unused
+static int hdaStreamStart(PHDASTREAM pStrmSt)
{
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- ASMAtomicXchgBool(&pStream->State.fDoStop, false);
- ASMAtomicXchgBool(&pStream->State.fActive, true);
+ ASMAtomicXchgBool(&pStrmSt->State.fDoStop, false);
+ ASMAtomicXchgBool(&pStrmSt->State.fActive, true);
LogFlowFuncLeave();
return VINF_SUCCESS;
}
-# endif /* unused */
+#endif
-static int hdaStreamStop(PHDASTREAM pStream)
+static int hdaStreamStop(PHDASTREAM pStrmSt)
{
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
/* Already in stopped state? */
- bool fActive = ASMAtomicReadBool(&pStream->State.fActive);
+ bool fActive = ASMAtomicReadBool(&pStrmSt->State.fActive);
if (!fActive)
return VINF_SUCCESS;
-# if 0 /** @todo Does not work (yet), as EMT deadlocks then. */
+#if 0 /** @todo Does not work (yet), as EMT deadlocks then. */
/*
* Wait for the stream to stop.
*/
- ASMAtomicXchgBool(&pStream->State.fDoStop, true);
+ ASMAtomicXchgBool(&pStrmSt->State.fDoStop, true);
- int rc = hdaStreamWaitForStateChange(pStream, 60 * 1000 /* ms timeout */);
- fActive = ASMAtomicReadBool(&pStream->State.fActive);
+ int rc = hdaStreamWaitForStateChange(pStrmSt, 60 * 1000 /* ms timeout */);
+ fActive = ASMAtomicReadBool(&pStrmSt->State.fActive);
if ( /* Waiting failed? */
RT_FAILURE(rc)
/* Stream is still active? */
@@ -1894,167 +1642,50 @@ static int hdaStreamStop(PHDASTREAM pStream)
{
AssertRC(rc);
LogRel(("HDA: Warning: Unable to stop stream %RU8 (state: %s), rc=%Rrc\n",
- pStream->u8Strm, fActive ? "active" : "stopped", rc));
+ pStrmSt->u8Strm, fActive ? "active" : "stopped", rc));
}
-# else
+#else
int rc = VINF_SUCCESS;
-# endif
+#endif
LogFlowFuncLeaveRC(rc);
return rc;
}
-# if defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND)
-static int hdaStreamChannelExtract(PPDMAUDIOSTREAMCHANNEL pChan, const void *pvBuf, size_t cbBuf)
+#if 0 // unused
+static int hdaStreamWaitForStateChange(PHDASTREAM pStrmSt, RTMSINTERVAL msTimeout)
{
- AssertPtrReturn(pChan, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
-
- AssertRelease(pChan->cbOff <= cbBuf);
-
- const uint8_t *pu8Buf = (const uint8_t *)pvBuf;
-
- size_t cbSrc = cbBuf - pChan->cbOff;
- const uint8_t *pvSrc = &pu8Buf[pChan->cbOff];
-
- size_t cbDst;
- uint8_t *pvDst;
- RTCircBufAcquireWriteBlock(pChan->Data.pCircBuf, cbBuf, (void **)&pvDst, &cbDst);
-
- cbSrc = RT_MIN(cbSrc, cbDst);
-
- while (cbSrc)
- {
- AssertBreak(cbDst >= cbSrc);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- /* Enough data for at least one next frame? */
- if (cbSrc < pChan->cbFrame)
- break;
-
- memcpy(pvDst, pvSrc, pChan->cbFrame);
-
- /* Advance to next channel frame in stream. */
- pvSrc += pChan->cbStep;
- Assert(cbSrc >= pChan->cbStep);
- cbSrc -= pChan->cbStep;
-
- /* Advance destination by one frame. */
- pvDst += pChan->cbFrame;
- Assert(cbDst >= pChan->cbFrame);
- cbDst -= pChan->cbFrame;
-
- /* Adjust offset. */
- pChan->cbOff += pChan->cbFrame;
- }
+ LogFlowFunc(("[SD%RU8]: msTimeout=%RU32\n", pStrmSt->u8Strm, msTimeout));
+ return RTSemEventWait(pStrmSt->State.hStateChangedEvent, msTimeout);
+}
+#endif
+#endif /* IN_RING3 */
- RTCircBufReleaseWriteBlock(pChan->Data.pCircBuf, cbDst);
+/* Register access handlers. */
+static int hdaRegReadUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
+{
+ RT_NOREF(pThis, iReg);
+ *pu32Value = 0;
return VINF_SUCCESS;
}
-# endif /* defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND) */
-# if 0 /** @todo hdaStreamChannelAdvance is unused */
-static int hdaStreamChannelAdvance(PPDMAUDIOSTREAMCHANNEL pChan, size_t cbAdv)
+static int hdaRegWriteUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- AssertPtrReturn(pChan, VERR_INVALID_POINTER);
-
- if (!cbAdv)
- return VINF_SUCCESS;
-
+ RT_NOREF(pThis, iReg, u32Value);
return VINF_SUCCESS;
}
-# endif
-static int hdaStreamChannelDataInit(PPDMAUDIOSTREAMCHANNELDATA pChanData, uint32_t fFlags)
+/* U8 */
+static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
{
- int rc = RTCircBufCreate(&pChanData->pCircBuf, 256); /** @todo Make this configurable? */
- if (RT_SUCCESS(rc))
- {
- pChanData->fFlags = fFlags;
- }
-
- return rc;
+ Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].mem_idx] & g_aHdaRegMap[iReg].readable) & 0xffffff00) == 0);
+ return hdaRegReadU32(pThis, iReg, pu32Value);
}
-/**
- * Frees a stream channel data block again.
- *
- * @param pChanData Pointer to channel data to free.
- */
-static void hdaStreamChannelDataDestroy(PPDMAUDIOSTREAMCHANNELDATA pChanData)
-{
- if (!pChanData)
- return;
-
- if (pChanData->pCircBuf)
- {
- RTCircBufDestroy(pChanData->pCircBuf);
- pChanData->pCircBuf = NULL;
- }
-
- pChanData->fFlags = PDMAUDIOSTREAMCHANNELDATA_FLAG_NONE;
-}
-
-# if defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND)
-
-static int hdaStreamChannelAcquireData(PPDMAUDIOSTREAMCHANNELDATA pChanData, void *pvData, size_t *pcbData)
-{
- AssertPtrReturn(pChanData, VERR_INVALID_POINTER);
- AssertPtrReturn(pvData, VERR_INVALID_POINTER);
- AssertPtrReturn(pcbData, VERR_INVALID_POINTER);
-
- RTCircBufAcquireReadBlock(pChanData->pCircBuf, 256 /** @todo Make this configurarble? */, &pvData, &pChanData->cbAcq);
-
- *pcbData = pChanData->cbAcq;
- return VINF_SUCCESS;
-}
-
-static int hdaStreamChannelReleaseData(PPDMAUDIOSTREAMCHANNELDATA pChanData)
-{
- AssertPtrReturn(pChanData, VERR_INVALID_POINTER);
- RTCircBufReleaseReadBlock(pChanData->pCircBuf, pChanData->cbAcq);
-
- return VINF_SUCCESS;
-}
-
-# endif /* defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND) */
-
-# if 0 /* currently unused */
-static int hdaStreamWaitForStateChange(PHDASTREAM pStream, RTMSINTERVAL msTimeout)
-{
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- LogFlowFunc(("[SD%RU8]: msTimeout=%RU32\n", pStream->u8SD, msTimeout));
- return RTSemEventWait(pStream->State.hStateChangedEvent, msTimeout);
-}
-# endif /* currently unused */
-
-#endif /* IN_RING3 */
-
-/* Register access handlers. */
-
-static int hdaRegReadUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg);
- *pu32Value = 0;
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
- return VINF_SUCCESS;
-}
-
-/* U8 */
-static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].mem_idx] & g_aHdaRegMap[iReg].readable) & 0xffffff00) == 0);
- return hdaRegReadU32(pThis, iReg, pu32Value);
-}
-
-static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
+static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
Assert((u32Value & 0xffffff00) == 0);
return hdaRegWriteU32(pThis, iReg, u32Value);
@@ -2080,13 +1711,11 @@ static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
return hdaRegReadU32(pThis, iReg, pu32Value);
}
-#ifdef IN_RING3
static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
Assert((u32Value & 0xff000000) == 0);
return hdaRegWriteU32(pThis, iReg, u32Value);
}
-#endif
/* U32 */
static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
@@ -2108,8 +1737,7 @@ static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- RT_NOREF_PV(iReg);
-
+ RT_NOREF(iReg);
if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, RST))
{
/* Set the CRST bit to indicate that we're leaving reset mode. */
@@ -2117,7 +1745,7 @@ static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
if (pThis->fInReset)
{
- LogFunc(("Guest leaving HDA reset\n"));
+ LogFunc(("Leaving reset\n"));
pThis->fInReset = false;
}
}
@@ -2125,20 +1753,24 @@ static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
#ifdef IN_RING3
/* Enter reset state. */
- LogFunc(("Guest entering HDA reset with DMA(RIRB:%s, CORB:%s)\n",
- HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) ? "on" : "off",
- HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA) ? "on" : "off"));
+ if ( HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)
+ || HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA))
+ {
+ LogFunc(("Entering reset with DMA(RIRB:%s, CORB:%s)\n",
+ HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) ? "on" : "off",
+ HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA) ? "on" : "off"));
+ }
- /* Clear the CRST bit to indicate that we're in reset state. */
+ /* Clear the CRST bit to indicate that we're in reset mode. */
HDA_REG(pThis, GCTL) &= ~HDA_REG_FIELD_FLAG_MASK(GCTL, RST);
pThis->fInReset = true;
+ /* As the CRST bit now is set, we now can proceed resetting stuff. */
hdaReset(pThis->CTX_SUFF(pDevIns));
#else
return VINF_IOM_R3_MMIO_WRITE;
#endif
}
-
if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, FSH))
{
/* Flush: GSTS:1 set, see 6.2.6. */
@@ -2160,8 +1792,7 @@ static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value
static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
{
- RT_NOREF_PV(iReg);
-
+ RT_NOREF(iReg);
uint32_t v = 0;
if ( HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RIRBOIS)
|| HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RINTFL)
@@ -2171,30 +1802,26 @@ static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
v |= RT_BIT(30); /* Touch CIS. */
}
-#define HDA_MARK_STREAM(x) \
- if (/* Descriptor Error */ \
- (SDSTS((pThis), x) & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE)) \
- /* FIFO Error */ \
- || (SDSTS((pThis), x) & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE)) \
- /* Buffer Completion Interrupt Status */ \
- || (SDSTS((pThis), x) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS))) \
- { \
- Log3Func(("[SD%RU8] BCIS: Marked\n", x)); \
- v |= RT_BIT(x); \
- }
+#define HDA_IS_STREAM_EVENT(pThis, num) \
+ ( (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE)) \
+ || (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE)) \
+ || (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
- HDA_MARK_STREAM(0);
- HDA_MARK_STREAM(1);
- HDA_MARK_STREAM(2);
- HDA_MARK_STREAM(3);
- HDA_MARK_STREAM(4);
- HDA_MARK_STREAM(5);
- HDA_MARK_STREAM(6);
- HDA_MARK_STREAM(7);
+#define HDA_MARK_STREAM(pThis, num, v) \
+ do { (v) |= HDA_IS_STREAM_EVENT((pThis), num) ? RT_BIT((num)) : 0; } while(0)
+ HDA_MARK_STREAM(pThis, 0, v);
+ HDA_MARK_STREAM(pThis, 1, v);
+ HDA_MARK_STREAM(pThis, 2, v);
+ HDA_MARK_STREAM(pThis, 3, v);
+ HDA_MARK_STREAM(pThis, 4, v);
+ HDA_MARK_STREAM(pThis, 5, v);
+ HDA_MARK_STREAM(pThis, 6, v);
+ HDA_MARK_STREAM(pThis, 7, v);
+
+#undef HDA_IS_STREAM_EVENT
#undef HDA_MARK_STREAM
- /* "OR" bit of all interrupt status bits. */
v |= v ? RT_BIT(31) : 0;
*pu32Value = v;
@@ -2204,8 +1831,9 @@ static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
static int hdaRegReadLPIB(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
{
const uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, LPIB, iReg);
- uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, u8Strm);
-#ifdef LOG_ENABLED
+ uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, u8Strm);
+
+#if defined(LOG_ENABLED)
const uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, u8Strm);
LogFlowFunc(("[SD%RU8]: LPIB=%RU32, CBL=%RU32\n", u8Strm, u32LPIB, u32CBL));
#endif
@@ -2216,8 +1844,7 @@ static int hdaRegReadLPIB(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
{
- RT_NOREF_PV(iReg);
-
+ RT_NOREF(iReg);
/* HDA spec (1a): 3.3.16 WALCLK counter ticks with 24Mhz bitclock rate. */
*pu32Value = (uint32_t)ASMMultU64ByU32DivByU32(PDMDevHlpTMTimeVirtGetNano(pThis->CTX_SUFF(pDevIns))
- pThis->u64BaseTS, 24, 1000);
@@ -2225,30 +1852,9 @@ static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
return VINF_SUCCESS;
}
-#if 0 /** @todo hdaRegReadSSYNC & hdaRegWriteSSYNC are unused */
-
-static int hdaRegReadSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- RT_NOREF_PV(iReg);
-
- /* HDA spec (1a): 3.3.16 WALCLK counter ticks with 24Mhz bitclock rate. */
- *pu32Value = HDA_REG(pThis, SSYNC);
- LogFlowFunc(("%RU32\n", *pu32Value));
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteSSYNC(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- LogFlowFunc(("%RU32\n", u32Value));
- return hdaRegWriteU32(pThis, iReg, u32Value);
-}
-
-#endif /* unused */
-
static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- RT_NOREF_PV(iReg);
-
+ RT_NOREF(iReg);
if (u32Value & HDA_REG_FIELD_FLAG_MASK(CORBRP, RST))
{
HDA_REG(pThis, CORBRP) = 0;
@@ -2272,15 +1878,14 @@ static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
}
return rc;
#else
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
+ RT_NOREF(pThis, iReg, u32Value);
return VINF_IOM_R3_MMIO_WRITE;
#endif
}
static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- RT_NOREF_PV(iReg);
-
+ RT_NOREF(iReg);
uint32_t v = HDA_REG(pThis, CORBSTS);
HDA_REG(pThis, CORBSTS) &= ~(v & u32Value);
return VINF_SUCCESS;
@@ -2299,236 +1904,179 @@ static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
return VINF_SUCCESS;
rc = hdaCORBCmdProcess(pThis);
return rc;
-#else /* !IN_RING3 */
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
+#else
+ RT_NOREF(pThis, iReg, u32Value);
return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
+#endif
}
static int hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
-#ifdef IN_RING3
- if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
- return VINF_SUCCESS;
-
- PHDASTREAM pStream = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, CBL, iReg));
- if (!pStream)
+ int rc = hdaRegWriteU32(pThis, iReg, u32Value);
+ if (RT_SUCCESS(rc))
{
- LogFunc(("[SD%RU8]: Warning: Changing SDCBL on non-attached stream (0x%x)\n", HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), u32Value));
- return hdaRegWriteU32(pThis, iReg, u32Value);
- }
-
- int rc2 = hdaRegWriteSDLock(pThis, pStream, iReg, u32Value);
- AssertRC(rc2);
+ uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, CBL, iReg);
- pStream->u32CBL = u32Value;
-
- /* Reset BDLE state. */
- RT_ZERO(pStream->State.BDLE);
- pStream->State.uCurBDLE = 0;
+ PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
+ if (pStrmSt)
+ {
+ pStrmSt->u32CBL = u32Value;
- rc2 = hdaRegWriteU32(pThis, iReg, u32Value);
- AssertRC(rc2);
+ /* Reset BDLE state. */
+ RT_ZERO(pStrmSt->State.BDLE);
+ pStrmSt->State.uCurBDLE = 0;
+ }
- LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", pStream->u8SD, u32Value));
- hdaRegWriteSDUnlock(pStream);
+ LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", u8Strm, u32Value));
+ }
+ else
+ AssertRCReturn(rc, VINF_SUCCESS);
- return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-#else /* !IN_RING3 */
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
- return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
+ return rc;
}
static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
-#ifdef IN_RING3
- bool fRun = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
- bool fInRun = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
-
- bool fReset = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
- bool fInReset = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
-
- if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
- return VINF_SUCCESS; /* Always return success to the MMIO handler. */
+#if defined(LOG_ENABLED) || defined(IN_RING3)
+ bool const fRun = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+ bool const fInRun = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+#endif
+ bool const fReset = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
+ bool const fInReset = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
- /* Get the stream descriptor. */
- uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
+ uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
- /*
- * Extract the stream tag the guest wants to use for this specific
- * stream descriptor (SDn). This only can happen if the stream is in a non-running
- * state, so we're doing the lookup and assignment here.
- *
- * So depending on the guest OS, SD3 can use stream tag 4, for example.
- */
- uint8_t uTag = (u32Value >> HDA_SDCTL_NUM_SHIFT) & HDA_SDCTL_NUM_MASK;
- if (uTag > HDA_MAX_TAGS)
+ PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
+ if (!pStrmSt)
{
- LogFunc(("[SD%RU8]: Warning: Invalid stream tag %RU8 specified!\n", uSD, uTag));
- return hdaRegWriteU24(pThis, iReg, u32Value);
+ LogFunc(("Warning: Changing SDCTL on non-attached stream with ID=%RU8 (iReg=0x%x)\n", u8Strm, iReg));
+ return hdaRegWriteU24(pThis, iReg, u32Value); /* Write 3 bytes. */
}
- PHDATAG pTag = &pThis->aTags[uTag];
- AssertPtr(pTag);
-
- LogFunc(("[SD%RU8]: Using stream tag=%RU8\n", uSD, uTag));
-
- /* Assign new values. */
- pTag->uTag = uTag;
- pTag->pStrm = hdaStreamFromSD(pThis, uSD);
-
- PHDASTREAM pStream = pTag->pStrm;
- AssertPtr(pStream);
-
- /* Note: Do not use hdaRegWriteSDLock() here, as SDnCTL might change the RUN bit. */
- int rc2 = RTCritSectEnter(&pStream->State.CritSect);
- AssertRC(rc2);
-
LogFunc(("[SD%RU8]: fRun=%RTbool, fInRun=%RTbool, fReset=%RTbool, fInReset=%RTbool, %R[sdctl]\n",
- uSD, fRun, fInRun, fReset, fInReset, u32Value));
+ u8Strm, fRun, fInRun, fReset, fInReset, u32Value));
if (fInReset)
{
+ /* Guest is resetting HDA's stream, we're expecting guest will mark stream as exit. */
Assert(!fReset);
- Assert(!fInRun && !fRun);
-
- /* Report that we're done resetting this stream by clearing SRST. */
- HDA_STREAM_REG(pThis, CTL, uSD) &= ~HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST);
-
- LogFunc(("[SD%RU8]: Guest initiated exit of stream reset\n", uSD));
+ LogFunc(("Guest initiated exit of stream reset\n"));
}
else if (fReset)
{
+#ifdef IN_RING3
/* ICH6 datasheet 18.2.33 says that RUN bit should be cleared before initiation of reset. */
Assert(!fInRun && !fRun);
- LogFunc(("[SD%RU8]: Guest initiated enter to stream reset\n", pStream->u8SD));
- hdaStreamReset(pThis, pStream);
+ LogFunc(("Guest initiated enter to stream reset\n"));
+ hdaStreamReset(pThis, pStrmSt, u8Strm);
+#else
+ return VINF_IOM_R3_MMIO_WRITE;
+#endif
}
else
{
+#ifdef IN_RING3
/*
* We enter here to change DMA states only.
*/
if (fInRun != fRun)
{
Assert(!fReset && !fInReset);
- LogFunc(("[SD%RU8]: fRun=%RTbool\n", pStream->u8SD, fRun));
-
- hdaStreamSetActive(pThis, pStream, fRun);
+ LogFunc(("[SD%RU8]: fRun=%RTbool\n", u8Strm, fRun));
- if (fRun)
+ PHDADRIVER pDrv;
+ switch (u8Strm)
{
- /* (Re-)Fetch the current BDLE entry. */
- rc2 = hdaBDLEFetch(pThis, &pStream->State.BDLE, pStream->u64BDLBase, pStream->State.uCurBDLE);
- AssertRC(rc2);
+ case 0: /** @todo Use a variable here. Later. */
+ {
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+ pDrv->LineIn.pStrmIn, fRun);
+ break;
+ }
+# ifdef VBOX_WITH_HDA_MIC_IN
+ case 2: /** @todo Use a variable here. Later. */
+ {
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+ pDrv->MicIn.pStrmIn, fRun);
+ break;
+ }
+# endif
+ case 4: /** @todo Use a variable here. Later. */
+ {
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
+ pDrv->Out.pStrmOut, fRun);
+ break;
+ }
+ default:
+ AssertMsgFailed(("Changing RUN bit on non-attached stream, register %RU32\n", iReg));
+ break;
}
}
if (!fInRun && !fRun)
- hdaStreamInit(pThis, pStream, pStream->u8SD);
- }
-
- /* Make sure to handle interrupts here as well. */
- hdaProcessInterrupt(pThis);
+ hdaStreamInit(pThis, pStrmSt, u8Strm);
- rc2 = hdaRegWriteU24(pThis, iReg, u32Value);
- AssertRC(rc2);
+#else /* IN_RING3 */
+ return VINF_IOM_R3_MMIO_WRITE;
+#endif /* !IN_RING3 */
+ }
- hdaRegWriteSDUnlock(pStream);
- return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-#else /* !IN_RING3 */
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
- return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
+ return hdaRegWriteU24(pThis, iReg, u32Value);
}
static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- uint32_t v = HDA_REG_IND(pThis, iReg);
- /* Clear (zero) FIFOE and DESE bits when writing 1 to it. */
- v &= ~(u32Value & v);
-
+ uint32_t v = HDA_REG_IND(pThis, iReg);
+ v &= ~(u32Value & v);
HDA_REG_IND(pThis, iReg) = v;
-
hdaProcessInterrupt(pThis);
return VINF_SUCCESS;
}
static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
-#ifdef IN_RING3
- if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
+ if (!hdaRegWriteSDIsAllowed(pThis, iReg, u32Value))
return VINF_SUCCESS;
- PHDASTREAM pStream = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, LVI, iReg));
- if (!pStream)
+ int rc = hdaRegWriteU16(pThis, iReg, u32Value);
+ if (RT_SUCCESS(rc))
{
- LogFunc(("[SD%RU8]: Warning: Changing SDLVI on non-attached stream (0x%x)\n", HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), u32Value));
- return hdaRegWriteU16(pThis, iReg, u32Value);
- }
-
- int rc2 = hdaRegWriteSDLock(pThis, pStream, iReg, u32Value);
- AssertRC(rc2);
-
- /** @todo Validate LVI. */
- pStream->u16LVI = u32Value;
+ uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, LVI, iReg);
- /* Reset BDLE state. */
- RT_ZERO(pStream->State.BDLE);
- pStream->State.uCurBDLE = 0;
-
- rc2 = hdaRegWriteU16(pThis, iReg, u32Value);
- AssertRC(rc2);
+ PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
+ if (pStrmSt)
+ {
+ pStrmSt->u16LVI = u32Value;
- LogFlowFunc(("[SD%RU8]: LVI=%RU32\n", pStream->u8SD, u32Value));
- hdaRegWriteSDUnlock(pStream);
+ /* Reset BDLE state. */
+ RT_ZERO(pStrmSt->State.BDLE);
+ pStrmSt->State.uCurBDLE = 0;
+ }
- return VINF_SUCCESS; /* Always return success to the MMIO handler. */
+ LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", u8Strm, u32Value));
+ }
+ else
+ AssertRCReturn(rc, VINF_SUCCESS);
-#else /* !IN_RING3 */
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
- return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
+ return rc;
}
-#if 0 /** @todo hdaRegWriteSDFIFOW & hdaRegWriteSDFIFOS are unused */
static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, FIFOW, iReg);
- /** @todo Only allow updating FIFOS if RUN bit is 0? */
- uint32_t u32FIFOW = 0;
-
- if (hdaGetDirFromSD(uSD) != PDMAUDIODIR_IN) /* FIFOW for input streams only. */
- {
- LogRel(("HDA: Warning: Guest tried to write read-only FIFOW to stream #%RU8, ignoring\n", uSD));
- return VINF_SUCCESS;
- }
-
switch (u32Value)
{
case HDA_SDFIFOW_8B:
case HDA_SDFIFOW_16B:
case HDA_SDFIFOW_32B:
- u32FIFOW = u32Value;
- break;
+ return hdaRegWriteU16(pThis, iReg, u32Value);
default:
- LogRel(("HDA: Warning: Guest tried write unsupported FIFOW (0x%x) to stream #%RU8, defaulting to 32 bytes\n",
- u32Value, uSD));
- u32FIFOW = HDA_SDFIFOW_32B;
- break;
- }
-
- if (u32FIFOW)
- {
- LogFunc(("[SD%RU8]: Updating FIFOW to %RU32 bytes\n", uSD, hdaSDFIFOSToBytes(u32FIFOW)));
- /** @todo Update internal stream state with new FIFOS. */
-
- return hdaRegWriteU16(pThis, iReg, u32FIFOW);
+ LogFunc(("Attempt to store unsupported value(%x) in SDFIFOW\n", u32Value));
+ return hdaRegWriteU16(pThis, iReg, HDA_SDFIFOW_32B);
}
-
- return VINF_SUCCESS; /* Never reached. */
}
/**
@@ -2537,40 +2085,55 @@ static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
*/
static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- uint8_t uSD = HDA_SD_NUM_FROM_REG(pThis, FIFOS, iReg);
/** @todo Only allow updating FIFOS if RUN bit is 0? */
uint32_t u32FIFOS = 0;
- if (hdaGetDirFromSD(uSD) != PDMAUDIODIR_OUT) /* FIFOS for output streams only. */
- {
- LogRel(("HDA: Warning: Guest tried to write read-only FIFOS to stream #%RU8, ignoring\n", uSD));
- return VINF_SUCCESS;
- }
-
- switch(u32Value)
+ switch (iReg)
{
- case HDA_SDOFIFO_16B:
- case HDA_SDOFIFO_32B:
- case HDA_SDOFIFO_64B:
- case HDA_SDOFIFO_128B:
- case HDA_SDOFIFO_192B:
- u32FIFOS = u32Value;
+ /* SDInFIFOS is RO, n=0-3. */
+ case HDA_REG_SD0FIFOS:
+ case HDA_REG_SD1FIFOS:
+ case HDA_REG_SD2FIFOS:
+ case HDA_REG_SD3FIFOS:
+ {
+ LogFunc(("Guest tries to change R/O value of FIFO size of input stream, ignoring\n"));
break;
+ }
+ case HDA_REG_SD4FIFOS:
+ case HDA_REG_SD5FIFOS:
+ case HDA_REG_SD6FIFOS:
+ case HDA_REG_SD7FIFOS:
+ {
+ switch(u32Value)
+ {
+ case HDA_SDONFIFO_16B:
+ case HDA_SDONFIFO_32B:
+ case HDA_SDONFIFO_64B:
+ case HDA_SDONFIFO_128B:
+ case HDA_SDONFIFO_192B:
+ u32FIFOS = u32Value;
+ break;
+
+ case HDA_SDONFIFO_256B: /** @todo r=andy Investigate this. */
+ LogFunc(("256-bit is unsupported, HDA is switched into 192-bit mode\n"));
+ /* Fall through is intentional. */
+ default:
+ u32FIFOS = HDA_SDONFIFO_192B;
+ break;
+ }
- case HDA_SDOFIFO_256B: /** @todo r=andy Investigate this. */
- LogFunc(("256-bit is unsupported, HDA is switched into 192-bit mode\n"));
- /* Fall through is intentional. */
+ break;
+ }
default:
- LogRel(("HDA: Warning: Guest tried write unsupported FIFOS (0x%x) to stream #%RU8, defaulting to 192 bytes\n",
- u32Value, uSD));
- u32FIFOS = HDA_SDOFIFO_192B;
+ {
+ AssertMsgFailed(("Something weird happened with register lookup routine\n"));
break;
+ }
}
if (u32FIFOS)
{
- LogFunc(("[SD%RU8]: Updating FIFOS to %RU32 bytes\n",
- HDA_SD_NUM_FROM_REG(pThis, FIFOS, iReg), hdaSDFIFOSToBytes(u32FIFOS)));
+ LogFunc(("[SD%RU8]: Updating FIFOS to %RU32 bytes\n", 0, hdaSDFIFOSToBytes(u32FIFOS)));
/** @todo Update internal stream state with new FIFOS. */
return hdaRegWriteU16(pThis, iReg, u32FIFOS);
@@ -2579,19 +2142,16 @@ static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
return VINF_SUCCESS;
}
-#endif /* unused */
-
-#ifdef IN_RING3
-static int hdaSDFMTToStrmCfg(uint32_t u32SDFMT, PPDMAUDIOSTREAMCFG pStrmCfg)
+#if defined(IN_RING3) && defined(VBOX_WITH_HDA_CODEC_EMU)
+static int hdaSDFMTToStrmCfg(uint32_t u32SDFMT, PPDMAUDIOSTREAMCFG pCfg)
{
- AssertPtrReturn(pStrmCfg, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
# define EXTRACT_VALUE(v, mask, shift) ((v & ((mask) << (shift))) >> (shift))
int rc = VINF_SUCCESS;
- uint32_t u32Hz = EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BASE_RATE_MASK, HDA_SDFMT_BASE_RATE_SHIFT)
- ? 44100 : 48000;
+ uint32_t u32Hz = (u32SDFMT & HDA_SDFMT_BASE_RATE_SHIFT) ? 44100 : 48000;
uint32_t u32HzMult = 1;
uint32_t u32HzDiv = 1;
@@ -2624,350 +2184,121 @@ static int hdaSDFMTToStrmCfg(uint32_t u32SDFMT, PPDMAUDIOSTREAMCFG pStrmCfg)
break;
}
- PDMAUDIOFMT enmFmt;
+ PDMAUDIOFMT enmFmt = AUD_FMT_S16; /* Default to 16-bit signed. */
switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT))
{
case 0:
- enmFmt = PDMAUDIOFMT_S8;
+ LogFunc(("Requested 8-bit\n"));
+ enmFmt = AUD_FMT_S8;
break;
case 1:
- enmFmt = PDMAUDIOFMT_S16;
+ LogFunc(("Requested 16-bit\n"));
+ enmFmt = AUD_FMT_S16;
+ break;
+ case 2:
+ LogFunc(("Requested 20-bit\n"));
+ break;
+ case 3:
+ LogFunc(("Requested 24-bit\n"));
break;
case 4:
- enmFmt = PDMAUDIOFMT_S32;
+ LogFunc(("Requested 32-bit\n"));
+ enmFmt = AUD_FMT_S32;
break;
default:
- AssertMsgFailed(("Unsupported bits per sample %x\n",
+ AssertMsgFailed(("Unsupported bits shift %x\n",
EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT)));
- enmFmt = PDMAUDIOFMT_INVALID;
rc = VERR_NOT_SUPPORTED;
break;
}
if (RT_SUCCESS(rc))
{
- pStrmCfg->uHz = u32Hz * u32HzMult / u32HzDiv;
- pStrmCfg->cChannels = (u32SDFMT & 0xf) + 1;
- pStrmCfg->enmFormat = enmFmt;
- pStrmCfg->enmEndianness = PDMAUDIOHOSTENDIANNESS;
+ pCfg->uHz = u32Hz * u32HzMult / u32HzDiv;
+ pCfg->cChannels = (u32SDFMT & 0xf) + 1;
+ pCfg->enmFormat = enmFmt;
+ pCfg->enmEndianness = PDMAUDIOHOSTENDIANNESS;
}
# undef EXTRACT_VALUE
+
+ LogFlowFuncLeaveRC(rc);
return rc;
}
+#endif
-static int hdaAddStreamOut(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
+static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
-
- LogFlowFunc(("Stream=%s\n", pCfg->szName));
-
- int rc = VINF_SUCCESS;
-
- bool fUseFront = true; /* Always use front out by default. */
-#ifdef VBOX_WITH_HDA_51_SURROUND
- bool fUseRear;
- bool fUseCenter;
- bool fUseLFE;
+#ifdef IN_RING3
+# ifdef VBOX_WITH_HDA_CODEC_EMU
+ /* No reason to re-open stream with same settings. */
+ if (u32Value == HDA_REG_IND(pThis, iReg))
+ return VINF_SUCCESS;
- fUseRear = fUseCenter = fUseLFE = false;
+ PDMAUDIOSTREAMCFG strmCfg;
+ int rc = hdaSDFMTToStrmCfg(u32Value, &strmCfg);
+ if (RT_FAILURE(rc))
+ return VINF_SUCCESS; /* Always return success to the MMIO handler. */
- /*
- * Use commonly used setups for speaker configurations.
- */
+ uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, FMT, iReg);
- /** @todo Make the following configurable through mixer API and/or CFGM? */
- switch (pCfg->cChannels)
+ PHDADRIVER pDrv;
+ switch (iReg)
{
- case 3: /* 2.1: Front (Stereo) + LFE. */
- {
- fUseLFE = true;
- break;
- }
-
- case 4: /* Quadrophonic: Front (Stereo) + Rear (Stereo). */
- {
- fUseRear = true;
+ case HDA_REG_SD0FMT:
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ rc = hdaCodecOpenStream(pThis->pCodec, PI_INDEX, &strmCfg);
break;
- }
-
- case 5: /* 4.1: Front (Stereo) + Rear (Stereo) + LFE. */
- {
- fUseRear = true;
- fUseLFE = true;
+# ifdef VBOX_WITH_HDA_MIC_IN
+ case HDA_REG_SD2FMT:
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ rc = hdaCodecOpenStream(pThis->pCodec, MC_INDEX, &strmCfg);
break;
- }
-
- case 6: /* 5.1: Front (Stereo) + Rear (Stereo) + Center/LFE. */
- {
- fUseRear = true;
- fUseCenter = true;
- fUseLFE = true;
+# endif
+ case HDA_REG_SD4FMT:
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ rc = hdaCodecOpenStream(pThis->pCodec, PO_INDEX, &strmCfg);
break;
- }
-
- default: /* Unknown; fall back to 2 front channels (stereo). */
- {
- rc = VERR_NOT_SUPPORTED;
+ default:
+ LogFunc(("Warning: Changing SDFMT on non-attached stream with ID=%RU8 (iReg=0x%x)\n", u8Strm, iReg));
break;
- }
- }
-#else /* !VBOX_WITH_HDA_51_SURROUND */
- /* Only support mono or stereo channels. */
- if ( pCfg->cChannels != 1 /* Mono */
- && pCfg->cChannels != 2 /* Stereo */)
- {
- rc = VERR_NOT_SUPPORTED;
}
-#endif
- if (rc == VERR_NOT_SUPPORTED)
- {
- LogRel(("HDA: Unsupported channel count (%RU8), falling back to stereo channels\n", pCfg->cChannels));
- pCfg->cChannels = 2;
+ /** @todo r=andy rc gets lost; needs fixing. */
+ return hdaRegWriteU16(pThis, iReg, u32Value);
+# else /* !VBOX_WITH_HDA_CODEC_EMU */
+ return hdaRegWriteU16(pThis, iReg, u32Value);
+# endif
+#else /* !IN_RING3 */
+ RT_NOREF(pThis, iReg, u32Value);
+ return VINF_IOM_R3_MMIO_WRITE;
+#endif
+}
- rc = VINF_SUCCESS;
- }
+/* Note: Will be called for both, BDPL and BDPU, registers. */
+DECLINLINE(int) hdaRegWriteSDBDPX(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value, uint8_t u8Strm)
+{
+ if (!hdaRegWriteSDIsAllowed(pThis, iReg, u32Value))
+ return VINF_SUCCESS;
- do
+ int rc = hdaRegWriteU32(pThis, iReg, u32Value);
+ if (RT_SUCCESS(rc))
{
- if (RT_FAILURE(rc))
- break;
-
- if (fUseFront)
+ PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
+ if (pStrmSt)
{
- RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Front");
- pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
- pCfg->cChannels = 2;
-
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_FRONT);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_FRONT, pCfg);
+ pStrmSt->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
+ HDA_STREAM_REG(pThis, BDPU, u8Strm));
+ /* Reset BDLE state. */
+ RT_ZERO(pStrmSt->State.BDLE);
+ pStrmSt->State.uCurBDLE = 0;
}
+ }
+ else
+ AssertRCReturn(rc, VINF_SUCCESS);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- if ( RT_SUCCESS(rc)
- && (fUseCenter || fUseLFE))
- {
- RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Center/LFE");
- pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_CENTER_LFE;
- pCfg->cChannels = (fUseCenter && fUseLFE) ? 2 : 1;
-
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_CENTER_LFE, pCfg);
- }
-
- if ( RT_SUCCESS(rc)
- && fUseRear)
- {
- RTStrPrintf(pCfg->szName, RT_ELEMENTS(pCfg->szName), "Rear");
- pCfg->DestSource.Dest = PDMAUDIOPLAYBACKDEST_REAR;
- pCfg->cChannels = 2;
-
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_REAR);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_REAR, pCfg);
- }
-#endif /* VBOX_WITH_HDA_51_SURROUND */
-
- } while (0);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static int hdaAddStreamIn(PHDASTATE pThis, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- AssertReturn(pCfg->enmDir == PDMAUDIODIR_IN, VERR_INVALID_PARAMETER);
-
- LogFlowFunc(("Stream=%s, Source=%ld\n", pCfg->szName, pCfg->DestSource.Source));
-
- int rc;
-
- switch (pCfg->DestSource.Source)
- {
- case PDMAUDIORECSOURCE_LINE:
- {
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_LINE_IN);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_LINE_IN, pCfg);
- break;
- }
-#ifdef VBOX_WITH_HDA_MIC_IN
- case PDMAUDIORECSOURCE_MIC:
- {
- rc = hdaCodecRemoveStream(pThis->pCodec, PDMAUDIOMIXERCTL_MIC_IN);
- if (RT_SUCCESS(rc))
- rc = hdaCodecAddStream(pThis->pCodec, PDMAUDIOMIXERCTL_MIC_IN, pCfg);
- break;
- }
-#endif
- default:
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- LogFlowFuncLeaveRC(rc);
return rc;
}
-#endif /* IN_RING3 */
-
-static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-#ifdef IN_RING3
- PDMAUDIOSTREAMCFG strmCfg;
- RT_ZERO(strmCfg);
-
- int rc = hdaSDFMTToStrmCfg(u32Value, &strmCfg);
- if (RT_FAILURE(rc))
- return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-
- PHDASTREAM pStream = hdaStreamFromSD(pThis, HDA_SD_NUM_FROM_REG(pThis, FMT, iReg));
- if (!pStream)
- {
- LogFunc(("[SD%RU8]: Warning: Changing SDFMT on non-attached stream (0x%x)\n",
- HDA_SD_NUM_FROM_REG(pThis, FMT, iReg), u32Value));
- return hdaRegWriteU16(pThis, iReg, u32Value);
- }
-
- int rcSem = hdaRegWriteSDLock(pThis, pStream, iReg, u32Value);
- AssertRC(rcSem);
-
- LogFunc(("[SD%RU8]: Hz=%RU32, Channels=%RU8, enmFmt=%RU32\n",
- pStream->u8SD, strmCfg.uHz, strmCfg.cChannels, strmCfg.enmFormat));
-
- /* Set audio direction. */
- strmCfg.enmDir = hdaGetDirFromSD(pStream->u8SD);
- switch (strmCfg.enmDir)
- {
- case PDMAUDIODIR_IN:
-# ifdef VBOX_WITH_HDA_MIC_IN
-# error "Implement me!"
-# else
- strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
- RTStrCopy(strmCfg.szName, sizeof(strmCfg.szName), "Line In");
-# endif
- break;
-
- case PDMAUDIODIR_OUT:
- /* Destination(s) will be set in hdaAddStreamOut(),
- * based on the channels / stream layout. */
- break;
-
- default:
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- /*
- * Initialize the stream mapping in any case, regardless if
- * we support surround audio or not. This is needed to handle
- * the supported channels within a single audio stream, e.g. mono/stereo.
- *
- * In other words, the stream mapping *always* knowns the real
- * number of channels in a single audio stream.
- */
- if (RT_SUCCESS(rc))
- {
- rc = hdaStreamMapInit(&pStream->State.Mapping, &strmCfg);
- AssertRC(rc);
- }
-
- if (RT_SUCCESS(rc))
- {
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- int rc2;
- switch (strmCfg.enmDir)
- {
- case PDMAUDIODIR_OUT:
- rc2 = hdaAddStreamOut(pThis, &strmCfg);
- break;
-
- case PDMAUDIODIR_IN:
- rc2 = hdaAddStreamIn(pThis, &strmCfg);
- break;
-
- default:
- rc2 = VERR_NOT_SUPPORTED;
- AssertFailed();
- break;
- }
-
- if ( RT_FAILURE(rc2)
- && (pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY)) /* We only care about primary drivers here, the rest may fail. */
- {
- if (RT_SUCCESS(rc))
- rc = rc2;
- /* Keep going. */
- }
- }
-
- /* If (re-)opening the stream by the codec above failed, don't write the new
- * format to the register so that the guest is aware it didn't work. */
- if (RT_SUCCESS(rc))
- {
- rc = hdaRegWriteU16(pThis, iReg, u32Value);
- AssertRC(rc);
- }
- else
- LogFunc(("[SD%RU8]: (Re-)Opening stream failed with rc=%Rrc\n", pStream->u8SD, rc));
- }
-
- if (RT_SUCCESS(rcSem))
- hdaRegWriteSDUnlock(pStream);
-
- return VINF_SUCCESS; /* Never return failure. */
-#else /* !IN_RING3 */
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value);
- return VINF_IOM_R3_MMIO_WRITE;
-#endif
-}
-
-/* Note: Will be called for both, BDPL and BDPU, registers. */
-DECLINLINE(int) hdaRegWriteSDBDPX(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value, uint8_t u8Strm)
-{
-#ifdef IN_RING3
- if (HDA_REG_IND(pThis, iReg) == u32Value) /* Value already set? */
- return VINF_SUCCESS;
-
- PHDASTREAM pStream = hdaStreamFromSD(pThis, u8Strm);
- if (!pStream)
- {
- LogFunc(("[SD%RU8]: Warning: Changing SDBPL/SDBPU on non-attached stream (0x%x)\n", HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), u32Value));
- return hdaRegWriteU32(pThis, iReg, u32Value);
- }
-
- int rc2 = hdaRegWriteSDLock(pThis, pStream, iReg, u32Value);
- AssertRC(rc2);
-
- rc2 = hdaRegWriteU32(pThis, iReg, u32Value);
- AssertRC(rc2);
-
- /* Update BDL base. */
- pStream->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
- HDA_STREAM_REG(pThis, BDPU, u8Strm));
- /* Reset BDLE state. */
- RT_ZERO(pStream->State.BDLE);
- pStream->State.uCurBDLE = 0;
-
- LogFlowFunc(("[SD%RU8]: BDLBase=0x%x\n", pStream->u8SD, pStream->u64BDLBase));
- hdaRegWriteSDUnlock(pStream);
-
- return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-#else /* !IN_RING3 */
- RT_NOREF_PV(pThis); RT_NOREF_PV(iReg); RT_NOREF_PV(u32Value); RT_NOREF_PV(u8Strm);
- return VINF_IOM_R3_MMIO_WRITE;
-#endif /* IN_RING3 */
-}
static int hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
@@ -2979,64 +2310,48 @@ static int hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
return hdaRegWriteSDBDPX(pThis, iReg, u32Value, HDA_SD_NUM_FROM_REG(pThis, BDPU, iReg));
}
-#ifdef IN_RING3
/**
- * XXX
- *
- * @return VBox status code. ALL THE CALLERS IGNORES THIS. DUH.
+ * Checks whether a write to a specific SDnXXX register is allowed or not.
*
+ * @return bool Returns @true if write is allowed, @false if not.
* @param pThis Pointer to HDA state.
- * @param iReg Register to write (logging only).
- * @param u32Value Value to write (logging only).
+ * @param iReg Register to write.
+ * @param u32Value Value to write.
*/
-DECLINLINE(int) hdaRegWriteSDLock(PHDASTATE pThis, PHDASTREAM pStream, uint32_t iReg, uint32_t u32Value)
+inline bool hdaRegWriteSDIsAllowed(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- RT_NOREF(pThis, iReg, u32Value);
- AssertPtr(pThis); /* don't bother returning errors */
- AssertPtr(pStream);
+ RT_NOREF(u32Value);
-# ifdef VBOX_STRICT
/* Check if the SD's RUN bit is set. */
- uint32_t u32SDCTL = HDA_STREAM_REG(pThis, CTL, pStream->u8SD);
- bool fIsRunning = RT_BOOL(u32SDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+ bool fIsRunning = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
if (fIsRunning)
{
- LogFunc(("[SD%RU8]: Warning: Cannot write to register 0x%x (0x%x) when RUN bit is set (%R[sdctl])\n",
- pStream->u8SD, iReg, u32Value, u32SDCTL));
-# ifdef DEBUG_andy
- AssertFailed();
-# endif
- return VERR_ACCESS_DENIED;
+#ifdef VBOX_STRICT
+ AssertMsgFailed(("[SD%RU8]: Cannot write to register 0x%x (0x%x) when RUN bit is set\n",
+ HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), iReg, u32Value));
+#endif
+ return false;
}
-# endif
-
- return RTCritSectEnter(&pStream->State.CritSect);
-}
-
-DECLINLINE(void) hdaRegWriteSDUnlock(PHDASTREAM pStream)
-{
- AssertPtrReturnVoid(pStream);
- int rc2 = RTCritSectLeave(&pStream->State.CritSect);
- AssertRC(rc2);
+ return true;
}
-#endif /* IN_RING3 */
static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
{
+ int rc = VINF_SUCCESS;
/* regarding 3.4.3 we should mark IRS as busy in case CORB is active */
if ( HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP)
|| HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA))
- {
HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy */
- }
- return hdaRegReadU32(pThis, iReg, pu32Value);
+ rc = hdaRegReadU32(pThis, iReg, pu32Value);
+ return rc;
}
static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- RT_NOREF_PV(iReg);
+ RT_NOREF(iReg);
+ int rc = VINF_SUCCESS;
/*
* If the guest set the ICB bit of IRS register, HDA should process the verb in IC register,
@@ -3046,51 +2361,56 @@ static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
&& !HDA_REG_FLAG_VALUE(pThis, IRS, ICB))
{
#ifdef IN_RING3
- uint32_t uCmd = HDA_REG(pThis, IC);
-
+ PFNHDACODECVERBPROCESSOR pfn = NULL;
+ uint64_t resp;
+ uint32_t cmd = HDA_REG(pThis, IC);
if (HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP))
{
/*
- * 3.4.3: Defines behavior of immediate Command status register.
+ * 3.4.3 defines behavior of immediate Command status register.
*/
- LogRel(("HDA: Guest attempted process immediate verb (%x) with active CORB\n", uCmd));
- return VINF_SUCCESS;
+ LogRel(("guest attempted process immediate verb (%x) with active CORB\n", cmd));
+ return rc;
}
-
HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy */
+ LogFunc(("IC:%x\n", cmd));
- uint64_t uResp;
- int rc2 = pThis->pCodec->pfnLookup(pThis->pCodec,
- HDA_CODEC_CMD(uCmd, 0 /* LUN */), &uResp);
- if (RT_FAILURE(rc2))
- LogFunc(("Codec lookup failed with rc2=%Rrc\n", rc2));
+ rc = pThis->pCodec->pfnLookup(pThis->pCodec,
+ HDA_CODEC_CMD(cmd, 0 /* LUN */),
+ &pfn);
+ if (RT_FAILURE(rc))
+ AssertRCReturn(rc, rc);
+ rc = pfn(pThis->pCodec,
+ HDA_CODEC_CMD(cmd, 0 /* LUN */), &resp);
+ if (RT_FAILURE(rc))
+ AssertRCReturn(rc, rc);
- HDA_REG(pThis, IR) = (uint32_t)uResp; /** @todo r=andy Do we need a 64-bit response? */
- HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, IRV); /* result is ready */
+ HDA_REG(pThis, IR) = (uint32_t)resp;
+ LogFunc(("IR:%x\n", HDA_REG(pThis, IR)));
+ HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, IRV); /* result is ready */
HDA_REG(pThis, IRS) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy is clear */
- return VINF_SUCCESS;
-#else /* !IN_RING3 */
- return VINF_IOM_R3_MMIO_WRITE;
-#endif /* !IN_RING3 */
+#else /* !IN_RING3 */
+ rc = VINF_IOM_R3_MMIO_WRITE;
+#endif
+ return rc;
}
-
/*
* Once the guest read the response, it should clean the IRV bit of the IRS register.
*/
if ( u32Value & HDA_REG_FIELD_FLAG_MASK(IRS, IRV)
&& HDA_REG_FLAG_VALUE(pThis, IRS, IRV))
HDA_REG(pThis, IRS) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, IRV);
- return VINF_SUCCESS;
+ return rc;
}
static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- RT_NOREF_PV(iReg);
-
+ RT_NOREF(iReg);
if (u32Value & HDA_REG_FIELD_FLAG_MASK(RIRBWP, RST))
+ {
HDA_REG(pThis, RIRBWP) = 0;
-
- /* The remaining bits are O, see 6.2.22. */
+ }
+ /* The remaining bits are O, see 6.2.22 */
return VINF_SUCCESS;
}
@@ -3125,8 +2445,8 @@ static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
pThis->u64DPBase |= pThis->au32Regs[iRegMem];
/* Also make sure to handle the DMA position enable bit. */
- pThis->fDMAPosition = RT_BOOL(pThis->u64DPBase & RT_BIT_64(0));
- LogRel2(("HDA: %s DMA position buffer\n", pThis->fDMAPosition ? "Enabled" : "Disabled"));
+ pThis->fDMAPosition = pThis->au32Regs[iRegMem] & RT_BIT_32(0);
+ LogRel(("HDA: %s DMA position buffer\n", pThis->fDMAPosition ? "Enabled" : "Disabled"));
break;
}
case HDA_REG_DPUBASE:
@@ -3145,8 +2465,7 @@ static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
{
- RT_NOREF_PV(iReg);
-
+ RT_NOREF(iReg);
uint8_t v = HDA_REG(pThis, RIRBSTS);
HDA_REG(pThis, RIRBSTS) &= ~(v & u32Value);
@@ -3154,7 +2473,7 @@ static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
}
#ifdef IN_RING3
-#ifdef LOG_ENABLED
+# ifdef LOG_ENABLED
static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
{
LogFlowFunc(("BDLEs @ 0x%x (%RU16):\n", u64BDLBase, cBDLE));
@@ -3193,7 +2512,7 @@ static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
LogFlowFunc(("\t#%03d DMA @ 0x%x\n", i , uDMACnt));
}
}
-#endif
+# endif
/**
* Fetches a Bundle Descriptor List Entry (BDLE) from the DMA engine.
@@ -3208,12 +2527,6 @@ static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, ui
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
AssertPtrReturn(pBDLE, VERR_INVALID_POINTER);
AssertReturn(u64BaseDMA, VERR_INVALID_PARAMETER);
-
- if (!u64BaseDMA)
- {
- LogRel2(("HDA: Unable to fetch BDLE #%RU16 - no base DMA address set (yet)\n", u16Entry));
- return VERR_NOT_FOUND;
- }
/** @todo Compare u16Entry with LVI. */
uint8_t uBundleEntry[16]; /** @todo Define a BDLE length. */
@@ -3230,7 +2543,7 @@ static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, ui
if (pBDLE->u32BufSize < sizeof(uint16_t)) /* Must be at least one word. */
return VERR_INVALID_STATE;
- pBDLE->fIntOnCompletion = (*(uint32_t *)&uBundleEntry[12]) & RT_BIT(0);
+ pBDLE->fIntOnCompletion = (*(uint32_t *)&uBundleEntry[12]) & 0x1;
return VINF_SUCCESS;
}
@@ -3241,27 +2554,24 @@ static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, ui
*
* @return Number of bytes for the DMA engine to process.
*/
-DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbMax)
+DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax)
{
- AssertPtrReturn(pThis, 0);
- AssertPtrReturn(pStream, 0);
+ AssertPtrReturn(pThis, 0);
+ AssertPtrReturn(pStrmSt, 0);
if (!cbMax)
return 0;
- PHDABDLE pBDLE = &pStream->State.BDLE;
+ PHDABDLE pBDLE = &pStrmSt->State.BDLE;
- uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
- Assert(u32LPIB <= pStream->u32CBL);
-
- uint32_t cbFree = pStream->u32CBL - u32LPIB;
+ uint32_t cbFree = pStrmSt->u32CBL - HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
if (cbFree)
{
/* Limit to the available free space of the current BDLE. */
cbFree = RT_MIN(cbFree, pBDLE->u32BufSize - pBDLE->State.u32BufOff);
/* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
- cbFree = RT_MIN(cbFree, uint32_t(pStream->u16FIFOS));
+ cbFree = RT_MIN(cbFree, pStrmSt->u16FIFOS);
/* Make sure we only transfer as many bytes as requested. */
cbFree = RT_MIN(cbFree, cbMax);
@@ -3279,8 +2589,8 @@ DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStrea
}
}
- LogFlowFunc(("[SD%RU8]: CBL=%RU32, LPIB=%RU32, FIFOS=%RU16, cbFree=%RU32, %R[bdle]\n", pStream->u8SD,
- pStream->u32CBL, HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), pStream->u16FIFOS, cbFree, pBDLE));
+ LogFlowFunc(("[SD%RU8]: CBL=%RU32, LPIB=%RU32, cbFree=%RU32, %R[bdle]\n", pStrmSt->u8Strm,
+ pStrmSt->u32CBL, HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm), cbFree, pBDLE));
return cbFree;
}
@@ -3318,153 +2628,48 @@ DECLINLINE(void) hdaBDLEUpdate(PHDABDLE pBDLE, uint32_t cbData, uint32_t cbProce
LogFlowFunc(("cbData=%RU32, cbProcessed=%RU32, %R[bdle]\n", cbData, cbProcessed, pBDLE));
}
-#ifdef IN_RING3
-/**
- * Initializes a stream mapping structure according to the given stream configuration.
- *
- * @return IPRT status code.
- * @param pMapping Pointer to mapping to initialize.
- * @param pCfg Pointer to stream configuration to use.
- */
-static int hdaStreamMapInit(PHDASTREAMMAPPING pMapping, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pMapping, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- AssertReturn(pCfg->cChannels, VERR_INVALID_PARAMETER);
-
- hdaStreamMapReset(pMapping);
-
- pMapping->paChannels = (PPDMAUDIOSTREAMCHANNEL)RTMemAlloc(sizeof(PDMAUDIOSTREAMCHANNEL) * pCfg->cChannels);
- if (!pMapping->paChannels)
- return VERR_NO_MEMORY;
-
- PDMAUDIOPCMPROPS Props;
- int rc = DrvAudioHlpStreamCfgToProps(pCfg, &Props);
- if (RT_FAILURE(rc))
- return rc;
-
- Assert(RT_IS_POWER_OF_TWO(Props.cBits));
-
- /** @todo We assume all channels in a stream have the same format. */
- PPDMAUDIOSTREAMCHANNEL pChan = pMapping->paChannels;
- for (uint8_t i = 0; i < pCfg->cChannels; i++)
- {
- pChan->uChannel = i;
- pChan->cbStep = (Props.cBits / 2);
- pChan->cbFrame = pChan->cbStep * pCfg->cChannels;
- pChan->cbFirst = i * pChan->cbStep;
- pChan->cbOff = pChan->cbFirst;
-
- int rc2 = hdaStreamChannelDataInit(&pChan->Data, PDMAUDIOSTREAMCHANNELDATA_FLAG_NONE);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- if (RT_FAILURE(rc))
- break;
-
- pChan++;
- }
-
- if ( RT_SUCCESS(rc)
- /* Create circular buffer if not created yet. */
- && !pMapping->pCircBuf)
- {
- rc = RTCircBufCreate(&pMapping->pCircBuf, _4K); /** @todo Make size configurable? */
- }
-
- if (RT_SUCCESS(rc))
- {
- pMapping->cChannels = pCfg->cChannels;
-#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
- pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_INTERLEAVED;
-#else
- pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_NON_INTERLEAVED;
-#endif
- }
-
- return rc;
-}
-
-/**
- * Destroys a given stream mapping.
- *
- * @param pMapping Pointer to mapping to destroy.
- */
-static void hdaStreamMapDestroy(PHDASTREAMMAPPING pMapping)
-{
- hdaStreamMapReset(pMapping);
-
- if (pMapping->pCircBuf)
- {
- RTCircBufDestroy(pMapping->pCircBuf);
- pMapping->pCircBuf = NULL;
- }
-}
-
-/**
- * Resets a given stream mapping.
- *
- * @param pMapping Pointer to mapping to reset.
- */
-static void hdaStreamMapReset(PHDASTREAMMAPPING pMapping)
-{
- AssertPtrReturnVoid(pMapping);
-
- pMapping->enmLayout = PDMAUDIOSTREAMLAYOUT_UNKNOWN;
-
- if (pMapping->cChannels)
- {
- for (uint8_t i = 0; i < pMapping->cChannels; i++)
- hdaStreamChannelDataDestroy(&pMapping->paChannels[i].Data);
-
- AssertPtr(pMapping->paChannels);
- RTMemFree(pMapping->paChannels);
- pMapping->paChannels = NULL;
-
- pMapping->cChannels = 0;
- }
-}
-#endif /* IN_RING3 */
-
-DECLINLINE(bool) hdaStreamNeedsNextBDLE(PHDASTATE pThis, PHDASTREAM pStream)
+DECLINLINE(bool) hdaStreamNeedsNextBDLE(PHDASTATE pThis, PHDASTREAM pStrmSt)
{
AssertPtrReturn(pThis, false);
- AssertPtrReturn(pStream, false);
+ AssertPtrReturn(pStrmSt, false);
- PHDABDLE pBDLE = &pStream->State.BDLE;
- uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
+ PHDABDLE pBDLE = &pStrmSt->State.BDLE;
+ uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
/* Did we reach the CBL (Cyclic Buffer List) limit? */
- bool fCBLLimitReached = u32LPIB >= pStream->u32CBL;
+ bool fCBLLimitReached = u32LPIB >= pStrmSt->u32CBL;
/* Do we need to use the next BDLE entry? Either because we reached
* the CBL limit or our internal DMA buffer is full. */
bool fNeedsNextBDLE = ( fCBLLimitReached
|| (pBDLE->State.u32BufOff >= pBDLE->u32BufSize));
- Assert(u32LPIB <= pStream->u32CBL);
+ Assert(u32LPIB <= pStrmSt->u32CBL);
Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
LogFlowFunc(("[SD%RU8]: LPIB=%RU32, CBL=%RU32, fCBLLimitReached=%RTbool, fNeedsNextBDLE=%RTbool, %R[bdle]\n",
- pStream->u8SD, u32LPIB, pStream->u32CBL, fCBLLimitReached, fNeedsNextBDLE, pBDLE));
+ pStrmSt->u8Strm, u32LPIB, pStrmSt->u32CBL, fCBLLimitReached, fNeedsNextBDLE, pBDLE));
+
+ if (fCBLLimitReached)
+ {
+ /* Reset LPIB register. */
+ u32LPIB -= RT_MIN(u32LPIB, pStrmSt->u32CBL);
+ hdaStreamUpdateLPIB(pThis, pStrmSt, u32LPIB);
+ }
return fNeedsNextBDLE;
}
-DECLINLINE(void) hdaStreamTransferUpdate(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbInc)
+DECLINLINE(void) hdaStreamTransferUpdate(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbInc)
{
AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStream);
+ AssertPtrReturnVoid(pStrmSt);
- LogFlowFunc(("[SD%RU8]: cbInc=%RU32\n", pStream->u8SD, cbInc));
+ LogFlowFunc(("[SD%RU8]: cbInc=%RU32\n", pStrmSt->u8Strm, cbInc));
- //Assert(cbInc <= pStream->u16FIFOS);
-
- if (!cbInc) /* Nothing to do? Bail out early. */
- return;
+ Assert(cbInc <= pStrmSt->u16FIFOS);
- PHDABDLE pBDLE = &pStream->State.BDLE;
+ PHDABDLE pBDLE = &pStrmSt->State.BDLE;
/*
* If we're below the FIFO watermark (SDFIFOW), it's expected that HDA
@@ -3473,40 +2678,33 @@ DECLINLINE(void) hdaStreamTransferUpdate(PHDASTATE pThis, PHDASTREAM pStream, ui
*/
if (pBDLE->State.cbBelowFIFOW == 0) /* Did we hit (or exceed) the watermark? */
{
- uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
-
- AssertMsg(((u32LPIB + cbInc) <= pStream->u32CBL),
- ("[SD%RU8] Increment (%RU32) exceeds CBL (%RU32): LPIB (%RU32)\n",
- pStream->u8SD, cbInc, pStream->u32CBL, u32LPIB));
-
- u32LPIB = RT_MIN(u32LPIB + cbInc, pStream->u32CBL);
+ const uint32_t u32LPIB = RT_MIN(HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) + cbInc,
+ pStrmSt->u32CBL);
LogFlowFunc(("[SD%RU8]: LPIB: %RU32 -> %RU32, CBL=%RU32\n",
- pStream->u8SD,
- HDA_STREAM_REG(pThis, LPIB, pStream->u8SD), HDA_STREAM_REG(pThis, LPIB, pStream->u8SD) + cbInc,
- pStream->u32CBL));
+ pStrmSt->u8Strm,
+ HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm), HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) + cbInc,
+ pStrmSt->u32CBL));
- hdaStreamUpdateLPIB(pThis, pStream, u32LPIB);
+ hdaStreamUpdateLPIB(pThis, pStrmSt, u32LPIB);
}
}
-static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStream, bool *pfInterrupt)
+static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStrmSt)
{
AssertPtrReturn(pThis, true);
- AssertPtrReturn(pStream, true);
+ AssertPtrReturn(pStrmSt, true);
- bool fInterrupt = false;
bool fIsComplete = false;
- PHDABDLE pBDLE = &pStream->State.BDLE;
-#ifdef LOG_ENABLED
- const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStream->u8SD);
-#endif
+ PHDABDLE pBDLE = &pStrmSt->State.BDLE;
+ const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
- /* Check if the current BDLE entry is complete (full). */
- if (pBDLE->State.u32BufOff >= pBDLE->u32BufSize)
+ if ( pBDLE->State.u32BufOff >= pBDLE->u32BufSize
+ || u32LPIB >= pStrmSt->u32CBL)
{
Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
+ Assert(u32LPIB <= pStrmSt->u32CBL);
if (/* IOC (Interrupt On Completion) bit set? */
pBDLE->fIntOnCompletion
@@ -3514,24 +2712,31 @@ static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStream, boo
&& pBDLE->State.cbBelowFIFOW == 0
)
{
- LogFlowFunc(("[SD%RU8]: %R[bdle] => COMPLETE\n", pStream->u8SD, pBDLE));
+ /**
+ * Set the BCIS (Buffer Completion Interrupt Status) flag as the
+ * last byte of data for the current descriptor has been fetched
+ * from memory and put into the DMA FIFO.
+ *
+ ** @todo More carefully investigate BCIS flag.
+ *
+ * Speech synthesis works fine on Mac Guest if this bit isn't set
+ * but in general sound quality gets worse.
+ */
+ HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
/*
* If the ICE (IOCE, "Interrupt On Completion Enable") bit of the SDCTL register is set
* we need to generate an interrupt.
*/
- if (HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
- fInterrupt = true;
+ if (HDA_STREAM_REG(pThis, CTL, pStrmSt->u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
+ hdaProcessInterrupt(pThis);
}
fIsComplete = true;
}
- if (pfInterrupt)
- *pfInterrupt = fInterrupt;
-
- LogFlowFunc(("[SD%RU8]: u32LPIB=%RU32, CBL=%RU32, fIsComplete=%RTbool, fInterrupt=%RTbool, %R[bdle]\n",
- pStream->u8SD, u32LPIB, pStream->u32CBL, fIsComplete, fInterrupt, pBDLE));
+ LogFlowFunc(("[SD%RU8]: u32LPIB=%RU32, CBL=%RU32, %R[bdle] => %s\n",
+ pStrmSt->u8Strm, u32LPIB, pStrmSt->u32CBL, pBDLE, fIsComplete ? "COMPLETE" : "INCOMPLETE"));
return fIsComplete;
}
@@ -3541,210 +2746,160 @@ static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStream, boo
* Note: This function writes to the DMA buffer immediately,
* but "reports bytes" when all conditions are met (FIFOW).
*/
-static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
+static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, PAUDMIXSINK pSink, uint32_t cbMax, uint32_t *pcbRead)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+ AssertPtrReturn(pSink, VERR_INVALID_POINTER);
/* pcbRead is optional. */
+ PHDABDLE pBDLE = &pStrmSt->State.BDLE;
+
int rc;
uint32_t cbRead = 0;
+ uint32_t cbBuf = hdaStreamGetTransferSize(pThis, pStrmSt, cbMax);
- do
- {
- PHDABDLE pBDLE = &pStream->State.BDLE;
+ LogFlowFunc(("cbBuf=%RU32, %R[bdle]\n", cbBuf, pBDLE));
- if (!cbToRead)
+ if (!cbBuf)
+ {
+ /* Nothing to write, bail out. */
+ rc = VINF_EOF;
+ }
+ else
+ {
+ rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbRead);
+ if (RT_SUCCESS(rc))
{
- rc = VINF_EOF;
- break;
- }
-
- AssertPtr(pStream->pMixSink);
- AssertPtr(pStream->pMixSink->pMixSink);
- rc = AudioMixerSinkRead(pStream->pMixSink->pMixSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbToRead, &cbRead);
- if (RT_FAILURE(rc))
- break;
-
- if (!cbRead)
- {
- rc = VINF_EOF;
- break;
- }
-
- /* Sanity checks. */
- Assert(cbRead <= cbToRead);
- Assert(cbRead <= sizeof(pBDLE->State.au8FIFO));
- Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
+ if (!cbRead)
+ {
+ rc = VINF_EOF;
+ }
+ else
+ {
+ /* Sanity checks. */
+ Assert(cbRead <= pStrmSt->u16FIFOS);
+ Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
- /*
- * Write to the BDLE's DMA buffer.
- */
- rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
- pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
- pBDLE->State.au8FIFO, cbRead);
- AssertRC(rc);
+ /*
+ * Write to the BDLE's DMA buffer.
+ */
+ rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
+ pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
+ pBDLE->State.au8FIFO, cbRead);
+ AssertRC(rc);
- if (pBDLE->State.cbBelowFIFOW + cbRead > hdaStreamGetFIFOW(pThis, pStream))
- {
- Assert(pBDLE->State.u32BufOff + cbRead <= pBDLE->u32BufSize);
- pBDLE->State.u32BufOff += cbRead;
- pBDLE->State.cbBelowFIFOW = 0;
- //hdaBackendReadTransferReported(pBDLE, cbDMAData, cbRead, &cbRead, pcbAvail);
- }
- else
- {
- Assert(pBDLE->State.u32BufOff + cbRead <= pBDLE->u32BufSize);
- pBDLE->State.u32BufOff += cbRead;
- pBDLE->State.cbBelowFIFOW += cbRead;
- Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStream));
- //hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbRead, pcbAvail);
+ if (pBDLE->State.cbBelowFIFOW + cbRead > hdaStreamGetFIFOW(pThis, pStrmSt))
+ {
+ pBDLE->State.u32BufOff += cbRead;
+ pBDLE->State.cbBelowFIFOW = 0;
+ //hdaBackendReadTransferReported(pBDLE, cbDMAData, cbRead, &cbRead, pcbAvail);
+ }
+ else
+ {
+ pBDLE->State.u32BufOff += cbRead;
+ pBDLE->State.cbBelowFIFOW += cbRead;
+ Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStrmSt));
+ //hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbRead, pcbAvail);
- rc = VERR_NO_DATA;
+ rc = VERR_NO_DATA;
+ }
+ }
}
-
- } while (0);
+ }
if (RT_SUCCESS(rc))
{
if (pcbRead)
*pcbRead = cbRead;
}
-
- if (RT_FAILURE(rc))
+ else
LogFlowFunc(("Failed with %Rrc\n", rc));
return rc;
}
-static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
+static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax, uint32_t *pcbWritten)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
/* pcbWritten is optional. */
- PHDABDLE pBDLE = &pStream->State.BDLE;
+ PHDABDLE pBDLE = &pStrmSt->State.BDLE;
uint32_t cbWritten = 0;
+ uint32_t cbData = hdaStreamGetTransferSize(pThis, pStrmSt, cbMax);
+
+ LogFlowFunc(("cbData=%RU32, %R[bdle]\n", cbData, pBDLE));
/*
* Copy from DMA to the corresponding stream buffer (if there are any bytes from the
* previous unreported transfer we write at offset 'pBDLE->State.cbUnderFifoW').
*/
int rc;
- if (!cbToWrite)
+ if (!cbData)
{
rc = VINF_EOF;
}
else
{
- void *pvBuf = pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW;
- Assert(cbToWrite >= pBDLE->State.cbBelowFIFOW);
- uint32_t cbBuf = cbToWrite - pBDLE->State.cbBelowFIFOW;
-
/*
* Read from the current BDLE's DMA buffer.
*/
rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
- pvBuf, cbBuf);
+ pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW, cbData);
AssertRC(rc);
-#ifdef HDA_DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio-hda.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- RTFileWrite(fh, pvBuf, cbBuf, NULL);
- RTFileClose(fh);
-#endif
-
#ifdef VBOX_WITH_STATISTICS
- STAM_COUNTER_ADD(&pThis->StatBytesRead, cbBuf);
+ STAM_COUNTER_ADD(&pThis->StatBytesRead, cbData);
#endif
/*
* Write to audio backend. We should ensure that we have enough bytes to copy to the backend.
*/
- if (cbBuf >= hdaStreamGetFIFOW(pThis, pStream))
+ uint32_t cbToWrite = cbData + pBDLE->State.cbBelowFIFOW;
+ if (cbToWrite >= hdaStreamGetFIFOW(pThis, pStrmSt))
{
-#if defined(VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT) || defined(VBOX_WITH_HDA_51_SURROUND)
- PHDASTREAMMAPPING pMapping = &pStream->State.Mapping;
-#endif
-
- /** @todo Which channel is which? */
-#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
- PPDMAUDIOSTREAMCHANNEL pChanFront = &pMapping->paChannels[0];
-#endif
-#ifdef VBOX_WITH_HDA_51_SURROUND
- PPDMAUDIOSTREAMCHANNEL pChanCenterLFE = &pMapping->paChannels[2]; /** @todo FIX! */
- PPDMAUDIOSTREAMCHANNEL pChanRear = &pMapping->paChannels[4]; /** @todo FIX! */
-#endif
+ uint32_t cbWrittenToStream;
int rc2;
- void *pvDataFront = NULL;
- size_t cbDataFront;
-#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
- rc2 = hdaStreamChannelExtract(pChanFront, pvBuf, cbBuf);
- AssertRC(rc2);
-
- rc2 = hdaStreamChannelAcquireData(&pChanFront->Data, pvDataFront, &cbDataFront);
- AssertRC(rc2);
-#else
- /* Use stuff in the whole FIFO to use for the channel data. */
- pvDataFront = pvBuf;
- cbDataFront = cbBuf;
-#endif
-#ifdef VBOX_WITH_HDA_51_SURROUND
- void *pvDataCenterLFE;
- size_t cbDataCenterLFE;
- rc2 = hdaStreamChannelExtract(pChanCenterLFE, pvBuf, cbBuf);
- AssertRC(rc2);
-
- rc2 = hdaStreamChannelAcquireData(&pChanCenterLFE->Data, pvDataCenterLFE, &cbDataCenterLFE);
- AssertRC(rc2);
-
- void *pvDataRear;
- size_t cbDataRear;
- rc2 = hdaStreamChannelExtract(pChanRear, pvBuf, cbBuf);
- AssertRC(rc2);
-
- rc2 = hdaStreamChannelAcquireData(&pChanRear->Data, pvDataRear, &cbDataRear);
- AssertRC(rc2);
-#endif
- /*
- * Write data to according mixer sinks.
- */
- rc2 = AudioMixerSinkWrite(pThis->SinkFront.pMixSink, AUDMIXOP_COPY, pvDataFront, (uint32_t)cbDataFront,
- NULL /* pcbWritten */);
- AssertRC(rc2);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- rc2 = AudioMixerSinkWrite(pThis->SinkCenterLFE, AUDMIXOP_COPY, pvDataCenterLFE, cbDataCenterLFE,
- NULL /* pcbWritten */);
- AssertRC(rc2);
- rc2 = AudioMixerSinkWrite(pThis->SinkRear, AUDMIXOP_COPY, pvDataRear, cbDataRear,
- NULL /* pcbWritten */);
- AssertRC(rc2);
-#endif
+ PHDADRIVER pDrv;
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ {
+ if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut))
+ {
+ rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+ pBDLE->State.au8FIFO, cbToWrite, &cbWrittenToStream);
+ if (RT_SUCCESS(rc2))
+ {
+ if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
+ LogFlowFunc(("\tLUN#%RU8: Warning: Only written %RU32 / %RU32 bytes, expect lags\n",
+ pDrv->uLUN, cbWrittenToStream, cbToWrite));
+ }
+ }
+ else /* Stream disabled, not fatal. */
+ {
+ cbWrittenToStream = 0;
+ rc2 = VERR_NOT_AVAILABLE;
+ /* Keep going. */
+ }
-#ifdef VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
- hdaStreamChannelReleaseData(&pChanFront->Data);
-#endif
-#ifdef VBOX_WITH_HDA_51_SURROUND
- hdaStreamChannelReleaseData(&pChanCenterLFE->Data);
- hdaStreamChannelReleaseData(&pChanRear->Data);
-#endif
+ LogFlowFunc(("\tLUN#%RU8: cbToWrite=%RU32, cbWrittenToStream=%RU32, rc=%Rrc\n",
+ pDrv->uLUN, cbToWrite, cbWrittenToStream, rc2));
+ }
/* Always report all data as being written;
* backends who were not able to catch up have to deal with it themselves. */
cbWritten = cbToWrite;
- hdaBDLEUpdate(pBDLE, cbToWrite, cbWritten);
+ hdaBDLEUpdate(pBDLE, cbData, cbWritten);
}
else
{
- Assert(pBDLE->State.u32BufOff + cbWritten <= pBDLE->u32BufSize);
- pBDLE->State.u32BufOff += cbWritten;
+ pBDLE->State.u32BufOff += cbWritten;
pBDLE->State.cbBelowFIFOW += cbWritten;
- Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStream));
+ Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStrmSt));
/* Not enough bytes to be processed and reported, we'll try our luck next time around. */
//hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbAvail, NULL);
@@ -3752,7 +2907,7 @@ static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite
}
}
- //Assert(cbWritten <= pStream->u16FIFOS);
+ Assert(cbWritten <= pStrmSt->u16FIFOS);
if (RT_SUCCESS(rc))
{
@@ -3760,9 +2915,7 @@ static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToWrite
*pcbWritten = cbWritten;
}
- if (RT_FAILURE(rc))
- LogFlowFunc(("Failed with %Rrc\n", rc));
-
+ LogFunc(("Returning cbWritten=%RU32, rc=%Rrc\n", cbWritten, rc));
return rc;
}
@@ -3776,357 +2929,129 @@ static DECLCALLBACK(int) hdaCodecReset(PHDACODEC pCodec)
return VINF_SUCCESS;
}
-/**
- * Retrieves a corresponding sink for a given mixer control.
- * Returns NULL if no sink is found.
- *
- * @return PHDAMIXERSINK
- * @param pThis HDA state.
- * @param enmMixerCtl Mixer control to get the corresponding sink for.
- */
-static PHDAMIXERSINK hdaMixerControlToSink(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl)
+
+static DECLCALLBACK(void) hdaCloseIn(PHDASTATE pThis, PDMAUDIORECSOURCE enmRecSource)
{
- PHDAMIXERSINK pSink;
+ NOREF(pThis);
+ NOREF(enmRecSource);
+ LogFlowFuncEnter();
+}
- switch (enmMixerCtl)
+static DECLCALLBACK(void) hdaCloseOut(PHDASTATE pThis)
+{
+ NOREF(pThis);
+ LogFlowFuncEnter();
+}
+
+static DECLCALLBACK(int) hdaOpenIn(PHDASTATE pThis,
+ const char *pszName, PDMAUDIORECSOURCE enmRecSource,
+ PPDMAUDIOSTREAMCFG pCfg)
+{
+ PAUDMIXSINK pSink;
+
+ switch (enmRecSource)
{
- case PDMAUDIOMIXERCTL_VOLUME_MASTER:
- /* Fall through is intentional. */
- case PDMAUDIOMIXERCTL_FRONT:
- pSink = &pThis->SinkFront;
- break;
-#ifdef VBOX_WITH_HDA_51_SURROUND
- case PDMAUDIOMIXERCTL_CENTER_LFE:
- pSink = &pThis->SinkCenterLFE;
- break;
- case PDMAUDIOMIXERCTL_REAR:
- pSink = &pThis->SinkRear;
- break;
-#endif
- case PDMAUDIOMIXERCTL_LINE_IN:
- pSink = &pThis->SinkLineIn;
+# ifdef VBOX_WITH_HDA_MIC_IN
+ case PDMAUDIORECSOURCE_MIC:
+ pSink = pThis->pSinkMicIn;
break;
-#ifdef VBOX_WITH_HDA_MIC_IN
- case PDMAUDIOMIXERCTL_MIC_IN:
- pSink = &pThis->SinkMicIn;
+# endif
+ case PDMAUDIORECSOURCE_LINE_IN:
+ pSink = pThis->pSinkLineIn;
break;
-#endif
default:
- pSink = NULL;
- AssertMsgFailed(("Unhandled mixer control\n"));
- break;
+ AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
+ return VERR_NOT_SUPPORTED;
}
- return pSink;
-}
-
-static DECLCALLBACK(int) hdaMixerAddStream(PHDASTATE pThis, PHDAMIXERSINK pSink, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- LogFunc(("Sink=%s, Stream=%s\n", pSink->pMixSink->pszName, pCfg->szName));
-
- /* Update the sink's format. */
- PDMAUDIOPCMPROPS PCMProps;
- int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
- if (RT_SUCCESS(rc))
- rc = AudioMixerSinkSetFormat(pSink->pMixSink, &PCMProps);
-
- if (RT_FAILURE(rc))
- return rc;
+ int rc = VINF_SUCCESS;
+ char *pszDesc;
PHDADRIVER pDrv;
RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
{
- int rc2 = VINF_SUCCESS;
- PHDAMIXERSTREAM pStream = NULL;
-
- PPDMAUDIOSTREAMCFG pStreamCfg = (PPDMAUDIOSTREAMCFG)RTMemDup(pCfg, sizeof(PDMAUDIOSTREAMCFG));
- if (!pStreamCfg)
+ if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pszName) <= 0)
{
rc = VERR_NO_MEMORY;
break;
}
- /* Include the driver's LUN in the stream name for easier identification. */
- RTStrPrintf(pStreamCfg->szName, RT_ELEMENTS(pStreamCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pCfg->szName);
-
- if (pStreamCfg->enmDir == PDMAUDIODIR_IN)
- {
- LogFunc(("enmRecSource=%d\n", pStreamCfg->DestSource.Source));
-
- switch (pStreamCfg->DestSource.Source)
- {
- case PDMAUDIORECSOURCE_LINE:
- pStream = &pDrv->LineIn;
- break;
-#ifdef VBOX_WITH_HDA_MIC_IN
- case PDMAUDIORECSOURCE_MIC:
- pStream = &pDrv->MicIn;
- break;
-#endif
- default:
- rc2 = VERR_NOT_SUPPORTED;
- break;
- }
- }
- else if (pStreamCfg->enmDir == PDMAUDIODIR_OUT)
- {
- LogFunc(("enmPlaybackDest=%d\n", pStreamCfg->DestSource.Dest));
-
- switch (pStreamCfg->DestSource.Dest)
- {
- case PDMAUDIOPLAYBACKDEST_FRONT:
- pStream = &pDrv->Front;
- break;
-#ifdef VBOX_WITH_HDA_51_SURROUND
- case PDMAUDIOPLAYBACKDEST_CENTER_LFE:
- pStream = &pDrv->CenterLFE;
- break;
- case PDMAUDIOPLAYBACKDEST_REAR:
- pStream = &pDrv->Rear;
- break;
-#endif
- default:
- rc2 = VERR_NOT_SUPPORTED;
- break;
- }
- }
- else
- rc2 = VERR_NOT_SUPPORTED;
-
- if (RT_SUCCESS(rc2))
- {
- AssertPtr(pStream);
-
- AudioMixerSinkRemoveStream(pSink->pMixSink, pStream->pMixStrm);
-
- AudioMixerStreamDestroy(pStream->pMixStrm);
- pStream->pMixStrm = NULL;
-
- PAUDMIXSTREAM pMixStrm;
- rc2 = AudioMixerSinkCreateStream(pSink->pMixSink, pDrv->pConnector, pStreamCfg, 0 /* fFlags */, &pMixStrm);
- if (RT_SUCCESS(rc2))
- {
- rc2 = AudioMixerSinkAddStream(pSink->pMixSink, pMixStrm);
- LogFlowFunc(("LUN#%RU8: Added \"%s\" to sink, rc=%Rrc\n", pDrv->uLUN, pStreamCfg->szName , rc2));
- }
-
- if (RT_SUCCESS(rc2))
- pStream->pMixStrm = pMixStrm;
- }
-
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- if (pStreamCfg)
+ rc = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, enmRecSource, pCfg, &pDrv->LineIn.pStrmIn);
+ LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+ if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
{
- RTMemFree(pStreamCfg);
- pStreamCfg = NULL;
+ AudioMixerRemoveStream(pSink, pDrv->LineIn.phStrmIn);
+ rc = AudioMixerAddStreamIn(pSink,
+ pDrv->pConnector, pDrv->LineIn.pStrmIn,
+ 0 /* uFlags */, &pDrv->LineIn.phStrmIn);
}
- }
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * Adds a new audio stream to a specific mixer control.
- * Depending on the mixer control the stream then gets assigned to one of the internal
- * mixer sinks, which in turn then handle the mixing of all connected streams to that sink.
- *
- * @return IPRT status code.
- * @param pThis HDA state.
- * @param enmMixerCtl Mixer control to assign new stream to.
- * @param pCfg Stream configuration for the new stream.
- */
-static DECLCALLBACK(int) hdaMixerAddStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- int rc;
-
- PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
- if (pSink)
- {
- rc = hdaMixerAddStream(pThis, pSink, pCfg);
-
- AssertPtr(pSink->pMixSink);
- LogFlowFunc(("Sink=%s, enmMixerCtl=%d\n", pSink->pMixSink->pszName, enmMixerCtl));
+ RTStrFree(pszDesc);
}
- else
- rc = VERR_NOT_FOUND;
LogFlowFuncLeaveRC(rc);
return rc;
}
-/**
- * Removes a specified mixer control from the HDA's mixer.
- *
- * @return IPRT status code.
- * @param pThis HDA state.
- * @param enmMixerCtl Mixer control to remove.
- */
-static DECLCALLBACK(int) hdaMixerRemoveStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl)
+static DECLCALLBACK(int) hdaOpenOut(PHDASTATE pThis,
+ const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- int rc;
+ int rc = VINF_SUCCESS;
+ char *pszDesc;
- PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
- if (pSink)
+ PHDADRIVER pDrv;
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
{
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
+ pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel") <= 0)
{
- PAUDMIXSTREAM pMixStream = NULL;
- switch (enmMixerCtl)
- {
- /*
- * Input.
- */
- case PDMAUDIOMIXERCTL_LINE_IN:
- pMixStream = pDrv->LineIn.pMixStrm;
- pDrv->LineIn.pMixStrm = NULL;
- break;
-#ifdef VBOX_WITH_HDA_MIC_IN
- case PDMAUDIOMIXERCTL_MIC_IN:
- pMixStream = pDrv->MicIn.pMixStrm;
- pDrv->MicIn.pMixStrm = NULL;
- break;
-#endif
- /*
- * Output.
- */
- case PDMAUDIOMIXERCTL_FRONT:
- pMixStream = pDrv->Front.pMixStrm;
- pDrv->Front.pMixStrm = NULL;
- break;
-#ifdef VBOX_WITH_HDA_51_SURROUND
- case PDMAUDIOMIXERCTL_CENTER_LFE:
- pMixStream = pDrv->CenterLFE.pMixStrm;
- pDrv->CenterLFE.pMixStrm = NULL;
- break;
- case PDMAUDIOMIXERCTL_REAR:
- pMixStream = pDrv->Rear.pMixStrm;
- pDrv->Rear.pMixStrm = NULL;
- break;
-#endif
- default:
- AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
- break;
- }
-
- if (pMixStream)
- {
- AudioMixerSinkRemoveStream(pSink->pMixSink, pMixStream);
- AudioMixerStreamDestroy(pMixStream);
-
- pMixStream = NULL;
- }
+ rc = VERR_NO_MEMORY;
+ break;
}
- AudioMixerSinkRemoveAllStreams(pSink->pMixSink);
- rc = VINF_SUCCESS;
- }
- else
- rc = VERR_NOT_FOUND;
-
- LogFlowFunc(("enmMixerCtl=%d, rc=%Rrc\n", enmMixerCtl, rc));
- return rc;
-}
-
-/**
- * Sets a SDn stream number and channel to a particular mixer control.
- *
- * @returns IPRT status code.
- * @param pThis HDA State.
- * @param enmMixerCtl Mixer control to set SD stream number and channel for.
- * @param uSD SD stream number (number + 1) to set. Set to 0 for unassign.
- * @param uChannel Channel to set. Only valid if a valid SD stream number is specified.
- */
-static DECLCALLBACK(int) hdaMixerSetStream(PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel)
-{
- LogFlowFunc(("enmMixerCtl=%RU32, uSD=%RU8, uChannel=%RU8\n", enmMixerCtl, uSD, uChannel));
-
- if (uSD == 0) /* Stream number 0 is reserved. */
- {
- LogFlowFunc(("Invalid SDn (%RU8) number for mixer control %d, ignoring\n", uSD, enmMixerCtl));
- return VINF_SUCCESS;
- }
- /* uChannel is optional. */
-
- /* SDn0 starts as 1. */
- Assert(uSD);
- uSD--;
-
- int rc;
-
- PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
- if (pSink)
- {
- if ( (uSD < HDA_MAX_SDI)
- && AudioMixerSinkGetDir(pSink->pMixSink) == AUDMIXSINKDIR_OUTPUT)
+ rc = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
+ LogFlowFunc(("LUN#%RU8: Created output \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+ if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
{
- uSD += HDA_MAX_SDI;
+ AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
+ rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
+ pDrv->pConnector, pDrv->Out.pStrmOut,
+ 0 /* uFlags */, &pDrv->Out.phStrmOut);
}
- LogFlowFunc(("%s: Setting to stream ID=%RU8, channel=%RU8, enmMixerCtl=%RU32\n",
- pSink->pMixSink->pszName, uSD, uChannel, enmMixerCtl));
-
- Assert(uSD < HDA_MAX_STREAMS);
-
- PHDASTREAM pStream = hdaStreamFromSD(pThis, uSD);
- if (pStream)
- {
- pSink->uSD = uSD;
- pSink->uChannel = uChannel;
-
- /* Make sure that the stream also has this sink set. */
- hdaStreamAssignToSink(pStream, pSink);
-
- rc = VINF_SUCCESS;
- }
- else
- {
- LogRel(("HDA: Guest wanted to assign invalid stream ID=%RU8 (channel %RU8) to mixer control %RU32, skipping\n",
- uSD, uChannel, enmMixerCtl));
- rc = VERR_INVALID_PARAMETER;
- }
+ RTStrFree(pszDesc);
}
- else
- rc = VERR_NOT_FOUND;
LogFlowFuncLeaveRC(rc);
return rc;
}
-/**
- * Sets the volume of a specified mixer control.
- *
- * @return IPRT status code.
- * @param pThis HDA State.
- * @param enmMixerCtl Mixer control to set volume for.
- * @param pVol Pointer to volume data to set.
- */
-static DECLCALLBACK(int) hdaMixerSetVolume(PHDASTATE pThis,
- PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol)
+static DECLCALLBACK(int) hdaSetVolume(PHDASTATE pThis, ENMSOUNDSOURCE enmSource,
+ bool fMute, uint8_t uVolLeft, uint8_t uVolRight)
{
- int rc;
+ int rc = VINF_SUCCESS;
+ PDMAUDIOVOLUME vol = { fMute, uVolLeft, uVolRight };
+ PAUDMIXSINK pSink;
- PHDAMIXERSINK pSink = hdaMixerControlToSink(pThis, enmMixerCtl);
- if (pSink)
+ /* Convert the audio source to corresponding sink. */
+ switch (enmSource)
{
- /* Set the volume.
- * We assume that the codec already converted it to the correct range. */
- rc = AudioMixerSinkSetVolume(pSink->pMixSink, pVol);
+ case PO_INDEX:
+ pSink = pThis->pSinkOutput;
+ break;
+ case PI_INDEX:
+ pSink = pThis->pSinkLineIn;
+ break;
+ case MC_INDEX:
+ pSink = pThis->pSinkMicIn;
+ break;
+ default:
+ AssertFailedReturn(VERR_INVALID_PARAMETER);
+ break;
}
- else
- rc = VERR_NOT_FOUND;
+
+ /* Set the volume. Codec already converted it to the correct range. */
+ AudioMixerSetSinkVolume(pSink, &vol);
LogFlowFuncLeaveRC(rc);
return rc;
@@ -4134,42 +3059,6 @@ static DECLCALLBACK(int) hdaMixerSetVolume(PHDASTATE pThis,
#ifndef VBOX_WITH_AUDIO_CALLBACKS
-static void hdaTimerMaybeStart(PHDASTATE pThis)
-{
- if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
- return;
-
- if (!pThis->pTimer)
- return;
-
- LogFlowFuncEnter();
-
- LogFlowFunc(("Starting timer\n"));
-
- /* Set timer flag. */
- ASMAtomicXchgBool(&pThis->fTimerActive, true);
-
- /* Update current time timestamp. */
- pThis->uTimerTS = TMTimerGet(pThis->pTimer);
-
- /* Fire off timer. */
- TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
-}
-
-static void hdaTimerMaybeStop(PHDASTATE pThis)
-{
- if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
- return;
-
- if (!pThis->pTimer)
- return;
-
- LogFlowFunc(("Stopping timer\n"));
-
- /* Set timer flag. */
- ASMAtomicXchgBool(&pThis->fTimerActive, false);
-}
-
static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
{
RT_NOREF(pDevIns);
@@ -4179,92 +3068,97 @@ static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pv
STAM_PROFILE_START(&pThis->StatTimer, a);
- uint64_t cTicksNow = TMTimerGet(pTimer);
+ uint32_t cbInMax = 0;
+ uint32_t cbOutMin = UINT32_MAX;
- LogFlowFuncEnter();
+ PHDADRIVER pDrv;
+
+ uint64_t cTicksNow = TMTimerGet(pTimer);
+ uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS;
+ uint64_t cTicksPerSec = TMTimerGetFreq(pTimer);
- /* Update current time timestamp. */
pThis->uTimerTS = cTicksNow;
- /* Flag indicating whether to kick the timer again for a
- * new data processing round. */
- bool fKickTimer = false;
+ /*
+ * Calculate the codec's (fixed) sampling rate.
+ */
+ AssertPtr(pThis->pCodec);
+ PDMPCMPROPS codecStrmProps;
- PHDASTREAM pStreamLineIn = hdaGetStreamFromSink(pThis, &pThis->SinkLineIn);
-#ifdef VBOX_WITH_HDA_MIC_IN
- PHDASTREAM pStreamMicIn = hdaGetStreamFromSink(pThis, &pThis->SinkMicIn);
-#endif
- PHDASTREAM pStreamFront = hdaGetStreamFromSink(pThis, &pThis->SinkFront);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- /** @todo See note below. */
-#endif
+ int rc = DrvAudioStreamCfgToProps(&pThis->pCodec->strmCfg, &codecStrmProps);
+ AssertRC(rc);
- uint32_t cbToProcess;
- int rc = AudioMixerSinkUpdate(pThis->SinkLineIn.pMixSink);
- if (RT_SUCCESS(rc))
- {
- cbToProcess = AudioMixerSinkGetReadable(pThis->SinkLineIn.pMixSink);
- if (cbToProcess)
- {
- rc = hdaTransfer(pThis, pStreamLineIn, cbToProcess, NULL /* pcbProcessed */);
- fKickTimer |= RT_SUCCESS(rc);
- }
- }
+ uint32_t cCodecSamplesMin = (int)((2 * cTicksElapsed * pThis->pCodec->strmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
+ uint32_t cbCodecSamplesMin = cCodecSamplesMin << codecStrmProps.cShift;
-#ifdef VBOX_WITH_HDA_MIC_IN
- rc = AudioMixerSinkUpdate(pThis->SinkMicIn.pMixSink);
- if (RT_SUCCESS(rc))
+ /*
+ * Process all driver nodes.
+ */
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
{
- cbToProcess = AudioMixerSinkGetReadable(pThis->SinkMicIn.pMixSink);
- if (cbToProcess)
+ uint32_t cbIn = 0;
+ uint32_t cbOut = 0;
+
+ rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector, &cbIn, &cbOut, NULL /* pcSamplesLive */);
+ if (RT_SUCCESS(rc))
+ rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* pcSamplesPlayed */);
+
+ Log3Func(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
+
+ /* If we there was an error handling (available) output or there simply is no output available,
+ * then calculate the minimum data rate which must be processed by the device emulation in order
+ * to function correctly.
+ *
+ * This is not the optimal solution, but as we have to deal with this on a timer-based approach
+ * (until we have the audio callbacks) we need to have device' DMA engines running. */
+ if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
{
- rc = hdaTransfer(pThis, pStreamMicIn, cbToProcess, NULL /* pcbProcessed */);
- fKickTimer |= RT_SUCCESS(rc);
+ /* Use the codec's (fixed) sampling rate. */
+ cbOut = RT_MAX(cbOut, cbCodecSamplesMin);
}
- }
-#endif
+ else
+ {
+ const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
+ if ( RT_FAILURE(rc)
+ || !fIsActiveOut)
+ {
+ uint32_t cSamplesMin = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
+ uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- rc = AudioMixerSinkUpdate(pThis->SinkCenterLFE.pMixSink);
- if (RT_SUCCESS(rc))
- {
+ Log3Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
+
+ cbOut = RT_MAX(cbOut, cbSamplesMin);
+ }
+ }
+ cbOutMin = RT_MIN(cbOutMin, cbOut);
+ cbInMax = RT_MAX(cbInMax, cbIn);
}
- rc = AudioMixerSinkUpdate(pThis->SinkRear.pMixSink);
- if (RT_SUCCESS(rc))
- {
+ Log3Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
- }
- /** @todo Check for stream interleaving and only call hdaTransfer() if required! */
+ if (cbOutMin == UINT32_MAX)
+ cbOutMin = 0;
/*
- * Only call hdaTransfer if CenterLFE and/or Rear are on different SDs,
- * otherwise we have to use the interleaved streams support for getting the data
- * out of the Front sink (depending on the mapping layout).
+ * Playback.
*/
-#endif
- rc = AudioMixerSinkUpdate(pThis->SinkFront.pMixSink);
- if (RT_SUCCESS(rc))
+ if (cbOutMin)
{
- cbToProcess = AudioMixerSinkGetWritable(pThis->SinkFront.pMixSink);
- if (cbToProcess)
- {
- rc = hdaTransfer(pThis, pStreamFront, cbToProcess, NULL /* pcbProcessed */);
- fKickTimer |= RT_SUCCESS(rc);
- }
+ Assert(cbOutMin != UINT32_MAX);
+ hdaTransfer(pThis, PO_INDEX, cbOutMin /* cbToProcess */, NULL /* pcbProcessed */);
}
- if ( ASMAtomicReadBool(&pThis->fTimerActive)
- || fKickTimer)
- {
- /* Kick the timer again. */
- uint64_t cTicks = pThis->cTimerTicks;
- /** @todo adjust cTicks down by now much cbOutMin represents. */
- TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
- }
+ /*
+ * Recording.
+ */
+ if (cbInMax)
+ hdaTransfer(pThis, PI_INDEX, cbInMax /* cbToProcess */, NULL /* pcbProcessed */);
- LogFlowFuncLeave();
+ /* Kick the timer again. */
+ uint64_t cTicks = pThis->cTimerTicks;
+ /** @todo adjust cTicks down by now much cbOutMin represents. */
+ TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
STAM_PROFILE_STOP(&pThis->StatTimer, a);
}
@@ -4312,201 +3206,156 @@ static DECLCALLBACK(int) hdaCallbackOutput(PDMAUDIOCALLBACKTYPE enmType, void *p
RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
{
uint32_t cSamplesPlayed;
- int rc2 = pDrv->pConnector->pfnPlay(pDrv->pConnector, &cSamplesPlayed);
+ int rc2 = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, &cSamplesPlayed);
LogFlowFunc(("LUN#%RU8: cSamplesPlayed=%RU32, rc=%Rrc\n", pDrv->uLUN, cSamplesPlayed, rc2));
}
}
}
#endif /* VBOX_WITH_AUDIO_CALLBACKS */
-static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
+static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbToProcess, uint32_t *pcbProcessed)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
/* pcbProcessed is optional. */
if (ASMAtomicReadBool(&pThis->fInReset)) /* HDA controller in reset mode? Bail out. */
{
- LogFlowFunc(("HDA in reset mode, skipping\n"));
+ LogFlowFunc(("In reset mode, skipping\n"));
+
+ if (pcbProcessed)
+ *pcbProcessed = 0;
+ return VINF_SUCCESS;
+ }
+
+ PHDASTREAM pStrmSt;
+ switch (enmSrc)
+ {
+ case PI_INDEX:
+ {
+ pStrmSt = &pThis->StrmStLineIn;
+ break;
+ }
+
+#ifdef VBOX_WITH_HDA_MIC_IN
+ case MC_INDEX:
+ {
+ pStrmSt = &pThis->StrmStMicIn;
+ break;
+ }
+#endif
+ case PO_INDEX:
+ {
+ pStrmSt = &pThis->StrmStOut;
+ break;
+ }
- if (pcbProcessed)
- *pcbProcessed = 0;
- return VINF_SUCCESS;
+ default:
+ {
+ AssertMsgFailed(("Unknown source index %ld\n", enmSrc));
+ return VERR_NOT_SUPPORTED;
+ }
}
+ int rc = VINF_SUCCESS;
bool fProceed = true;
- int rc = RTCritSectEnter(&pStream->State.CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- Log3Func(("[SD%RU8] fActive=%RTbool, cbToProcess=%RU32\n", pStream->u8SD, pStream->State.fActive, cbToProcess));
/* Stop request received? */
- if ( !pStream->State.fActive
- || pStream->State.fDoStop)
+ if (ASMAtomicReadBool(&pStrmSt->State.fDoStop))
{
- pStream->State.fActive = false;
+ pStrmSt->State.fActive = false;
- rc = RTSemEventSignal(pStream->State.hStateChangedEvent);
+ rc = RTSemEventSignal(pStrmSt->State.hStateChangedEvent);
AssertRC(rc);
fProceed = false;
}
/* Is the stream not in a running state currently? */
- else if (!(HDA_STREAM_REG(pThis, CTL, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
+ else if (!(HDA_STREAM_REG(pThis, CTL, pStrmSt->u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
fProceed = false;
/* Nothing to process? */
else if (!cbToProcess)
fProceed = false;
- if ((HDA_STREAM_REG(pThis, STS, pStream->u8SD) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
- {
- Log3Func(("[SD%RU8]: BCIS set\n", pStream->u8SD));
- fProceed = false;
- }
-
if (!fProceed)
{
- Log3Func(("[SD%RU8]: Skipping\n", pStream->u8SD));
-
- rc = RTCritSectLeave(&pStream->State.CritSect);
- AssertRC(rc);
-
if (pcbProcessed)
*pcbProcessed = 0;
return VINF_SUCCESS;
}
+ LogFlowFunc(("enmSrc=%RU32, cbToProcess=%RU32\n", enmSrc, cbToProcess));
+
/* Sanity checks. */
- Assert(pStream->u8SD <= HDA_MAX_STREAMS);
- Assert(pStream->u64BDLBase);
- Assert(pStream->u32CBL);
+ Assert(pStrmSt->u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
+ Assert(pStrmSt->u64BDLBase);
+ Assert(pStrmSt->u32CBL);
/* State sanity checks. */
- Assert(pStream->State.fInReset == false);
- Assert(HDA_STREAM_REG(pThis, LPIB, pStream->u8SD) <= pStream->u32CBL);
-
- bool fInterrupt = false;
-
-#ifdef DEBUG_andy
-//# define DEBUG_SIMPLE
-#endif
-
-#ifdef DEBUG_SIMPLE
- uint8_t u8FIFO[_16K+1];
- size_t u8FIFOff = 0;
-#endif
-
- uint32_t cbLeft = cbToProcess;
- uint32_t cbTotal = 0;
- uint32_t cbChunk = 0;
- uint32_t cbChunkProcessed = 0;
+ Assert(ASMAtomicReadBool(&pStrmSt->State.fInReset) == false);
- /* Set the FIFORDY bit on the stream while doing the transfer. */
- HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+ uint32_t cbProcessedTotal = 0;
+ bool fIsComplete = false;
- while (cbLeft)
+ while (cbToProcess)
{
/* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
- if (hdaStreamNeedsNextBDLE(pThis, pStream))
- {
- rc = hdaStreamGetNextBDLE(pThis, pStream);
- if (RT_FAILURE(rc))
- break;
- }
+ if (hdaStreamNeedsNextBDLE(pThis, pStrmSt))
+ hdaStreamGetNextBDLE(pThis, pStrmSt);
- cbChunk = hdaStreamGetTransferSize(pThis, pStream, cbLeft);
- cbChunkProcessed = 0;
+ /* Set the FIFORDY bit on the stream while doing the transfer. */
+ HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
- if (hdaGetDirFromSD(pStream->u8SD) == PDMAUDIODIR_IN)
- rc = hdaReadAudio(pThis, pStream, cbChunk, &cbChunkProcessed);
- else
+ uint32_t cbProcessed = 0;
+ switch (enmSrc)
{
-#ifndef DEBUG_SIMPLE
- rc = hdaWriteAudio(pThis, pStream, cbChunk, &cbChunkProcessed);
-#else
- void *pvBuf = u8FIFO + u8FIFOff;
- int32_t cbBuf = cbChunk;
-
- PHDABDLE pBDLE = &pStream->State.BDLE;
-
- if (cbBuf)
- rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
- pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
- pvBuf, cbBuf);
-
- cbChunkProcessed = cbChunk;
-
- hdaBDLEUpdate(pBDLE, cbChunkProcessed, cbChunkProcessed);
-
- u8FIFOff += cbChunkProcessed;
- Assert((u8FIFOff & 1) == 0);
- Assert(u8FIFOff <= sizeof(u8FIFO));
+ case PI_INDEX:
+ rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkLineIn, cbToProcess, &cbProcessed);
+ break;
+ case PO_INDEX:
+ rc = hdaWriteAudio(pThis, pStrmSt, cbToProcess, &cbProcessed);
+ break;
+#ifdef VBOX_WITH_HDA_MIC_IN
+ case MC_INDEX:
+ rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkMicIn, cbToProcess, &cbProcessed);
+ break;
#endif
+ default:
+ AssertMsgFailed(("Unsupported source index %ld\n", enmSrc));
+ rc = VERR_NOT_SUPPORTED;
+ break;
}
- if (RT_FAILURE(rc))
- break;
-
- hdaStreamTransferUpdate(pThis, pStream, cbChunkProcessed);
-
- Assert(cbLeft >= cbChunkProcessed);
- cbLeft -= cbChunkProcessed;
- cbTotal += cbChunkProcessed;
+ /* Remove the FIFORDY bit again. */
+ HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
- if (rc == VINF_EOF)
- break;
-
- if (hdaStreamTransferIsComplete(pThis, pStream, &fInterrupt))
+ if (RT_FAILURE(rc))
break;
- }
- /* Remove the FIFORDY bit again. */
- HDA_STREAM_REG(pThis, STS, pStream->u8SD) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
+ hdaStreamTransferUpdate(pThis, pStrmSt, cbProcessed);
- LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8SD, cbTotal, cbToProcess, rc));
+ cbToProcess -= RT_MIN(cbToProcess, cbProcessed);
+ cbProcessedTotal += cbProcessed;
-#ifdef DEBUG_SIMPLE
-# ifdef HDA_DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- RTFileOpen(&fh, HDA_DEBUG_DUMP_PCM_DATA_PATH "hdaWriteAudio.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- RTFileWrite(fh, u8FIFO, u8FIFOff, NULL);
- RTFileClose(fh);
-# endif
+ LogFlowFunc(("cbProcessed=%RU32, cbToProcess=%RU32, cbProcessedTotal=%RU32, rc=%Rrc\n",
+ cbProcessed, cbToProcess, cbProcessedTotal, rc));
- AudioMixerSinkWrite(pThis->SinkFront.pMixSink, AUDMIXOP_COPY, u8FIFO, u8FIFOff,
- NULL /* pcbWritten */);
-#endif /* DEBUG_SIMPLE */
+ if (rc == VINF_EOF)
+ fIsComplete = true;
- if (fInterrupt)
- {
- /**
- * Set the BCIS (Buffer Completion Interrupt Status) flag as the
- * last byte of data for the current descriptor has been fetched
- * from memory and put into the DMA FIFO.
- *
- * Speech synthesis works fine on Mac Guest if this bit isn't set
- * but in general sound quality gets worse.
- *
- * This must be set in *any* case.
- */
- HDA_STREAM_REG(pThis, STS, pStream->u8SD) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
- Log3Func(("[SD%RU8]: BCIS: Set\n", pStream->u8SD));
+ if (!fIsComplete)
+ fIsComplete = hdaStreamTransferIsComplete(pThis, pStrmSt);
- hdaProcessInterrupt(pThis);
+ if (fIsComplete)
+ break;
}
if (RT_SUCCESS(rc))
{
if (pcbProcessed)
- *pcbProcessed = cbTotal;
+ *pcbProcessed = cbProcessedTotal;
}
- int rc2 = RTCritSectLeave(&pStream->State.CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
+ LogFlowFuncLeaveRC(rc);
return rc;
}
#endif /* IN_RING3 */
@@ -4522,28 +3371,28 @@ static int hdaTransfer(PHDASTATE pThis, PHDASTREAM pStream, uint32_t cbToProcess
*/
PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
+ RT_NOREF(pvUser);
+ PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
int rc;
- RT_NOREF_PV(pvUser);
/*
* Look up and log.
*/
uint32_t offReg = GCPhysAddr - pThis->MMIOBaseAddr;
- int idxRegDsc = hdaRegLookup(offReg); /* Register descriptor index. */
+ int idxRegDsc = hdaRegLookup(pThis, offReg); /* Register descriptor index. */
#ifdef LOG_ENABLED
unsigned const cbLog = cb;
uint32_t offRegLog = offReg;
#endif
- Log3Func(("offReg=%#x cb=%#x\n", offReg, cb));
+ LogFunc(("offReg=%#x cb=%#x\n", offReg, cb));
Assert(cb == 4); Assert((offReg & 3) == 0);
if (pThis->fInReset && idxRegDsc != HDA_REG_GCTL)
- LogFunc(("Access to registers except GCTL is blocked while reset\n"));
+ LogFunc(("\tAccess to registers except GCTL is blocked while reset\n"));
if (idxRegDsc == -1)
- LogRel(("HDA: Invalid read access @0x%x (bytes=%u)\n", offReg, cb));
+ LogRel(("HDA: Invalid read access @0x%x (bytes=%d)\n", offReg, cb));
if (idxRegDsc != -1)
{
@@ -4554,7 +3403,7 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
* Straight forward DWORD access.
*/
rc = g_aHdaRegMap[idxRegDsc].pfnRead(pThis, idxRegDsc, (uint32_t *)pv);
- Log3Func(("\tRead %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].abbrev, *(uint32_t *)pv, rc));
+ LogFunc(("\tRead %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].abbrev, *(uint32_t *)pv, rc));
}
else
{
@@ -4570,7 +3419,7 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
uint32_t u32Tmp = 0;
rc = g_aHdaRegMap[idxRegDsc].pfnRead(pThis, idxRegDsc, &u32Tmp);
- Log3Func(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, rc));
+ LogFunc(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, rc));
if (rc != VINF_SUCCESS)
break;
u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8);
@@ -4589,7 +3438,7 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
else
{
rc = VINF_IOM_MMIO_UNUSED_FF;
- Log3Func(("\tHole at %x is accessed for read\n", offReg));
+ LogFunc(("\tHole at %x is accessed for read\n", offReg));
}
/*
@@ -4597,11 +3446,11 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
*/
#ifdef LOG_ENABLED
if (cbLog == 4)
- Log3Func(("\tReturning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc));
+ LogFunc(("\tReturning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc));
else if (cbLog == 2)
- Log3Func(("\tReturning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc));
+ LogFunc(("\tReturning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc));
else if (cbLog == 1)
- Log3Func(("\tReturning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc));
+ LogFunc(("\tReturning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc));
#endif
return rc;
}
@@ -4609,20 +3458,20 @@ PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhys
DECLINLINE(int) hdaWriteReg(PHDASTATE pThis, int idxRegDsc, uint32_t u32Value, char const *pszLog)
{
+ RT_NOREF(pszLog);
if (pThis->fInReset && idxRegDsc != HDA_REG_GCTL)
{
- LogRel2(("HDA: Warning: Access to register 0x%x is blocked while reset\n", idxRegDsc));
+ LogRel2(("HDA: Access to register 0x%x is blocked while reset\n", idxRegDsc));
return VINF_SUCCESS;
}
#ifdef LOG_ENABLED
- uint32_t const idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
+ uint32_t idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
uint32_t const u32CurValue = pThis->au32Regs[idxRegMem];
#endif
int rc = g_aHdaRegMap[idxRegDsc].pfnWrite(pThis, idxRegDsc, u32Value);
- Log3Func(("Written value %#x to %s[%d byte]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxRegDsc].abbrev,
- g_aHdaRegMap[idxRegDsc].size, u32CurValue, pThis->au32Regs[idxRegMem], pszLog));
- RT_NOREF1(pszLog);
+ LogFunc(("write %#x -> %s[%db]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxRegDsc].abbrev,
+ g_aHdaRegMap[idxRegDsc].size, u32CurValue, pThis->au32Regs[idxRegMem], pszLog));
return rc;
}
@@ -4632,9 +3481,9 @@ DECLINLINE(int) hdaWriteReg(PHDASTATE pThis, int idxRegDsc, uint32_t u32Value, c
*/
PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
+ RT_NOREF(pvUser);
+ PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
int rc;
- RT_NOREF_PV(pvUser);
/*
* The behavior of accesses that aren't aligned on natural boundraries is
@@ -4649,7 +3498,7 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
* Look up and log the access.
*/
uint32_t offReg = GCPhysAddr - pThis->MMIOBaseAddr;
- int idxRegDsc = hdaRegLookup(offReg);
+ int idxRegDsc = hdaRegLookup(pThis, offReg);
uint32_t idxRegMem = idxRegDsc != -1 ? g_aHdaRegMap[idxRegDsc].mem_idx : UINT32_MAX;
uint64_t u64Value;
if (cb == 4) u64Value = *(uint32_t const *)pv;
@@ -4665,16 +3514,16 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
#ifdef LOG_ENABLED
uint32_t const u32LogOldValue = idxRegDsc >= 0 ? pThis->au32Regs[idxRegMem] : UINT32_MAX;
if (idxRegDsc == -1)
- Log3Func(("@%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb));
+ LogFunc(("@%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb));
else if (cb == 4)
- Log3Func(("@%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+ LogFunc(("@%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
else if (cb == 2)
- Log3Func(("@%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+ LogFunc(("@%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
else if (cb == 1)
- Log3Func(("@%#05x u8=%#04x (%#010x) %s\n", offReg, *(uint8_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
+ LogFunc(("@%#05x u8=%#04x (%#010x) %s\n", offReg, *(uint8_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
if (idxRegDsc >= 0 && g_aHdaRegMap[idxRegDsc].size != cb)
- Log3Func(("\tsize=%RU32 != cb=%u!!\n", g_aHdaRegMap[idxRegDsc].size, cb));
+ LogFunc(("\tsize=%RU32 != cb=%u!!\n", g_aHdaRegMap[idxRegDsc].size, cb));
#endif
/*
@@ -4683,7 +3532,9 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
if (idxRegDsc != -1 && g_aHdaRegMap[idxRegDsc].size == cb)
{
rc = hdaWriteReg(pThis, idxRegDsc, u64Value, "");
- Log3Func(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
+#ifdef LOG_ENABLED
+ LogFunc(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
+#endif
}
/*
* Partial or multiple register access, loop thru the requested memory.
@@ -4696,15 +3547,15 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
* will only see 1 or 2 byte accesses of this kind, so no risk of
* shifting out input values.
*/
- if (idxRegDsc == -1 && (idxRegDsc = hdaRegLookupWithin(offReg)) != -1)
+ if (idxRegDsc == -1 && (idxRegDsc = hdaRegLookupWithin(pThis, offReg)) != -1)
{
uint32_t const cbBefore = offReg - g_aHdaRegMap[idxRegDsc].offset; Assert(cbBefore > 0 && cbBefore < 4);
offReg -= cbBefore;
idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
u64Value <<= cbBefore * 8;
u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbBefore];
- Log3Func(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
- cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
+ LogFunc(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
+ cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
}
/* Loop thru the write area, it may cover multiple registers. */
@@ -4719,14 +3570,14 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
if (cb < cbReg)
{
u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbReg] & ~g_afMasks[cb];
- Log3Func(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
- g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
+ LogFunc(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
+ g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
}
#ifdef LOG_ENABLED
- uint32_t uLogOldVal = pThis->au32Regs[idxRegMem];
+ uint32_t const u32LogOldVal = pThis->au32Regs[idxRegMem];
#endif
rc = hdaWriteReg(pThis, idxRegDsc, u64Value, "*");
- Log3Func(("\t%#x -> %#x\n", uLogOldVal, pThis->au32Regs[idxRegMem]));
+ LogFunc(("\t%#x -> %#x\n", u32LogOldVal, pThis->au32Regs[idxRegMem]));
}
else
{
@@ -4743,7 +3594,7 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
cb -= cbReg;
u64Value >>= cbReg * 8;
if (idxRegDsc == -1)
- idxRegDsc = hdaRegLookup(offReg);
+ idxRegDsc = hdaRegLookup(pThis, offReg);
else
{
idxRegDsc++;
@@ -4766,11 +3617,11 @@ PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhy
/**
* @callback_method_impl{FNPCIIOREGIONMAP}
*/
-static DECLCALLBACK(int) hdaPciIoRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
- RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) hdaPciIoRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
+ RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
{
RT_NOREF(iRegion, enmType);
- PHDASTATE pThis = RT_FROM_MEMBER(pPciDev, HDASTATE, PciDev);
+ PHDASTATE pThis = RT_FROM_MEMBER(pPciDev, HDASTATE, PciDev);
/*
* 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word.
@@ -4780,8 +3631,10 @@ static DECLCALLBACK(int) hdaPciIoRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciD
*/
Assert(enmType == PCI_ADDRESS_SPACE_MEM);
int rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
- IOMMMIO_FLAGS_READ_DWORD | IOMMMIO_FLAGS_WRITE_PASSTHRU,
+ IOMMMIO_FLAGS_READ_DWORD
+ | IOMMMIO_FLAGS_WRITE_PASSTHRU,
hdaMMIOWrite, hdaMMIORead, "HDA");
+
if (RT_FAILURE(rc))
return rc;
@@ -4811,24 +3664,25 @@ static DECLCALLBACK(int) hdaPciIoRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciD
static int hdaSaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStrm)
{
RT_NOREF(pDevIns);
-#ifdef DEBUG
+#ifdef VBOX_STRICT
PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
#endif
- LogFlowFunc(("[SD%RU8]\n", pStrm->u8SD));
+
+ LogFlowFunc(("[SD%RU8]\n", pStrm->u8Strm));
/* Save stream ID. */
- int rc = SSMR3PutU8(pSSM, pStrm->u8SD);
+ int rc = SSMR3PutU8(pSSM, pStrm->u8Strm);
AssertRCReturn(rc, rc);
- Assert(pStrm->u8SD <= HDA_MAX_STREAMS);
+ Assert(pStrm->u8Strm <= 7); /** @todo Use a define. */
rc = SSMR3PutStructEx(pSSM, &pStrm->State, sizeof(HDASTREAMSTATE), 0 /*fFlags*/, g_aSSMStreamStateFields6, NULL);
AssertRCReturn(rc, rc);
-#ifdef DEBUG /* Sanity checks. */
- uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrm->u8SD),
- HDA_STREAM_REG(pThis, BDPU, pStrm->u8SD));
- uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, pStrm->u8SD);
- uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, pStrm->u8SD);
+#ifdef VBOX_STRICT /* Sanity checks. */
+ uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrm->u8Strm),
+ HDA_STREAM_REG(pThis, BDPU, pStrm->u8Strm));
+ uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, pStrm->u8Strm);
+ uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, pStrm->u8Strm);
hdaBDLEDumpAll(pThis, u64BaseDMA, u16LVI + 1);
@@ -4845,7 +3699,7 @@ static int hdaSaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStrm)
0 /*fFlags*/, g_aSSMBDLEStateFields6, NULL);
AssertRCReturn(rc, rc);
-#ifdef DEBUG /* Sanity checks. */
+#ifdef VBOX_STRICT /* Sanity checks. */
PHDABDLE pBDLE = &pStrm->State.BDLE;
if (u64BaseDMA)
{
@@ -4879,20 +3733,28 @@ static DECLCALLBACK(int) hdaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
hdaCodecSaveState(pThis->pCodec, pSSM);
/* Save MMIO registers. */
+ AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= HDA_NREGS_SAVED);
SSMR3PutU32(pSSM, RT_ELEMENTS(pThis->au32Regs));
SSMR3PutMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
/* Save number of streams. */
- SSMR3PutU32(pSSM, HDA_MAX_STREAMS);
+#ifdef VBOX_WITH_HDA_MIC_IN
+ SSMR3PutU32(pSSM, 3);
+#else
+ SSMR3PutU32(pSSM, 2);
+#endif
/* Save stream states. */
- for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
- {
- int rc = hdaSaveStream(pDevIns, pSSM, &pThis->aStreams[i]);
- AssertRCReturn(rc, rc);
- }
+ int rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStOut);
+ AssertRCReturn(rc, rc);
+#ifdef VBOX_WITH_HDA_MIC_IN
+ rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStMicIn);
+ AssertRCReturn(rc, rc);
+#endif
+ rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStLineIn);
+ AssertRCReturn(rc, rc);
- return VINF_SUCCESS;
+ return rc;
}
@@ -4941,7 +3803,7 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
case HDA_SSM_VERSION_2:
case HDA_SSM_VERSION_3:
cRegs = 112;
- AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= 112);
+ AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= HDA_NREGS_SAVED);
break;
/* Since version 4 we store the register count to stay flexible. */
@@ -5015,28 +3877,25 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
/* Note 2: The stream's saving order is/was fixed, so don't touch! */
/* Output */
- PHDASTREAM pStream = &pThis->aStreams[4];
- rc = hdaStreamInit(pThis, pStream, 4 /* Stream descriptor, hardcoded */);
+ rc = hdaStreamInit(pThis, &pThis->StrmStOut, 4 /* Stream number, hardcoded */);
if (RT_FAILURE(rc))
break;
- HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
- pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+ HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStOut.State.BDLE);
+ pThis->StrmStOut.State.uCurBDLE = pThis->StrmStOut.State.BDLE.State.u32BDLIndex;
/* Microphone-In */
- pStream = &pThis->aStreams[2];
- rc = hdaStreamInit(pThis, pStream, 2 /* Stream descriptor, hardcoded */);
+ rc = hdaStreamInit(pThis, &pThis->StrmStMicIn, 2 /* Stream number, hardcoded */);
if (RT_FAILURE(rc))
break;
- HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
- pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+ HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStMicIn.State.BDLE);
+ pThis->StrmStMicIn.State.uCurBDLE = pThis->StrmStMicIn.State.BDLE.State.u32BDLIndex;
/* Line-In */
- pStream = &pThis->aStreams[0];
- rc = hdaStreamInit(pThis, pStream, 0 /* Stream descriptor, hardcoded */);
+ rc = hdaStreamInit(pThis, &pThis->StrmStLineIn, 0 /* Stream number, hardcoded */);
if (RT_FAILURE(rc))
break;
- HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pStream->State.BDLE);
- pStream->State.uCurBDLE = pStream->State.BDLE.State.u32BDLIndex;
+ HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStLineIn.State.BDLE);
+ pThis->StrmStLineIn.State.uCurBDLE = pThis->StrmStLineIn.State.BDLE.State.u32BDLIndex;
break;
}
@@ -5054,26 +3913,26 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
/* Load stream states. */
for (uint32_t i = 0; i < cStreams; i++)
{
- uint8_t uSD;
- rc = SSMR3GetU8(pSSM, &uSD);
+ uint8_t uStreamID;
+ rc = SSMR3GetU8(pSSM, &uStreamID);
if (RT_FAILURE(rc))
break;
- PHDASTREAM pStrm = hdaStreamFromSD(pThis, uSD);
+ PHDASTREAM pStrm = hdaStreamFromID(pThis, uStreamID);
HDASTREAM StreamDummy;
if (!pStrm)
{
- RT_ZERO(StreamDummy);
pStrm = &StreamDummy;
- LogRel2(("HDA: Warning: Stream ID=%RU32 not supported, skipping to load ...\n", uSD));
- break;
+ LogRel2(("HDA: Warning: Stream ID=%RU32 not supported, skipping to load ...\n", uStreamID));
}
- rc = hdaStreamInit(pThis, pStrm, uSD);
+ RT_BZERO(pStrm, sizeof(HDASTREAM));
+
+ rc = hdaStreamInit(pThis, pStrm, uStreamID);
if (RT_FAILURE(rc))
{
- LogRel(("HDA: Stream #%RU32: Initialization of stream %RU8 failed, rc=%Rrc\n", i, uSD, rc));
+ LogRel(("HDA: Stream #%RU32: Initialization of stream %RU8 failed, rc=%Rrc\n", i, uStreamID, rc));
break;
}
@@ -5153,35 +4012,42 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
if (RT_SUCCESS(rc))
{
- pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
- pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
- pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE), HDA_REG(pThis, DPUBASE));
+ /*
+ * Update stuff after the state changes.
+ */
+ bool fEnableIn = RT_BOOL(HDA_SDCTL(pThis, 0 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+#ifdef VBOX_WITH_HDA_MIC_IN
+ bool fEnableMicIn = RT_BOOL(HDA_SDCTL(pThis, 2 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+#endif
+ bool fEnableOut = RT_BOOL(HDA_SDCTL(pThis, 4 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
- /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
- pThis->fDMAPosition = RT_BOOL(pThis->u64DPBase & RT_BIT_64(0));
+ PHDADRIVER pDrv;
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ {
+ rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, fEnableIn);
+ if (RT_FAILURE(rc))
+ break;
+#ifdef VBOX_WITH_HDA_MIC_IN
+ rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, fEnableMicIn);
+ if (RT_FAILURE(rc))
+ break;
+#endif
+ rc = pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, fEnableOut);
+ if (RT_FAILURE(rc))
+ break;
+ }
}
if (RT_SUCCESS(rc))
{
- for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
- {
- PHDASTREAM pStream = hdaStreamFromSD(pThis, i);
- if (pStream)
- {
- /* Deactive first. */
- int rc2 = hdaStreamSetActive(pThis, pStream, false);
- AssertRC(rc2);
-
- bool fActive = RT_BOOL(HDA_STREAM_REG(pThis, CTL, i) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
+ pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
+ pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
+ pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE), HDA_REG(pThis, DPUBASE));
- /* Activate, if needed. */
- rc2 = hdaStreamSetActive(pThis, pStream, fActive);
- AssertRC(rc2);
- }
- }
+ /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
+ pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
}
-
- if (RT_FAILURE(rc))
+ else
LogRel(("HDA: Failed loading device state (version %RU32, pass 0x%x), rc=%Rrc\n", uVersion, uPass, rc));
LogFlowFuncLeaveRC(rc);
@@ -5195,16 +4061,15 @@ static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32
* @callback_method_impl{FNRTSTRFORMATTYPE}
*/
static DECLCALLBACK(size_t) hdaDbgFmtBDLE(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
- const char *pszType, void const *pvValue,
- int cchWidth, int cchPrecision, unsigned fFlags,
- void *pvUser)
+ const char *pszType, void const *pvValue,
+ int cchWidth, int cchPrecision, unsigned fFlags,
+ void *pvUser)
{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
+ RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
PHDABDLE pBDLE = (PHDABDLE)pvValue;
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "BDLE(idx:%RU32, off:%RU32, fifow:%RU32, IOC:%RTbool, DMA[%RU32 bytes @ 0x%x])",
- pBDLE->State.u32BDLIndex, pBDLE->State.u32BufOff, pBDLE->State.cbBelowFIFOW, pBDLE->fIntOnCompletion,
- pBDLE->u32BufSize, pBDLE->u64BufAdr);
+ "BDLE(idx:%RU32, off:%RU32, fifow:%RU32, DMA[%RU32 bytes @ 0x%x])",
+ pBDLE->State.u32BDLIndex, pBDLE->State.u32BufOff, pBDLE->State.cbBelowFIFOW, pBDLE->u32BufSize, pBDLE->u64BufAdr);
}
/**
@@ -5215,7 +4080,7 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDCTL(PFNRTSTROUTPUT pfnOutput, void *pvArg
int cchWidth, int cchPrecision, unsigned fFlags,
void *pvUser)
{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
+ RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
uint32_t uSDCTL = (uint32_t)(uintptr_t)pvValue;
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
"SDCTL(raw:%#x, DIR:%s, TP:%RTbool, STRIPE:%x, DEIE:%RTbool, FEIE:%RTbool, IOCE:%RTbool, RUN:%RTbool, RESET:%RTbool)",
@@ -5238,7 +4103,7 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDFIFOS(PFNRTSTROUTPUT pfnOutput, void *pvA
int cchWidth, int cchPrecision, unsigned fFlags,
void *pvUser)
{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
+ RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
uint32_t uSDFIFOS = (uint32_t)(uintptr_t)pvValue;
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOS(raw:%#x, sdfifos:%RU8 B)", uSDFIFOS, hdaSDFIFOSToBytes(uSDFIFOS));
}
@@ -5251,7 +4116,7 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDFIFOW(PFNRTSTROUTPUT pfnOutput, void *pvA
int cchWidth, int cchPrecision, unsigned fFlags,
void *pvUser)
{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
+ RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
uint32_t uSDFIFOW = (uint32_t)(uintptr_t)pvValue;
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOW(raw: %#0x, sdfifow:%d B)", uSDFIFOW, hdaSDFIFOWToBytes(uSDFIFOW));
}
@@ -5264,7 +4129,7 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDSTS(PFNRTSTROUTPUT pfnOutput, void *pvArg
int cchWidth, int cchPrecision, unsigned fFlags,
void *pvUser)
{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
+ RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
uint32_t uSdSts = (uint32_t)(uintptr_t)pvValue;
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
"SDSTS(raw:%#0x, fifordy:%RTbool, dese:%RTbool, fifoe:%RTbool, bcis:%RTbool)",
@@ -5275,10 +4140,10 @@ static DECLCALLBACK(size_t) hdaDbgFmtSDSTS(PFNRTSTROUTPUT pfnOutput, void *pvArg
RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)));
}
-static int hdaDbgLookupRegByName(const char *pszArgs)
+static int hdaLookUpRegisterByName(const char *pszArgs)
{
int iReg = 0;
- for (; iReg < HDA_NUM_REGS; ++iReg)
+ for (; iReg < HDA_NREGS; ++iReg)
if (!RTStrICmp(g_aHdaRegMap[iReg].abbrev, pszArgs))
return iReg;
return -1;
@@ -5289,136 +4154,61 @@ static void hdaDbgPrintRegister(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaInd
{
Assert( pThis
&& iHdaIndex >= 0
- && iHdaIndex < HDA_NUM_REGS);
+ && iHdaIndex < HDA_NREGS);
pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].mem_idx]);
}
/**
* @callback_method_impl{FNDBGFHANDLERDEV}
*/
-static DECLCALLBACK(void) hdaDbgInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- int iHdaRegisterIndex = hdaDbgLookupRegByName(pszArgs);
+ int iHdaRegisterIndex = hdaLookUpRegisterByName(pszArgs);
if (iHdaRegisterIndex != -1)
hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
else
- {
- for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NUM_REGS; ++iHdaRegisterIndex)
+ for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NREGS; ++iHdaRegisterIndex)
hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
- }
-}
-
-static void hdaDbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
-{
- Assert( pThis
- && iIdx >= 0
- && iIdx < HDA_MAX_STREAMS);
-
- const PHDASTREAM pStrm = &pThis->aStreams[iIdx];
-
- pHlp->pfnPrintf(pHlp, "Stream #%d:\n", iIdx);
- pHlp->pfnPrintf(pHlp, "\tSD%dCTL : %R[sdctl]\n", iIdx, HDA_STREAM_REG(pThis, CTL, iIdx));
- pHlp->pfnPrintf(pHlp, "\tSD%dCTS : %R[sdsts]\n", iIdx, HDA_STREAM_REG(pThis, STS, iIdx));
- pHlp->pfnPrintf(pHlp, "\tSD%dFIFOS: %R[sdfifos]\n", iIdx, HDA_STREAM_REG(pThis, FIFOS, iIdx));
- pHlp->pfnPrintf(pHlp, "\tSD%dFIFOW: %R[sdfifow]\n", iIdx, HDA_STREAM_REG(pThis, FIFOW, iIdx));
- pHlp->pfnPrintf(pHlp, "\tBDLE : %R[bdle]\n", &pStrm->State.BDLE);
}
-static void hdaDbgPrintBDLE(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iIdx)
+static void hdaDbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaStrmIndex)
{
Assert( pThis
- && iIdx >= 0
- && iIdx < HDA_MAX_STREAMS);
-
- const PHDASTREAM pStrm = &pThis->aStreams[iIdx];
- const PHDABDLE pBDLE = &pStrm->State.BDLE;
-
- pHlp->pfnPrintf(pHlp, "Stream #%d BDLE:\n", iIdx);
- pHlp->pfnPrintf(pHlp, "\t%R[bdle]\n", pBDLE);
-
- uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, iIdx),
- HDA_STREAM_REG(pThis, BDPU, iIdx));
- uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, iIdx);
- /*uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, iIdx); - unused */
-
- if (!u64BaseDMA)
- return;
-
- uint32_t cbBDLE = 0;
- for (uint16_t i = 0; i < u16LVI + 1; i++)
- {
- uint8_t bdle[16]; /** @todo Use a define. */
- PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BaseDMA + i * 16, bdle, 16); /** @todo Use a define. */
-
- uint64_t addr = *(uint64_t *)bdle;
- uint32_t len = *(uint32_t *)&bdle[8];
- uint32_t ioc = *(uint32_t *)&bdle[12];
-
- pHlp->pfnPrintf(pHlp, "\t#%03d BDLE(adr:0x%llx, size:%RU32, ioc:%RTbool)\n",
- i, addr, len, RT_BOOL(ioc & 0x1));
-
- cbBDLE += len;
- }
-
- pHlp->pfnPrintf(pHlp, "Total: %RU32 bytes\n", cbBDLE);
-
- pHlp->pfnPrintf(pHlp, "DMA counters (base @ 0x%llx):\n", pThis->u64DPBase);
- if (!pThis->u64DPBase) /* No DMA base given? Bail out. */
- {
- pHlp->pfnPrintf(pHlp, "No counters found\n");
- return;
- }
-
- for (int i = 0; i < u16LVI + 1; i++)
- {
- uint32_t uDMACnt;
- PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)),
- &uDMACnt, sizeof(uDMACnt));
-
- pHlp->pfnPrintf(pHlp, "\t#%03d DMA @ 0x%x\n", i , uDMACnt);
- }
+ && iHdaStrmIndex >= 0
+ && iHdaStrmIndex < 7);
+ pHlp->pfnPrintf(pHlp, "Dump of %d HDA Stream:\n", iHdaStrmIndex);
+ pHlp->pfnPrintf(pHlp, "SD%dCTL: %R[sdctl]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, CTL, iHdaStrmIndex));
+ pHlp->pfnPrintf(pHlp, "SD%dCTS: %R[sdsts]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, STS, iHdaStrmIndex));
+ pHlp->pfnPrintf(pHlp, "SD%dFIFOS: %R[sdfifos]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, FIFOS, iHdaStrmIndex));
+ pHlp->pfnPrintf(pHlp, "SD%dFIFOW: %R[sdfifow]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, FIFOW, iHdaStrmIndex));
}
-static int hdaDbgLookupStrmIdx(PHDASTATE pThis, const char *pszArgs)
+static int hdaLookUpStreamIndex(PHDASTATE pThis, const char *pszArgs)
{
RT_NOREF(pThis, pszArgs);
- /** @todo Add args parsing. */
+ /** @todo add args parsing */
return -1;
}
/**
* @callback_method_impl{FNDBGFHANDLERDEV}
*/
-static DECLCALLBACK(void) hdaDbgInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- int iHdaStreamdex = hdaDbgLookupStrmIdx(pThis, pszArgs);
- if (iHdaStreamdex != -1)
- hdaDbgPrintStream(pThis, pHlp, iHdaStreamdex);
- else
- for(iHdaStreamdex = 0; iHdaStreamdex < HDA_MAX_STREAMS; ++iHdaStreamdex)
- hdaDbgPrintStream(pThis, pHlp, iHdaStreamdex);
-}
-
-/**
- * @callback_method_impl{FNDBGFHANDLERDEV}
- */
-static DECLCALLBACK(void) hdaDbgInfoBDLE(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- int iHdaStreamdex = hdaDbgLookupStrmIdx(pThis, pszArgs);
- if (iHdaStreamdex != -1)
- hdaDbgPrintBDLE(pThis, pHlp, iHdaStreamdex);
+ int iHdaStrmIndex = hdaLookUpStreamIndex(pThis, pszArgs);
+ if (iHdaStrmIndex != -1)
+ hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex);
else
- for(iHdaStreamdex = 0; iHdaStreamdex < HDA_MAX_STREAMS; ++iHdaStreamdex)
- hdaDbgPrintBDLE(pThis, pHlp, iHdaStreamdex);
+ for(iHdaStrmIndex = 0; iHdaStrmIndex < 7; ++iHdaStrmIndex)
+ hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex);
}
/**
* @callback_method_impl{FNDBGFHANDLERDEV}
*/
-static DECLCALLBACK(void) hdaDbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
@@ -5431,7 +4221,7 @@ static DECLCALLBACK(void) hdaDbgInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP
/**
* @callback_method_impl{FNDBGFHANDLERDEV}
*/
-static DECLCALLBACK(void) hdaDbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
@@ -5444,7 +4234,7 @@ static DECLCALLBACK(void) hdaDbgInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFO
/**
* @callback_method_impl{FNDBGFHANDLERDEV}
*/
-static DECLCALLBACK(void) hdaDbgInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
+static DECLCALLBACK(void) hdaInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
@@ -5485,62 +4275,45 @@ static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns)
{
PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- LogFlowFuncEnter();
-
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- /*
- * Stop the timer, if any.
- */
- hdaTimerMaybeStop(pThis);
-# endif
-
- /* See 6.2.1. */
- HDA_REG(pThis, GCAP) = HDA_MAKE_GCAP(HDA_MAX_SDO /* Ouput streams */,
- HDA_MAX_SDI /* Input streams */,
- 0 /* Bidirectional output streams */,
- 0 /* Serial data out signals */,
- 1 /* 64-bit */);
+ HDA_REG(pThis, GCAP) = HDA_MAKE_GCAP(4,4,0,0,1); /* see 6.2.1 */
HDA_REG(pThis, VMIN) = 0x00; /* see 6.2.2 */
HDA_REG(pThis, VMAJ) = 0x01; /* see 6.2.3 */
- /* Announce the full 60 words output payload. */
HDA_REG(pThis, OUTPAY) = 0x003C; /* see 6.2.4 */
- /* Announce the full 29 words input payload. */
HDA_REG(pThis, INPAY) = 0x001D; /* see 6.2.5 */
HDA_REG(pThis, CORBSIZE) = 0x42; /* see 6.2.1 */
HDA_REG(pThis, RIRBSIZE) = 0x42; /* see 6.2.1 */
HDA_REG(pThis, CORBRP) = 0x0;
HDA_REG(pThis, RIRBWP) = 0x0;
+ LogFunc(("Resetting ...\n"));
+
+# ifndef VBOX_WITH_AUDIO_CALLBACKS
/*
- * Stop any audio currently playing and/or recording.
+ * Stop the timer, if any.
*/
- AudioMixerSinkCtl(pThis->SinkFront.pMixSink, AUDMIXSINKCMD_DISABLE);
-# ifdef VBOX_WITH_HDA_MIC_IN
- AudioMixerSinkCtl(pThis->SinkMicIn.pMixSink, AUDMIXSINKCMD_DISABLE);
-# endif
- AudioMixerSinkCtl(pThis->SinkLineIn.pMixSink, AUDMIXSINKCMD_DISABLE);
-# ifdef VBOX_WITH_HDA_51_SURROUND
- AudioMixerSinkCtl(pThis->SinkCenterLFE.pMixSink, AUDMIXSINKCMD_DISABLE);
- AudioMixerSinkCtl(pThis->SinkRear.pMixSink, AUDMIXSINKCMD_DISABLE);
+ int rc2;
+ if (pThis->pTimer)
+ {
+ rc2 = TMTimerStop(pThis->pTimer);
+ AssertRC(rc2);
+ }
# endif
/*
- * Set some sensible defaults for which HDA sinks
- * are connected to which stream number.
- *
- * We use SD0 for input and SD4 for output by default.
- * These stream numbers can be changed by the guest dynamically lateron.
+ * Stop any audio currently playing and/or recording.
*/
-#ifdef VBOX_WITH_HDA_MIC_IN
- hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_MIC_IN , 1 /* SD0 */, 0 /* Channel */);
-#endif
- hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_LINE_IN , 1 /* SD0 */, 0 /* Channel */);
-
- hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_FRONT , 5 /* SD4 */, 0 /* Channel */);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, 5 /* SD4 */, 0 /* Channel */);
- hdaMixerSetStream(pThis, PDMAUDIOMIXERCTL_REAR , 5 /* SD4 */, 0 /* Channel */);
-#endif
+ PHDADRIVER pDrv;
+ RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
+ {
+ pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, false /* Disable */);
+# ifdef VBOX_WITH_HDA_MIC_IN
+ /* Ignore rc. */
+ pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, false /* Disable */);
+# endif
+ /* Ditto. */
+ pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, false /* Disable */);
+ /* Ditto. */
+ }
pThis->cbCorbBuf = 256 * sizeof(uint32_t); /** @todo Use a define here. */
@@ -5557,24 +4330,42 @@ static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns)
pThis->u64BaseTS = PDMDevHlpTMTimeVirtGetNano(pDevIns);
- for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
+ for (uint8_t u8Strm = 0; u8Strm < 8; u8Strm++) /** @todo Use a define here. */
{
- /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
- HDA_STREAM_REG(pThis, CTL, i) &= ~HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN);
- hdaStreamReset(pThis, &pThis->aStreams[i]);
- }
+ PHDASTREAM pStrmSt = NULL;
+ if (u8Strm == 0) /** @todo Implement dynamic stream IDs. */
+ pStrmSt = &pThis->StrmStLineIn;
+# ifdef VBOX_WITH_HDA_MIC_IN
+ else if (u8Strm == 2) /** @todo Implement dynamic stream IDs. */
+ pStrmSt = &pThis->StrmStMicIn;
+# endif
+ else if (u8Strm == 4) /** @todo Implement dynamic stream IDs. */
+ pStrmSt = &pThis->StrmStOut;
+
+ if (pStrmSt)
+ {
+ /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
+ HDA_STREAM_REG(pThis, CTL, u8Strm) &= ~HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN);
- /* Clear stream tags <-> objects mapping table. */
- RT_ZERO(pThis->aTags);
+ hdaStreamReset(pThis, pStrmSt, u8Strm);
+ }
+ }
/* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
HDA_REG(pThis, STATESTS) = 0x1;
# ifndef VBOX_WITH_AUDIO_CALLBACKS
- hdaTimerMaybeStart(pThis);
+ /*
+ * Start timer again, if any.
+ */
+ if (pThis->pTimer)
+ {
+ LogFunc(("Restarting timer\n"));
+ rc2 = TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
+ AssertRC(rc2);
+ }
# endif
- LogFlowFuncLeave();
LogRel(("HDA: Reset\n"));
}
@@ -5583,6 +4374,7 @@ static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns)
*/
static DECLCALLBACK(int) hdaDestruct(PPDMDEVINS pDevIns)
{
+ PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
PHDADRIVER pDrv;
@@ -5594,9 +4386,16 @@ static DECLCALLBACK(int) hdaDestruct(PPDMDEVINS pDevIns)
RTMemFree(pDrv);
}
+ if (pThis->pMixer)
+ {
+ AudioMixerDestroy(pThis->pMixer);
+ pThis->pMixer = NULL;
+ }
+
if (pThis->pCodec)
{
- hdaCodecDestruct(pThis->pCodec);
+ int rc = hdaCodecDestruct(pThis->pCodec);
+ AssertRC(rc);
RTMemFree(pThis->pCodec);
pThis->pCodec = NULL;
@@ -5608,8 +4407,9 @@ static DECLCALLBACK(int) hdaDestruct(PPDMDEVINS pDevIns)
RTMemFree(pThis->pu64RirbBuf);
pThis->pu64RirbBuf = NULL;
- for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
- hdaStreamDestroy(&pThis->aStreams[i]);
+ hdaStreamDestroy(&pThis->StrmStLineIn);
+ hdaStreamDestroy(&pThis->StrmStMicIn);
+ hdaStreamDestroy(&pThis->StrmStOut);
return VINF_SUCCESS;
}
@@ -5664,7 +4464,7 @@ static int hdaAttachInternal(PPDMDEVINS pDevIns, PHDADRIVER pDrv, unsigned uLUN,
* host backend. This might change in the future.
*/
if (pDrv->uLUN == 0)
- pDrv->Flags |= PDMAUDIODRVFLAGS_PRIMARY;
+ pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
LogFunc(("LUN#%u: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
@@ -5716,36 +4516,10 @@ static DECLCALLBACK(void) hdaDetach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t
}
/**
- * Powers off the device.
- *
- * @param pDevIns Device instance to power off.
- */
-static DECLCALLBACK(void) hdaPowerOff(PPDMDEVINS pDevIns)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- LogRel2(("HDA: Powering off ...\n"));
-
- /* Ditto goes for the codec, which in turn uses the mixer. */
- hdaCodecPowerOff(pThis->pCodec);
-
- /**
- * Note: Destroy the mixer while powering off and *not* in hdaDestruct,
- * giving the mixer the chance to release any references held to
- * PDM audio streams it maintains.
- */
- if (pThis->pMixer)
- {
- AudioMixerDestroy(pThis->pMixer);
- pThis->pMixer = NULL;
- }
-}
-
-/**
- * Re-attaches a new driver to the device's driver chain.
+ * Re-attach.
*
* @returns VBox status code.
- * @param pThis Device instance to re-attach driver to.
+ * @param pThis Device instance.
* @param pDrv Driver instance used for attaching to.
* If NULL is specified, a new driver will be created and appended
* to the driver list.
@@ -5982,35 +4756,29 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
rc = AudioMixerCreate("HDA Mixer", 0 /* uFlags */, &pThis->pMixer);
if (RT_SUCCESS(rc))
{
- /*
- * Add mixer output sinks.
- */
-#ifdef VBOX_WITH_HDA_51_SURROUND
- rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Front",
- AUDMIXSINKDIR_OUTPUT, &pThis->SinkFront.pMixSink);
+ /* Set a default audio format for our mixer. */
+ PDMAUDIOSTREAMCFG streamCfg;
+ streamCfg.uHz = 44100;
+ streamCfg.cChannels = 2;
+ streamCfg.enmFormat = AUD_FMT_S16;
+ streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+ rc = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
AssertRC(rc);
- rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Center / Subwoofer",
- AUDMIXSINKDIR_OUTPUT, &pThis->SinkCenterLFE.pMixSink);
- AssertRC(rc);
- rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] Rear",
- AUDMIXSINKDIR_OUTPUT, &pThis->SinkRear.pMixSink);
- AssertRC(rc);
-#else
- rc = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output",
- AUDMIXSINKDIR_OUTPUT, &pThis->SinkFront.pMixSink);
+
+ /* Add all required audio sinks. */
+ rc = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
+ AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
AssertRC(rc);
-#endif
- /*
- * Add mixer input sinks.
- */
- rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In",
- AUDMIXSINKDIR_INPUT, &pThis->SinkLineIn.pMixSink);
+
+ rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Line In",
+ AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
AssertRC(rc);
-#ifdef VBOX_WITH_HDA_MIC_IN
- rc = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In",
- AUDMIXSINKDIR_INPUT, &pThis->SinkMicIn.pMixSink);
+
+ rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Microphone In",
+ AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
AssertRC(rc);
-#endif
+
/* There is no master volume control. Set the master to max. */
PDMAUDIOVOLUME vol = { false, 255, 255 };
rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
@@ -6025,12 +4793,13 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
if (!pThis->pCodec)
return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("Out of memory allocating HDA codec state"));
- /* Set codec callbacks. */
- pThis->pCodec->pfnMixerAddStream = hdaMixerAddStream;
- pThis->pCodec->pfnMixerRemoveStream = hdaMixerRemoveStream;
- pThis->pCodec->pfnMixerSetStream = hdaMixerSetStream;
- pThis->pCodec->pfnMixerSetVolume = hdaMixerSetVolume;
- pThis->pCodec->pfnReset = hdaCodecReset;
+ /* Audio driver callbacks for multiplexing. */
+ pThis->pCodec->pfnCloseIn = hdaCloseIn;
+ pThis->pCodec->pfnCloseOut = hdaCloseOut;
+ pThis->pCodec->pfnOpenIn = hdaOpenIn;
+ pThis->pCodec->pfnOpenOut = hdaOpenOut;
+ pThis->pCodec->pfnReset = hdaCodecReset;
+ pThis->pCodec->pfnSetVolume = hdaSetVolume;
pThis->pCodec->pHDAState = pThis; /* Assign HDA controller state to codec. */
@@ -6049,18 +4818,15 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
if (RT_SUCCESS(rc))
{
- /*
- * Create all hardware streams.
- */
- for (uint8_t i = 0; i < HDA_MAX_STREAMS; i++)
- {
- rc = hdaStreamCreate(&pThis->aStreams[i], i /* uSD */);
- AssertRC(rc);
- }
+ rc = hdaStreamCreate(&pThis->StrmStLineIn);
+ AssertRC(rc);
+#ifdef VBOX_WITH_HDA_MIC_IN
+ rc = hdaStreamCreate(&pThis->StrmStMicIn);
+ AssertRC(rc);
+#endif
+ rc = hdaStreamCreate(&pThis->StrmStOut);
+ AssertRC(rc);
- /*
- * Initialize the driver chain.
- */
PHDADRIVER pDrv;
RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
{
@@ -6068,20 +4834,17 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
* Only primary drivers are critical for the VM to run. Everything else
* might not worth showing an own error message box in the GUI.
*/
- if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
+ if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
continue;
PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
AssertPtr(pCon);
- bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
+ bool fValidLineIn = pCon->pfnIsValidIn(pCon, pDrv->LineIn.pStrmIn);
#ifdef VBOX_WITH_HDA_MIC_IN
- bool fValidMicIn = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
-#endif
- bool fValidOut = AudioMixerStreamIsValid(pDrv->Front.pMixStrm);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- /** @todo Anything to do here? */
+ bool fValidMicIn = pCon->pfnIsValidIn (pCon, pDrv->MicIn.pStrmIn);
#endif
+ bool fValidOut = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
if ( !fValidLineIn
#ifdef VBOX_WITH_HDA_MIC_IN
@@ -6103,20 +4866,20 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
bool fWarn = false;
PDMAUDIOBACKENDCFG backendCfg;
- int rc2 = pCon->pfnGetConfig(pCon, &backendCfg);
+ int rc2 = pCon->pfnGetConfiguration(pCon, &backendCfg);
if (RT_SUCCESS(rc2))
{
- if (backendCfg.cSources)
+ if (backendCfg.cMaxHstStrmsIn)
{
#ifdef VBOX_WITH_HDA_MIC_IN
/* If the audio backend supports two or more input streams at once,
* warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
- if (backendCfg.cMaxStreamsIn >= 2)
+ if (backendCfg.cMaxHstStrmsIn >= 2)
fWarn = !fValidLineIn || !fValidMicIn;
/* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
* *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
* One of the two simply is not in use then. */
- else if (backendCfg.cMaxStreamsIn == 1)
+ else if (backendCfg.cMaxHstStrmsIn == 1)
fWarn = !fValidLineIn && !fValidMicIn;
/* Don't warn if our backend is not able of supporting any input streams at all. */
#else
@@ -6126,16 +4889,14 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
}
if ( !fWarn
- && backendCfg.cSinks)
+ && backendCfg.cMaxHstStrmsOut)
{
fWarn = !fValidOut;
}
}
else
- {
- LogRel(("HDA: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
- fWarn = true;
- }
+ AssertReleaseMsgFailed(("Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n",
+ pDrv->uLUN, rc2));
if (fWarn)
{
@@ -6186,12 +4947,11 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
/*
* Debug and string formatter types.
*/
- PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA info. (hda [register case-insensitive])", hdaDbgInfo);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdabdle", "HDA stream BDLE info. (hdabdle [stream number])", hdaDbgInfoBDLE);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdastrm", "HDA stream info. (hdastrm [stream number])", hdaDbgInfoStream);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaDbgInfoCodecNodes);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaDbgInfoCodecSelector);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer", "HDA mixer state.", hdaDbgInfoMixer);
+ PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA info. (hda [register case-insensitive])", hdaInfo);
+ PDMDevHlpDBGFInfoRegister(pDevIns, "hdastrm", "HDA stream info. (hdastrm [stream number])", hdaInfoStream);
+ PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaInfoCodecNodes);
+ PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaInfoCodecSelector);
+ PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer", "HDA mixer state.", hdaInfoMixer);
rc = RTStrFormatTypeRegister("bdle", hdaDbgFmtBDLE, NULL);
AssertRC(rc);
@@ -6257,7 +5017,7 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
{
/* Start the emulation timer. */
rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, hdaTimer, pThis,
- TMTIMER_FLAGS_NO_CRIT_SECT, "DevHDA", &pThis->pTimer);
+ TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchHda", &pThis->pTimer);
AssertRCReturn(rc, rc);
if (RT_SUCCESS(rc))
@@ -6266,7 +5026,8 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
pThis->uTimerTS = TMTimerGet(pThis->pTimer);
LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
- hdaTimerMaybeStart(pThis);
+ /* Fire off timer. */
+ TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
}
}
# else
@@ -6277,7 +5038,7 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
{
/* Only register primary driver.
* The device emulation does the output multiplexing then. */
- if (pDrv->Flags != PDMAUDIODRVFLAGS_PRIMARY)
+ if (pDrv->Flags != PDMAUDIODRVFLAG_PRIMARY)
continue;
PDMAUDIOCALLBACK AudioCallbacks[2];
@@ -6322,7 +5083,7 @@ static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNO
/**
* The device registration structure.
*/
-const PDMDEVREG g_DeviceHDA =
+const PDMDEVREG g_DeviceICH6_HDA =
{
/* u32Version */
PDM_DEVREG_VERSION,
@@ -6367,7 +5128,7 @@ const PDMDEVREG g_DeviceHDA =
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
- hdaPowerOff,
+ NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
diff --git a/src/VBox/Devices/Audio/DevHDACommon.h b/src/VBox/Devices/Audio/DevHDACommon.h
deleted file mode 100644
index 7b2dca8..0000000
--- a/src/VBox/Devices/Audio/DevHDACommon.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* $Id: DevHDACommon.h $ */
-/** @file
- * DevIchHdaCommon.h - Shared defines / functions between controller and codec.
- */
-
-/*
- * Copyright (C) 2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef DEV_HDA_COMMON_H
-#define DEV_HDA_COMMON_H
-
-#define HDA_SDFMT_NON_PCM_SHIFT 15
-#define HDA_SDFMT_NON_PCM_MASK 0x1
-#define HDA_SDFMT_BASE_RATE_SHIFT 14
-#define HDA_SDFMT_BASE_RATE_MASK 0x1
-#define HDA_SDFMT_MULT_SHIFT 11
-#define HDA_SDFMT_MULT_MASK 0x7
-#define HDA_SDFMT_DIV_SHIFT 8
-#define HDA_SDFMT_DIV_MASK 0x7
-#define HDA_SDFMT_BITS_SHIFT 4
-#define HDA_SDFMT_BITS_MASK 0x7
-#define HDA_SDFMT_CHANNELS_MASK 0xF
-
-#define HDA_SDFMT_TYPE RT_BIT(15)
-#define HDA_SDFMT_TYPE_PCM (0)
-#define HDA_SDFMT_TYPE_NON_PCM (1)
-
-#define HDA_SDFMT_BASE RT_BIT(14)
-#define HDA_SDFMT_BASE_48KHZ (0)
-#define HDA_SDFMT_BASE_44KHZ (1)
-
-#define HDA_SDFMT_MULT_1X (0)
-#define HDA_SDFMT_MULT_2X (1)
-#define HDA_SDFMT_MULT_3X (2)
-#define HDA_SDFMT_MULT_4X (3)
-
-#define HDA_SDFMT_DIV_1X (0)
-#define HDA_SDFMT_DIV_2X (1)
-#define HDA_SDFMT_DIV_3X (2)
-#define HDA_SDFMT_DIV_4X (3)
-#define HDA_SDFMT_DIV_5X (4)
-#define HDA_SDFMT_DIV_6X (5)
-#define HDA_SDFMT_DIV_7X (6)
-#define HDA_SDFMT_DIV_8X (7)
-
-#define HDA_SDFMT_8_BIT (0)
-#define HDA_SDFMT_16_BIT (1)
-#define HDA_SDFMT_20_BIT (2)
-#define HDA_SDFMT_24_BIT (3)
-#define HDA_SDFMT_32_BIT (4)
-
-#define HDA_SDFMT_CHAN_MONO (0)
-#define HDA_SDFMT_CHAN_STEREO (1)
-
-/* Emits a SDnFMT register format. */
-/* Also being used in the codec's converter format. */
-#define HDA_SDFMT_MAKE(_afNonPCM, _aBaseRate, _aMult, _aDiv, _aBits, _aChan) \
- ( (((_afNonPCM) & HDA_SDFMT_NON_PCM_MASK) << HDA_SDFMT_NON_PCM_SHIFT) \
- | (((_aBaseRate) & HDA_SDFMT_BASE_RATE_MASK) << HDA_SDFMT_BASE_RATE_SHIFT) \
- | (((_aMult) & HDA_SDFMT_MULT_MASK) << HDA_SDFMT_MULT_SHIFT) \
- | (((_aDiv) & HDA_SDFMT_DIV_MASK) << HDA_SDFMT_DIV_SHIFT) \
- | (((_aBits) & HDA_SDFMT_BITS_MASK) << HDA_SDFMT_BITS_SHIFT) \
- | ( (_aChan) & HDA_SDFMT_CHANNELS_MASK))
-
-#endif /* DEV_HDA_COMMON_H */
-
diff --git a/src/VBox/Devices/Audio/DevIchAc97.cpp b/src/VBox/Devices/Audio/DevIchAc97.cpp
index ed8de3d..61f231e 100644
--- a/src/VBox/Devices/Audio/DevIchAc97.cpp
+++ b/src/VBox/Devices/Audio/DevIchAc97.cpp
@@ -26,9 +26,6 @@
#include <iprt/assert.h>
#ifdef IN_RING3
-# ifdef DEBUG
-# include <iprt/file.h>
-# endif
# include <iprt/mem.h>
# include <iprt/string.h>
# include <iprt/uuid.h>
@@ -45,114 +42,97 @@
* Defined Constants And Macros *
*********************************************************************************************************************************/
-#if 0
-/*
- * AC97_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
- * to a file on the host. Be sure to adjust AC97_DEBUG_DUMP_PCM_DATA_PATH
- * to your needs before using this!
- */
-# define AC97_DEBUG_DUMP_PCM_DATA
-# ifdef RT_OS_WINDOWS
-# define AC97_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
-# else
-# define AC97_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
+#ifdef DEBUG
+//#define DEBUG_LUN
+# ifdef DEBUG_LUN
+# define DEBUG_LUN_NUM 1
# endif
-#endif
+#endif /* DEBUG */
-/** Current saved state version. */
-#define AC97_SSM_VERSION 1
-
-/** Timer frequency (in Hz) */
-#define AC97_TIMER_HZ 200
-
-#define AC97_SR_FIFOE RT_BIT(4) /* rwc, FIFO error. */
-#define AC97_SR_BCIS RT_BIT(3) /* rwc, Buffer completion interrupt status. */
-#define AC97_SR_LVBCI RT_BIT(2) /* rwc, Last valid buffer completion interrupt. */
-#define AC97_SR_CELV RT_BIT(1) /* ro, Current equals last valid. */
-#define AC97_SR_DCH RT_BIT(0) /* ro, Controller halted. */
-#define AC97_SR_VALID_MASK (RT_BIT(5) - 1)
-#define AC97_SR_WCLEAR_MASK (AC97_SR_FIFOE | AC97_SR_BCIS | AC97_SR_LVBCI)
-#define AC97_SR_RO_MASK (AC97_SR_DCH | AC97_SR_CELV)
-#define AC97_SR_INT_MASK (AC97_SR_FIFOE | AC97_SR_BCIS | AC97_SR_LVBCI)
-
-#define AC97_CR_IOCE RT_BIT(4) /* rw, Interrupt On Completion Enable. */
-#define AC97_CR_FEIE RT_BIT(3) /* rw FIFO Error Interrupt Enable. */
-#define AC97_CR_LVBIE RT_BIT(2) /* rw Last Valid Buffer Interrupt Enable. */
-#define AC97_CR_RR RT_BIT(1) /* rw Reset Registers. */
-#define AC97_CR_RPBM RT_BIT(0) /* rw Run/Pause Bus Master. */
-#define AC97_CR_VALID_MASK (RT_BIT(5) - 1)
-#define AC97_CR_DONT_CLEAR_MASK (AC97_CR_IOCE | AC97_CR_FEIE | AC97_CR_LVBIE)
-
-#define AC97_GC_WR 4 /* rw Warm reset. */
-#define AC97_GC_CR 2 /* rw Cold reset. */
-#define AC97_GC_VALID_MASK (RT_BIT(6) - 1)
-
-#define AC97_GS_MD3 RT_BIT(17) /* rw */
-#define AC97_GS_AD3 RT_BIT(16) /* rw */
-#define AC97_GS_RCS RT_BIT(15) /* rwc */
-#define AC97_GS_B3S12 RT_BIT(14) /* ro */
-#define AC97_GS_B2S12 RT_BIT(13) /* ro */
-#define AC97_GS_B1S12 RT_BIT(12) /* ro */
-#define AC97_GS_S1R1 RT_BIT(11) /* rwc */
-#define AC97_GS_S0R1 RT_BIT(10) /* rwc */
-#define AC97_GS_S1CR RT_BIT(9) /* ro */
-#define AC97_GS_S0CR RT_BIT(8) /* ro */
-#define AC97_GS_MINT RT_BIT(7) /* ro */
-#define AC97_GS_POINT RT_BIT(6) /* ro */
-#define AC97_GS_PIINT RT_BIT(5) /* ro */
-#define AC97_GS_RSRVD (RT_BIT(4)|RT_BIT(3))
-#define AC97_GS_MOINT RT_BIT(2) /* ro */
-#define AC97_GS_MIINT RT_BIT(1) /* ro */
-#define AC97_GS_GSCI RT_BIT(0) /* rwc */
-#define AC97_GS_RO_MASK (AC97_GS_B3S12 | \
- AC97_GS_B2S12 | \
- AC97_GS_B1S12 | \
- AC97_GS_S1CR | \
- AC97_GS_S0CR | \
- AC97_GS_MINT | \
- AC97_GS_POINT | \
- AC97_GS_PIINT | \
- AC97_GS_RSRVD | \
- AC97_GS_MOINT | \
- AC97_GS_MIINT)
-#define AC97_GS_VALID_MASK (RT_BIT(18) - 1)
-#define AC97_GS_WCLEAR_MASK (AC97_GS_RCS|AC97_GS_S1R1|AC97_GS_S0R1|AC97_GS_GSCI)
-
-/** @name Buffer Descriptor (BD).
- * @{ */
-#define AC97_BD_IOC RT_BIT(31) /**< Interrupt on Completion. */
-#define AC97_BD_BUP RT_BIT(30) /**< Buffer Underrun Policy. */
+#define AC97_SSM_VERSION 1
-#define AC97_BD_MAX_LEN_MASK 0xFFFE
-/** @} */
+#ifdef VBOX
+# define SOFT_VOLUME /** @todo Get rid of this crap. */
+#else
+# define SOFT_VOLUME
+#endif
-/** @name Extended Audio Status and Control Register (EACS).
+#define SR_FIFOE RT_BIT(4) /* rwc, FIFO error. */
+#define SR_BCIS RT_BIT(3) /* rwc, Buffer completion interrupt status. */
+#define SR_LVBCI RT_BIT(2) /* rwc, Last valid buffer completion interrupt. */
+#define SR_CELV RT_BIT(1) /* ro, Current equals last valid. */
+#define SR_DCH RT_BIT(0) /* ro, Controller halted. */
+#define SR_VALID_MASK (RT_BIT(5) - 1)
+#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+#define SR_RO_MASK (SR_DCH | SR_CELV)
+#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
+
+#define CR_IOCE RT_BIT(4) /* rw, Interrupt On Completion Enable. */
+#define CR_FEIE RT_BIT(3) /* rw FIFO Error Interrupt Enable. */
+#define CR_LVBIE RT_BIT(2) /* rw */
+#define CR_RR RT_BIT(1) /* rw */
+#define CR_RPBM RT_BIT(0) /* rw */
+#define CR_VALID_MASK (RT_BIT(5) - 1)
+#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
+
+#define GC_WR 4 /* rw */
+#define GC_CR 2 /* rw */
+#define GC_VALID_MASK (RT_BIT(6) - 1)
+
+#define GS_MD3 RT_BIT(17) /* rw */
+#define GS_AD3 RT_BIT(16) /* rw */
+#define GS_RCS RT_BIT(15) /* rwc */
+#define GS_B3S12 RT_BIT(14) /* ro */
+#define GS_B2S12 RT_BIT(13) /* ro */
+#define GS_B1S12 RT_BIT(12) /* ro */
+#define GS_S1R1 RT_BIT(11) /* rwc */
+#define GS_S0R1 RT_BIT(10) /* rwc */
+#define GS_S1CR RT_BIT(9) /* ro */
+#define GS_S0CR RT_BIT(8) /* ro */
+#define GS_MINT RT_BIT(7) /* ro */
+#define GS_POINT RT_BIT(6) /* ro */
+#define GS_PIINT RT_BIT(5) /* ro */
+#define GS_RSRVD (RT_BIT(4)|RT_BIT(3))
+#define GS_MOINT RT_BIT(2) /* ro */
+#define GS_MIINT RT_BIT(1) /* ro */
+#define GS_GSCI RT_BIT(0) /* rwc */
+#define GS_RO_MASK (GS_B3S12 | \
+ GS_B2S12 | \
+ GS_B1S12 | \
+ GS_S1CR | \
+ GS_S0CR | \
+ GS_MINT | \
+ GS_POINT | \
+ GS_PIINT | \
+ GS_RSRVD | \
+ GS_MOINT | \
+ GS_MIINT)
+#define GS_VALID_MASK (RT_BIT(18) - 1)
+#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
+
+/** @name Buffer Descriptor
* @{ */
-#define AC97_EACS_VRA 1 /**< Variable Rate Audio (4.2.1.1). */
-#define AC97_EACS_VRM 8 /**< Variable Rate Mic Audio (4.2.1.1). */
+#define BD_IOC RT_BIT(31) /**< Interrupt on Completion */
+#define BD_BUP RT_BIT(30) /**< Buffer Underrun Policy */
/** @} */
-/** @name Baseline Audio Register Set (BARS).
- * @{ */
-#define AC97_BARS_VOL_MASK 0x1f /**< Volume mask for the Baseline Audio Register Set (5.7.2). */
-#define AC97_BARS_VOL_STEPS 31 /**< Volume steps for the Baseline Audio Register Set (5.7.2). */
-#define AC97_BARS_VOL_MUTE_SHIFT 15 /**< Mute bit shift for the Baseline Audio Register Set (5.7.2). */
-/** @} */
+#define EACS_VRA 1
+#define EACS_VRM 8
-/* AC'97 uses 1.5dB steps, we use 0.375dB steps: 1 AC'97 step equals 4 PDM steps. */
-#define AC97_DB_FACTOR 4
+#define VOL_MASK 0x1f
+#define MUTE_SHIFT 15
-#define AC97_REC_MASK 7
+#define REC_MASK 7
enum
{
- AC97_REC_MIC = 0,
- AC97_REC_CD,
- AC97_REC_VIDEO,
- AC97_REC_AUX,
- AC97_REC_LINE_IN,
- AC97_REC_STEREO_MIX,
- AC97_REC_MONO_MIX,
- AC97_REC_PHONE
+ REC_MIC = 0,
+ REC_CD,
+ REC_VIDEO,
+ REC_AUX,
+ REC_LINE_IN,
+ REC_STEREO_MIX,
+ REC_MONO_MIX,
+ REC_PHONE
};
enum
@@ -193,16 +173,15 @@ enum
};
/* Codec models. */
-typedef enum
-{
- AC97_CODEC_STAC9700 = 0, /* SigmaTel STAC9700 */
- AC97_CODEC_AD1980, /* Analog Devices AD1980 */
- AC97_CODEC_AD1981B /* Analog Devices AD1981B */
-} AC97CODEC;
+enum {
+ Codec_STAC9700 = 0, /* SigmaTel STAC9700 */
+ Codec_AD1980, /* Analog Devices AD1980 */
+ Codec_AD1981B /* Analog Devices AD1981B */
+};
/* Analog Devices miscellaneous regiter bits used in AD1980. */
-#define AC97_AD_MISC_LOSEL RT_BIT(5) /* Surround (rear) goes to line out outputs. */
-#define AC97_AD_MISC_HPSEL RT_BIT(10) /* PCM (front) goes to headphone outputs. */
+#define AD_MISC_LOSEL RT_BIT(5) /* Surround (rear) goes to line out outputs. */
+#define AD_MISC_HPSEL RT_BIT(10) /* PCM (front) goes to headphone outputs. */
#define ICHAC97STATE_2_DEVINS(a_pAC97) ((a_pAC97)->pDevInsR3)
@@ -213,44 +192,43 @@ enum
};
/** Emits registers for a specific (Native Audio Bus Master BAR) NABMBAR. */
-#define AC97_NABMBAR_REGS(prefix, off) \
- enum { \
- prefix ## _BDBAR = off, /* Buffer Descriptor Base Address */ \
- prefix ## _CIV = off + 4, /* Current Index Value */ \
- prefix ## _LVI = off + 5, /* Last Valid Index */ \
- prefix ## _SR = off + 6, /* Status Register */ \
- prefix ## _PICB = off + 8, /* Position in Current Buffer */ \
- prefix ## _PIV = off + 10, /* Prefetched Index Value */ \
- prefix ## _CR = off + 11 /* Control Register */ \
+#define AC97_NABMBAR_REGS(prefix, off) \
+ enum { \
+ prefix ## _BDBAR = off, \
+ prefix ## _CIV = off + 4, \
+ prefix ## _LVI = off + 5, \
+ prefix ## _SR = off + 6, \
+ prefix ## _PICB = off + 8, \
+ prefix ## _PIV = off + 10, \
+ prefix ## _CR = off + 11 \
}
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
typedef enum
{
- AC97SOUNDSOURCE_PI_INDEX = 0, /** PCM in */
- AC97SOUNDSOURCE_PO_INDEX, /** PCM out */
- AC97SOUNDSOURCE_MC_INDEX, /** Mic in */
- AC97SOUNDSOURCE_LAST_INDEX
+ PI_INDEX = 0, /** PCM in */
+ PO_INDEX, /** PCM out */
+ MC_INDEX, /** Mic in */
+ LAST_INDEX
} AC97SOUNDSOURCE;
-AC97_NABMBAR_REGS(PI, AC97SOUNDSOURCE_PI_INDEX * 16);
-AC97_NABMBAR_REGS(PO, AC97SOUNDSOURCE_PO_INDEX * 16);
-AC97_NABMBAR_REGS(MC, AC97SOUNDSOURCE_MC_INDEX * 16);
+AC97_NABMBAR_REGS(PI, PI_INDEX * 16);
+AC97_NABMBAR_REGS(PO, PO_INDEX * 16);
+AC97_NABMBAR_REGS(MC, MC_INDEX * 16);
#endif
enum
{
/** NABMBAR: Global Control Register. */
- AC97_GLOB_CNT = 0x2c,
+ GLOB_CNT = 0x2c,
/** NABMBAR Global Status. */
- AC97_GLOB_STA = 0x30,
+ GLOB_STA = 0x30,
/** Codec Access Semaphore Register. */
- AC97_CAS = 0x34
+ CAS = 0x34
};
#define AC97_PORT2IDX(a_idx) ( ((a_idx) >> 4) & 3 )
-
/*********************************************************************************************************************************
* Structures and Typedefs *
*********************************************************************************************************************************/
@@ -273,7 +251,7 @@ typedef struct AC97BMREGS
uint8_t civ; /** ro 0, Current index value. */
uint8_t lvi; /** rw 0, Last valid index. */
uint16_t sr; /** rw 1, Status register. */
- uint16_t picb; /** ro 0, Position in current buffer (in samples). */
+ uint16_t picb; /** ro 0, Position in current buffer. */
uint8_t piv; /** ro 0, Prefetched index value. */
uint8_t cr; /** rw 0, Control register. */
int bd_valid; /** Whether current BDLE is initialized or not. */
@@ -281,28 +259,23 @@ typedef struct AC97BMREGS
} AC97BMREGS, *PAC97BMREGS;
/**
- * Internal state of an AC'97 stream.
+ * Internal state of an AC97 stream.
*/
typedef struct AC97STREAMSTATE
{
- /** Temporary FIFO write buffer. */
- R3PTRTYPE(uint8_t *) au8FIFOW;
- /** Size of the temporary FIFO write buffer. */
- uint32_t cbFIFOW;
- /** Current write offset in FIFO write buffer. */
- uint32_t offFIFOW;
- uint8_t Padding;
+ /* Nothing yet. */
} AC97STREAMSTATE, *PAC97STREAMSTATE;
/**
- * Structure for keeping an AC'97 stream state.
+ * Structure for keeping an AC97 stream state.
+ *
+ * Contains only register values which do *not* change until a
+ * stream reset occurs.
*/
typedef struct AC97STREAM
{
/** Stream number (SDn). */
uint8_t u8Strm;
- /** Criticial section for this stream. */
- RTCRITSECT CritSect;
/** Bus master registers of this stream. */
AC97BMREGS Regs;
/** Internal state of this stream. */
@@ -311,14 +284,18 @@ typedef struct AC97STREAM
typedef struct AC97INPUTSTREAM
{
- /** Mixer handle for input stream. */
- R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
+ /** PCM line input stream. */
+ R3PTRTYPE(PPDMAUDIOGSTSTRMIN) pStrmIn;
+ /** Mixer handle for line input stream. */
+ R3PTRTYPE(PAUDMIXSTREAM) phStrmIn;
} AC97INPUTSTREAM, *PAC97INPUTSTREAM;
typedef struct AC97OUTPUTSTREAM
{
+ /** PCM output stream. */
+ R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
/** Mixer handle for output stream. */
- R3PTRTYPE(PAUDMIXSTREAM) pMixStrm;
+ R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
} AC97OUTPUTSTREAM, *PAC97OUTPUTSTREAM;
/**
@@ -357,33 +334,23 @@ typedef struct AC97STATE
PDMPCIDEV PciDev;
/** R3 Pointer to the device instance. */
PPDMDEVINSR3 pDevInsR3;
- /** Global Control (Bus Master Control Register). */
+ /** Global Control (Bus Master Control Register) */
uint32_t glob_cnt;
- /** Global Status (Bus Master Control Register). */
+ /** Global Status (Bus Master Control Register) */
uint32_t glob_sta;
- /** Codec Access Semaphore Register (Bus Master Control Register). */
+ /** Codec Access Semaphore Register (Bus Master Control Register) */
uint32_t cas;
uint32_t last_samp;
uint8_t mixer_data[256];
/** Stream state for line-in. */
- AC97STREAM StreamLineIn;
+ AC97STREAM StrmStLineIn;
/** Stream state for microphone-in. */
- AC97STREAM StreamMicIn;
+ AC97STREAM StrmStMicIn;
/** Stream state for output. */
- AC97STREAM StreamOut;
- /** Number of active (running) SDn streams. */
- uint8_t cStreamsActive;
+ AC97STREAM StrmStOut;
#ifndef VBOX_WITH_AUDIO_CALLBACKS
/** The timer for pumping data thru the attached LUN drivers. */
PTMTIMERR3 pTimer;
- /** Criticial section for timer. */
- RTCRITSECT csTimer;
-# if HC_ARCH_BITS == 32
- uint32_t Padding0;
-# endif
- /** Flag indicating whether the timer is active or not. */
- bool fTimerActive;
- uint8_t u8Padding1[7];
/** The timer interval for pumping data thru the LUN drivers in timer ticks. */
uint64_t cTimerTicks;
/** Timestamp of the last timer callback (ac97Timer).
@@ -391,17 +358,16 @@ typedef struct AC97STATE
uint64_t uTimerTS;
#endif
#ifdef VBOX_WITH_STATISTICS
- uint8_t Padding1;
STAMPROFILE StatTimer;
STAMCOUNTER StatBytesRead;
STAMCOUNTER StatBytesWritten;
#endif
/** List of associated LUN drivers (AC97DRIVER). */
RTLISTANCHOR lstDrv;
- /** The device's software mixer. */
+ /** The device' software mixer. */
R3PTRTYPE(PAUDIOMIXER) pMixer;
/** Audio sink for PCM output. */
- R3PTRTYPE(PAUDMIXSINK) pSinkOut;
+ R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
/** Audio sink for line input. */
R3PTRTYPE(PAUDMIXSINK) pSinkLineIn;
/** Audio sink for microphone input. */
@@ -412,33 +378,26 @@ typedef struct AC97STATE
PDMIBASE IBase;
/** Base port of the I/O space region. */
RTIOPORT IOPortBase[2];
+ /** Pointer to temporary scratch read/write buffer. */
+ R3PTRTYPE(uint8_t *) pvReadWriteBuf;
+ /** Size of the temporary scratch read/write buffer. */
+ uint32_t cbReadWriteBuf;
/** Codec model. */
uint32_t uCodecModel;
} AC97STATE, *PAC97STATE;
#ifdef VBOX_WITH_STATISTICS
-AssertCompileMemberAlignment(AC97STATE, StatTimer, 8);
-AssertCompileMemberAlignment(AC97STATE, StatBytesRead, 8);
-AssertCompileMemberAlignment(AC97STATE, StatBytesWritten, 8);
+AssertCompileMemberAlignment(AC97STATE, StatTimer, 8);
#endif
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource);
-static void ichac97DestroyOut(PAC97STATE pThis);
DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID);
-static int ichac97StreamInit(PAC97STREAM pStream, uint8_t u8Strm);
-static void ichac97StreamDestroy(PAC97STREAM pStream);
-static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream);
-static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream);
-static void ichac97StreamClose(PAC97STREAM pStream);
static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns);
#ifndef VBOX_WITH_AUDIO_CALLBACKS
-static void ichac97TimerMaybeStart(PAC97STATE pThis);
-static void ichac97TimerMaybeStop(PAC97STATE pThis);
static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
#endif
-static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed);
+static int ichac97TransferAudio(PAC97STATE pThis, AC97SOUNDSOURCE enmSrc, uint32_t cbElapsed);
static void ichac97WarmReset(PAC97STATE pThis)
{
@@ -450,27 +409,11 @@ static void ichac97ColdReset(PAC97STATE pThis)
NOREF(pThis);
}
-DECLINLINE(PAUDMIXSINK) ichac97IndexToSink(PAC97STATE pThis, uint8_t uIndex)
-{
- AssertPtrReturn(pThis, NULL);
-
- switch (uIndex)
- {
- case AC97SOUNDSOURCE_PI_INDEX: return pThis->pSinkLineIn; break;
- case AC97SOUNDSOURCE_PO_INDEX: return pThis->pSinkOut; break;
- case AC97SOUNDSOURCE_MC_INDEX: return pThis->pSinkMicIn; break;
- default: break;
- }
-
- AssertMsgFailed(("Wrong index %RU8\n", uIndex));
- return NULL;
-}
-
/** Fetches the buffer descriptor at _CIV. */
-static void ichac97StreamFetchBDLE(PAC97STATE pThis, PAC97STREAM pStream)
+static void ichac97StreamFetchBDLE(PAC97STATE pThis, PAC97STREAM pStrmSt)
{
PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
- PAC97BMREGS pRegs = &pStream->Regs;
+ PAC97BMREGS pRegs = &pStrmSt->Regs;
uint32_t u32[2];
@@ -482,319 +425,187 @@ static void ichac97StreamFetchBDLE(PAC97STATE pThis, PAC97STREAM pStream)
pRegs->bd.addr = RT_H2LE_U32(u32[0] & ~3);
pRegs->bd.ctl_len = RT_H2LE_U32(u32[1]);
#endif
- pRegs->picb = pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK;
+ pRegs->picb = pRegs->bd.ctl_len & 0xffff;
LogFlowFunc(("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len >> 16,
- pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK,
- (pRegs->bd.ctl_len & AC97_BD_MAX_LEN_MASK) << 1)); /** @todo r=andy Assumes 16bit samples. */
+ pRegs->bd.ctl_len & 0xffff, (pRegs->bd.ctl_len & 0xffff) << 1));
}
/**
* Update the BM status register
*/
-static void ichac97StreamUpdateSR(PAC97STATE pThis, PAC97STREAM pStream, uint32_t new_sr)
+static void ichac97StreamUpdateStatus(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t new_sr)
{
PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
- PAC97BMREGS pRegs = &pStream->Regs;
+ PAC97BMREGS pRegs = &pStrmSt->Regs;
- bool fSignal = false;
- int iIRQL = 0;
+ bool fSignal = false;
+ bool iIrqLevel = 0;
- uint32_t new_mask = new_sr & AC97_SR_INT_MASK;
- uint32_t old_mask = pRegs->sr & AC97_SR_INT_MASK;
+ uint32_t new_mask = new_sr & SR_INT_MASK;
+ uint32_t old_mask = pRegs->sr & SR_INT_MASK;
- static uint32_t const masks[] = { AC97_GS_PIINT, AC97_GS_POINT, AC97_GS_MINT };
+ static uint32_t const masks[] = { GS_PIINT, GS_POINT, GS_MINT };
if (new_mask ^ old_mask)
{
/** @todo Is IRQ deasserted when only one of status bits is cleared? */
if (!new_mask)
{
- fSignal = true;
- iIRQL = 0;
+ fSignal = true;
+ iIrqLevel = 0;
}
- else if ((new_mask & AC97_SR_LVBCI) && (pRegs->cr & AC97_CR_LVBIE))
+ else if ((new_mask & SR_LVBCI) && (pRegs->cr & CR_LVBIE))
{
- fSignal = true;
- iIRQL = 1;
+ fSignal = true;
+ iIrqLevel = 1;
}
- else if ((new_mask & AC97_SR_BCIS) && (pRegs->cr & AC97_CR_IOCE))
+ else if ((new_mask & SR_BCIS) && (pRegs->cr & CR_IOCE))
{
- fSignal = true;
- iIRQL = 1;
+ fSignal = true;
+ iIrqLevel = 1;
}
}
pRegs->sr = new_sr;
- LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, IRQL=%d\n",
- pRegs->sr & AC97_SR_BCIS, pRegs->sr & AC97_SR_LVBCI, pRegs->sr, fSignal, iIRQL));
+ LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, iIrqLevel=%d\n",
+ pRegs->sr & SR_BCIS, pRegs->sr & SR_LVBCI, pRegs->sr, fSignal, iIrqLevel));
if (fSignal)
{
- if (iIRQL)
- pThis->glob_sta |= masks[pStream->u8Strm];
+ if (iIrqLevel)
+ pThis->glob_sta |= masks[pStrmSt->u8Strm];
else
- pThis->glob_sta &= ~masks[pStream->u8Strm];
+ pThis->glob_sta &= ~masks[pStrmSt->u8Strm];
- LogFlowFunc(("Setting IRQ level=%d\n", iIRQL));
- PDMDevHlpPCISetIrq(pDevIns, 0, iIRQL);
+ LogFlowFunc(("set irq level=%d\n", !!iIrqLevel));
+ PDMDevHlpPCISetIrq(pDevIns, 0, !!iIrqLevel);
}
}
-/**
- * Returns whether an AC'97 stream is enabled or not.
- *
- * @returns IPRT status code.
- * @param pThis AC'97 device state.
- * @param pStream Stream to return status for.
- */
-static bool ichac97StreamIsEnabled(PAC97STATE pThis, PAC97STREAM pStream)
-{
- AssertPtrReturn(pThis, false);
- AssertPtrReturn(pStream, false);
-
- PAUDMIXSINK pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
- bool fIsEnabled = RT_BOOL(AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING);
-
- LogFunc(("[SD%RU8] fIsEnabled=%RTbool\n", pStream->u8Strm, fIsEnabled));
- return fIsEnabled;
-}
-
-static int ichac97StreamEnable(PAC97STATE pThis, PAC97STREAM pStream, bool fEnable)
+static int ichac97StreamSetActive(PAC97STATE pThis, PAC97STREAM pStrmSt, bool fActive)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PAUDMIXSINK pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
- AssertPtr(pSink);
-
- const bool fIsEnabled = AudioMixerSinkGetStatus(pSink) & AUDMIXSINK_STS_RUNNING;
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- LogFunc(("[SD%RU8] fEnable=%RTbool, fIsEnabled=%RTbool, DCH=%RTbool, cStreamsActive=%RU8\n",
- pStream->u8Strm, fEnable, fIsEnabled, RT_BOOL(pStream->Regs.sr & AC97_SR_DCH), pThis->cStreamsActive));
+ LogFlowFunc(("u8Strm=%RU8, fActive=%RTbool\n", pStrmSt->u8Strm, fActive));
int rc = VINF_SUCCESS;
- if (fEnable != fIsEnabled)
+ PAC97DRIVER pDrv;
+ switch (pStrmSt->u8Strm)
{
- rc = ichac97StreamReOpen(pThis, pStream);
- if (RT_SUCCESS(rc))
- rc = AudioMixerSinkCtl(ichac97IndexToSink(pThis, pStream->u8Strm),
- fEnable ? AUDMIXSINKCMD_ENABLE : AUDMIXSINKCMD_DISABLE);
- if (RT_SUCCESS(rc))
- {
- if (!fEnable)
+ case PI_INDEX:
+ RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
{
- if (pThis->cStreamsActive) /* Disable can be called mupltiple times. */
- pThis->cStreamsActive--;
+ int rc2 = pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+ pDrv->LineIn.pStrmIn, fActive);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ break;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- ichac97TimerMaybeStop(pThis);
-#endif
+ case PO_INDEX:
+ RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+ {
+ int rc2 = pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
+ pDrv->Out.pStrmOut, fActive);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
}
- else
+ break;
+
+ case MC_INDEX:
+ RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
{
- pThis->cStreamsActive++;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- ichac97TimerMaybeStart(pThis);
-#endif
+ int rc2 = pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
+ pDrv->MicIn.pStrmIn, fActive);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
}
- }
+ break;
+
+ default:
+ AssertMsgFailed(("Wrong index %RU32\n", pStrmSt->u8Strm));
+ rc = VERR_NOT_SUPPORTED;
+ break;
}
- LogFunc(("Returning %Rrc\n", rc));
return rc;
}
-static void ichac97StreamResetBMRegs(PAC97STATE pThis, PAC97STREAM pStream)
+static void ichac97StreamResetBMRegs(PAC97STATE pThis, PAC97STREAM pStrmSt)
{
AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStream);
+ AssertPtrReturnVoid(pStrmSt);
- LogFunc(("[SD%RU8]\n", pStream->u8Strm));
+ LogFlowFuncEnter();
- PAC97BMREGS pRegs = &pStream->Regs;
+ PAC97BMREGS pRegs = &pStrmSt->Regs;
pRegs->bdbar = 0;
pRegs->civ = 0;
pRegs->lvi = 0;
- ichac97StreamEnable(pThis, pStream, false /* fActive */);
-
- ichac97StreamUpdateSR(pThis, pStream, AC97_SR_DCH); /** @todo Do we need to do that? */
+ ichac97StreamUpdateStatus(pThis, pStrmSt, SR_DCH); /** @todo Do we need to do that? */
pRegs->picb = 0;
pRegs->piv = 0;
- pRegs->cr = pRegs->cr & AC97_CR_DONT_CLEAR_MASK;
+ pRegs->cr = pRegs->cr & CR_DONT_CLEAR_MASK;
pRegs->bd_valid = 0;
- RT_ZERO(pThis->silence);
-}
-
-static int ichac97StreamInit(PAC97STREAM pStream, uint8_t u8Strm)
-{
- AssertPtrReturn(pStream, VERR_INVALID_PARAMETER);
-
- LogFunc(("[SD%RU8] pStream=%p\n", u8Strm, pStream));
-
- int rc = VINF_SUCCESS;
+ int rc = ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
+ AssertRC(rc);
- pStream->u8Strm = u8Strm;
- pStream->State.cbFIFOW = _4K; /** @todo Make FIFOW size configurable. */
- pStream->State.offFIFOW = 0;
- pStream->State.au8FIFOW = (uint8_t *)RTMemAllocZ(pStream->State.cbFIFOW);
- if (pStream->State.au8FIFOW)
- {
- rc = RTCritSectInit(&pStream->CritSect);
- }
- else
- rc = VERR_NO_MEMORY;
-
- return rc;
-}
-
-static void ichac97StreamDestroy(PAC97STREAM pStream)
-{
- LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
-
- if (pStream->State.au8FIFOW)
- {
- Assert(pStream->State.cbFIFOW);
- RTMemFree(pStream->State.au8FIFOW);
- pStream->State.au8FIFOW = NULL;
- }
-
- pStream->State.cbFIFOW = 0;
- pStream->State.offFIFOW = 0;
-
- if (RTCritSectIsInitialized(&pStream->CritSect))
- RTCritSectDelete(&pStream->CritSect);
-}
-
-static int ichac97StreamsInit(PAC97STATE pThis)
-{
- LogFlowFuncEnter();
-
- int rc = ichac97StreamInit (&pThis->StreamLineIn, AC97SOUNDSOURCE_PI_INDEX);
- if (RT_SUCCESS(rc))
- rc = ichac97StreamInit (&pThis->StreamMicIn, AC97SOUNDSOURCE_MC_INDEX);
- if (RT_SUCCESS(rc))
- rc = ichac97StreamInit(&pThis->StreamOut, AC97SOUNDSOURCE_PO_INDEX);
-
- /* Open all streams with the current AC'97 mixer settings. */
- if (RT_SUCCESS(rc))
- {
- rc = ichac97StreamOpen (pThis, &pThis->StreamLineIn);
- if (RT_SUCCESS(rc))
- rc = ichac97StreamOpen (pThis, &pThis->StreamMicIn);
- if (RT_SUCCESS(rc))
- rc = ichac97StreamOpen(pThis, &pThis->StreamOut);
- }
-
- LogFlowFunc(("Returning %Rrc\n", rc));
- return rc;
-}
-
-static void ichac97StreamsDestroy(PAC97STATE pThis)
-{
- LogFlowFuncEnter();
-
- ichac97DestroyIn(pThis, PDMAUDIORECSOURCE_LINE);
- ichac97DestroyIn(pThis, PDMAUDIORECSOURCE_MIC);
- ichac97DestroyOut(pThis);
-
- ichac97StreamDestroy(&pThis->StreamLineIn);
- ichac97StreamDestroy(&pThis->StreamMicIn);
- ichac97StreamDestroy(&pThis->StreamOut);
+ RT_ZERO(pThis->silence);
}
-static void ichac97MixerSet(PAC97STATE pThis, uint8_t uMixerIdx, uint16_t uVal)
+static void ichac97MixerSet(PAC97STATE pThis, uint32_t u8Idx, uint16_t v)
{
- if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
+ if (u8Idx + 2 > sizeof(pThis->mixer_data))
{
- AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
+ AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
return;
}
- pThis->mixer_data[uMixerIdx + 0] = RT_LO_U8(uVal);
- pThis->mixer_data[uMixerIdx + 1] = RT_HI_U8(uVal);
+ pThis->mixer_data[u8Idx + 0] = RT_LO_U8(v);
+ pThis->mixer_data[u8Idx + 1] = RT_HI_U8(v);
}
-static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t uMixerIdx)
+static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t u8Idx)
{
uint16_t uVal;
- if (size_t(uMixerIdx + 2) > sizeof(pThis->mixer_data))
+ if (u8Idx + 2 > sizeof(pThis->mixer_data))
{
- AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", uMixerIdx, sizeof(pThis->mixer_data)));
+ AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
uVal = UINT16_MAX;
}
else
- uVal = RT_MAKE_U16(pThis->mixer_data[uMixerIdx + 0], pThis->mixer_data[uMixerIdx + 1]);
+ uVal = RT_MAKE_U16(pThis->mixer_data[u8Idx + 0], pThis->mixer_data[u8Idx + 1]);
return uVal;
}
-static void ichac97DestroyIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource)
+#if 0 // unused
+static DECLCALLBACK(void) ichac97CloseIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource)
{
- AssertPtrReturnVoid(pThis);
-
+ NOREF(pThis);
+ NOREF(enmRecSource);
LogFlowFuncEnter();
-
- PAUDMIXSINK pSink;
- switch (enmRecSource)
- {
- case PDMAUDIORECSOURCE_MIC:
- pSink = pThis->pSinkMicIn;
- break;
- case PDMAUDIORECSOURCE_LINE:
- pSink = pThis->pSinkLineIn;
- break;
- default:
- AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
- return;
- }
-
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- PAC97INPUTSTREAM pStream;
- if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */
- pStream = &pDrv->MicIn;
- else
- pStream = &pDrv->LineIn;
-
- if (pStream->pMixStrm)
- {
- AudioMixerSinkRemoveStream(pSink, pStream->pMixStrm);
- AudioMixerStreamDestroy(pStream->pMixStrm);
- }
- pStream->pMixStrm = NULL;
- }
}
-static void ichac97DestroyOut(PAC97STATE pThis)
+static DECLCALLBACK(void) ichac97CloseOut(PAC97STATE pThis)
{
- AssertPtrReturnVoid(pThis);
-
+ NOREF(pThis);
LogFlowFuncEnter();
-
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- if (pDrv->Out.pMixStrm)
- {
- AudioMixerSinkRemoveStream(pThis->pSinkOut, pDrv->Out.pMixStrm);
- AudioMixerStreamDestroy(pDrv->Out.pMixStrm);
-
- pDrv->Out.pMixStrm = NULL;
- }
- }
}
+#endif
-static int ichac97CreateIn(PAC97STATE pThis,
- const char *pszName, PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg)
+static int ichac97OpenIn(PAC97STATE pThis,
+ const char *pszName, PDMAUDIORECSOURCE enmRecSource,
+ PPDMAUDIOSTREAMCFG pCfg)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
AssertPtrReturn(pszName, VERR_INVALID_POINTER);
@@ -806,7 +617,7 @@ static int ichac97CreateIn(PAC97STATE pThis,
case PDMAUDIORECSOURCE_MIC:
pSink = pThis->pSinkMicIn;
break;
- case PDMAUDIORECSOURCE_LINE:
+ case PDMAUDIORECSOURCE_LINE_IN:
pSink = pThis->pSinkLineIn;
break;
default:
@@ -814,176 +625,133 @@ static int ichac97CreateIn(PAC97STATE pThis,
return VERR_NOT_SUPPORTED;
}
- /* Update the sink's format. */
- PDMAUDIOPCMPROPS PCMProps;
- int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
- if (RT_SUCCESS(rc))
- rc = AudioMixerSinkSetFormat(pSink, &PCMProps);
-
- if (RT_FAILURE(rc))
- return rc;
+ int rc = VINF_SUCCESS;
PAC97DRIVER pDrv;
RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
{
- if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s", pDrv->uLUN, pszName))
+ char *pszDesc;
+ if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pszName) <= 0)
{
- rc = VERR_BUFFER_OVERFLOW;
+ rc = VERR_NO_MEMORY;
break;
}
- PAC97INPUTSTREAM pStream;
+ PAC97INPUTSTREAM pStrmIn;
if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */
- pStream = &pDrv->MicIn;
+ pStrmIn = &pDrv->MicIn;
else
- pStream = &pDrv->LineIn;
+ pStrmIn = &pDrv->LineIn;
- AudioMixerSinkRemoveStream(pSink, pStream->pMixStrm);
+ rc = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, enmRecSource, pCfg, &pStrmIn->pStrmIn);
- AudioMixerStreamDestroy(pStream->pMixStrm);
- pStream->pMixStrm = NULL;
-
- int rc2 = AudioMixerSinkCreateStream(pSink, pDrv->pConnector, pCfg, 0 /* fFlags */ , &pStream->pMixStrm);
- if (RT_SUCCESS(rc2))
+ LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+ if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
{
- rc2 = AudioMixerSinkAddStream(pSink, pStream->pMixStrm);
- LogFlowFunc(("LUN#%RU8: Created input \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
+ AudioMixerRemoveStream(pSink, pStrmIn->phStrmIn);
+ rc = AudioMixerAddStreamIn(pSink,
+ pDrv->pConnector, pStrmIn->pStrmIn,
+ 0 /* uFlags */, &pStrmIn->phStrmIn);
}
- if (RT_SUCCESS(rc))
- rc = rc2;
+ RTStrFree(pszDesc);
}
LogFlowFuncLeaveRC(rc);
return rc;
}
-static int ichac97CreateOut(PAC97STATE pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
+static int ichac97OpenOut(PAC97STATE pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
AssertPtrReturn(pszName, VERR_INVALID_POINTER);
AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- LogFunc(("%s\n", pszName));
-
- /* Update the sink's format. */
- PDMAUDIOPCMPROPS PCMProps;
- int rc = DrvAudioHlpStreamCfgToProps(pCfg, &PCMProps);
- if (RT_SUCCESS(rc))
- rc = AudioMixerSinkSetFormat(pThis->pSinkOut, &PCMProps);
-
- if (RT_FAILURE(rc))
- return rc;
+ int rc = VINF_SUCCESS;
+ char *pszDesc;
PAC97DRIVER pDrv;
RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
{
- if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
- pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel"))
+ if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
+ pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel") <= 0)
{
- rc = VERR_BUFFER_OVERFLOW;
+ rc = VERR_NO_MEMORY;
break;
}
- AudioMixerSinkRemoveStream(pThis->pSinkOut, pDrv->Out.pMixStrm);
-
- AudioMixerStreamDestroy(pDrv->Out.pMixStrm);
- pDrv->Out.pMixStrm = NULL;
-
- int rc2 = AudioMixerSinkCreateStream(pThis->pSinkOut, pDrv->pConnector, pCfg, 0 /* fFlags */, &pDrv->Out.pMixStrm);
- if (RT_SUCCESS(rc2))
+ rc = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
+ LogFlowFunc(("LUN#%RU8: Created output \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
+ if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
{
- rc2 = AudioMixerSinkAddStream(pThis->pSinkOut, pDrv->Out.pMixStrm);
- LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
+ AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
+ rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
+ pDrv->pConnector, pDrv->Out.pStrmOut,
+ 0 /* uFlags */, &pDrv->Out.phStrmOut);
}
- if (RT_SUCCESS(rc))
- rc = rc2;
+ RTStrFree(pszDesc);
}
LogFlowFuncLeaveRC(rc);
return rc;
}
-/**
- * Opens an AC'97 stream, extended version.
- *
- * @returns IPRT status code.
- * @param pThis AC'97 device state.
- * @param pStream Stream to initialize.
- * @param pCfg Audio stream configuration to initialize the stream with.
- */
-static int ichac97StreamOpenEx(PAC97STATE pThis, PAC97STREAM pStream, PPDMAUDIOSTREAMCFG pCfg)
+static int ichac97StreamInitEx(PAC97STATE pThis, PAC97STREAM pStrmSt, uint8_t u8Strm, PPDMAUDIOSTREAMCFG pCfg)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+ AssertReturn(u8Strm <= LAST_INDEX, VERR_INVALID_PARAMETER);
AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- LogFunc(("[SD%RU8] pCfg=%p\n", pStream->u8Strm, pCfg));
+ pStrmSt->u8Strm = u8Strm;
+
+ LogFlowFunc(("u8Strm=%RU8, %RU32Hz, %RU8 %s\n",
+ pStrmSt->u8Strm, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel"));
int rc;
- switch (pStream->u8Strm)
+ switch (pStrmSt->u8Strm)
{
- case AC97SOUNDSOURCE_PI_INDEX:
- rc = ichac97CreateIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE, pCfg);
+ case PI_INDEX:
+ rc = ichac97OpenIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE_IN, pCfg);
break;
- case AC97SOUNDSOURCE_MC_INDEX:
- rc = ichac97CreateIn(pThis, "ac97.mc", PDMAUDIORECSOURCE_MIC, pCfg);
+ case MC_INDEX:
+ rc = ichac97OpenIn(pThis, "ac97.mc", PDMAUDIORECSOURCE_MIC, pCfg);
break;
- case AC97SOUNDSOURCE_PO_INDEX:
- rc = ichac97CreateOut(pThis, "ac97.po", pCfg);
+ case PO_INDEX:
+ rc = ichac97OpenOut(pThis, "ac97.po", pCfg);
break;
default:
- AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
+ rc = VERR_NOT_SUPPORTED;
break;
}
- if (RT_FAILURE(rc))
- LogRel2(("AC97: Error opening stream #%RU8, rc=%Rrc\n", pStream->u8Strm, rc));
-
LogFlowFuncLeaveRC(rc);
return rc;
}
-/**
- * Opens an AC'97 stream.
- * This will open an AC'97 stream with 2 (stereo) channels, 16-bit samples and
- * the last set sample rate in the AC'97 mixer for this stream.
- *
- * @returns IPRT status code.
- * @param pThis AC'97 device state.
- * @param pStream Stream to initialize.
- */
-static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream)
+static int ichac97StreamInit(PAC97STATE pThis, PAC97STREAM pStrmSt, uint8_t u8Strm)
{
int rc = VINF_SUCCESS;
- LogFunc(("[SD%RU8]\n", pStream->u8Strm));
-
PDMAUDIOSTREAMCFG streamCfg;
RT_ZERO(streamCfg);
- switch (pStream->u8Strm)
+ switch (u8Strm)
{
- case AC97SOUNDSOURCE_PI_INDEX:
- streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate);
- streamCfg.enmDir = PDMAUDIODIR_IN;
- streamCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
+ case PI_INDEX:
+ streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate);
break;
- case AC97SOUNDSOURCE_MC_INDEX:
- streamCfg.uHz = ichac97MixerGet(pThis, AC97_MIC_ADC_Rate);
- streamCfg.enmDir = PDMAUDIODIR_IN;
- streamCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
+ case MC_INDEX:
+ streamCfg.uHz = ichac97MixerGet(pThis, AC97_MIC_ADC_Rate);
break;
- case AC97SOUNDSOURCE_PO_INDEX:
- streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate);
- streamCfg.enmDir = PDMAUDIODIR_OUT;
- streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
+ case PO_INDEX:
+ streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate);
break;
default:
@@ -991,150 +759,111 @@ static int ichac97StreamOpen(PAC97STATE pThis, PAC97STREAM pStream)
break;
}
- if (RT_SUCCESS(rc))
+ if (RT_FAILURE(rc))
+ return rc;
+
+ if (streamCfg.uHz)
{
- if (streamCfg.uHz)
- {
- streamCfg.cChannels = 2;
- streamCfg.enmFormat = PDMAUDIOFMT_S16;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+ streamCfg.cChannels = 2;
+ streamCfg.enmFormat = AUD_FMT_S16;
+ streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
- rc = ichac97StreamOpenEx(pThis, pStream, &streamCfg);
- }
- else
- rc = VERR_INVALID_PARAMETER;
+ return ichac97StreamInitEx(pThis, pStrmSt, u8Strm, &streamCfg);
}
- LogFlowFunc(("[SD%RU8] rc=%Rrc\n", pStream->u8Strm, rc));
- return rc;
+ /* If no frequency is given, disable the stream. */
+ return ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
}
-static void ichac97StreamClose(PAC97STREAM pStream)
+static int ichac97StreamReInit(PAC97STATE pThis, PAC97STREAM pStrmSt)
{
- RT_NOREF(pStream);
-
- LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
+ return ichac97StreamInit(pThis, pStrmSt, pStrmSt->u8Strm);
}
-/**
- * Re-opens an AC'97 stream on the backend side with the current AC'97 mixer
- * settings for this stream.
- *
- * @returns IPRT status code.
- * @param pThis AC'97 device state.
- * @param pStream Stream to re-open.
- */
-static int ichac97StreamReOpen(PAC97STATE pThis, PAC97STREAM pStream)
-{
- LogFlowFunc(("[SD%RU8]\n", pStream->u8Strm));
-
- ichac97StreamClose(pStream);
-
- return ichac97StreamOpen(pThis, pStream);
-}
-
-static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStrm)
+static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStrmSt)
{
AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStrm);
-
- LogFlowFunc(("[SD%RU8]\n", pStrm->u8Strm));
+ AssertPtrReturnVoid(pStrmSt);
- if (pStrm->State.au8FIFOW)
- {
- Assert(pStrm->State.cbFIFOW);
- RT_BZERO(pStrm->State.au8FIFOW, pStrm->State.cbFIFOW);
- }
-
- pStrm->State.offFIFOW = 0;
+ LogFlowFunc(("uStrm=%RU8\n", pStrmSt->u8Strm));
}
-static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL enmMixerCtl, uint32_t uVal)
+static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL mt, uint32_t val)
{
- bool fCntlMuted;
- uint8_t lCntlAtt, rCntlAtt;
+ int mute = (val >> MUTE_SHIFT) & 1;
+ uint8_t rvol = val & VOL_MASK;
+ uint8_t lvol = (val >> 8) & VOL_MASK;
- /*
- * From AC'97 SoundMax Codec AD1981A/AD1981B:
- * "Because AC '97 defines 6-bit volume registers, to maintain compatibility whenever the
- * D5 or D13 bits are set to 1, their respective lower five volume bits are automatically
- * set to 1 by the Codec logic. On readback, all lower 5 bits will read ones whenever
- * these bits are set to 1."
- *
- * Linux ALSA depends on this behavior.
- */
- /// @todo Does this apply to anything other than the master volume control?
- if (uVal & RT_BIT(5))
- uVal |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
- if (uVal & RT_BIT(13))
- uVal |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
-
- fCntlMuted = (uVal >> AC97_BARS_VOL_MUTE_SHIFT) & 1;
- lCntlAtt = (uVal >> 8) & AC97_BARS_VOL_MASK;
- rCntlAtt = uVal & AC97_BARS_VOL_MASK;
-
- /* For the master and headphone volume, 0 corresponds to 0dB attenuation. For the other
- * volume controls, 0 means 12dB gain and 8 means unity gain.
- */
- if (index != AC97_Master_Volume_Mute && index != AC97_Headphone_Volume_Mute)
+ /* For the master volume, 0 corresponds to 0dB gain. But for the other
+ * volume controls, 0 corresponds to +12dB and 8 to 0dB. */
+ if (mt != PDMAUDIOMIXERCTL_VOLUME)
{
-#ifndef VBOX_WITH_AC97_GAIN_SUPPORT
/* NB: Currently there is no gain support, only attenuation. */
- lCntlAtt = lCntlAtt < 8 ? 0 : lCntlAtt - 8;
- rCntlAtt = rCntlAtt < 8 ? 0 : rCntlAtt - 8;
-#endif
+ lvol = lvol < 8 ? 0 : lvol - 8;
+ rvol = rvol < 8 ? 0 : rvol - 8;
}
- Assert(lCntlAtt <= 255 / AC97_DB_FACTOR);
- Assert(rCntlAtt <= 255 / AC97_DB_FACTOR);
- LogFunc(("index=0x%x, uVal=%RU32, enmMixerCtl=%RU32\n", index, uVal, enmMixerCtl));
- LogFunc(("lAtt=%RU8, rAtt=%RU8 ", lCntlAtt, rCntlAtt));
+ /* AC'97 has 1.5dB steps; we use 0.375dB steps. */
+ rvol = 255 - rvol * 4;
+ lvol = 255 - lvol * 4;
- /*
- * For AC'97 volume controls, each additional step means -1.5dB attenuation with
- * zero being maximum. In contrast, we're internally using 255 (PDMAUDIO_VOLUME_MAX)
- * steps, each -0.375dB, where 0 corresponds to -96dB and 255 corresponds to 0dB.
- */
- uint8_t lVol = PDMAUDIO_VOLUME_MAX - lCntlAtt * AC97_DB_FACTOR;
- uint8_t rVol = PDMAUDIO_VOLUME_MAX - rCntlAtt * AC97_DB_FACTOR;
-
- Log(("-> fMuted=%RTbool, lVol=%RU8, rVol=%RU8\n", fCntlMuted, lVol, rVol));
+ LogFunc(("mt=%ld, val=%RX32, mute=%RTbool\n", mt, val, RT_BOOL(mute)));
int rc;
+#ifdef SOFT_VOLUME
if (pThis->pMixer) /* Device can be in reset state, so no mixer available. */
{
- PDMAUDIOVOLUME Vol = { fCntlMuted, lVol, rVol };
- switch (enmMixerCtl)
+ PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
+ switch (mt)
{
- case PDMAUDIOMIXERCTL_VOLUME_MASTER:
- rc = AudioMixerSetMasterVolume(pThis->pMixer, &Vol);
+ case PDMAUDIOMIXERCTL_VOLUME:
+ rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
break;
- case PDMAUDIOMIXERCTL_FRONT:
- rc = AudioMixerSinkSetVolume(pThis->pSinkOut, &Vol);
+
+ case PDMAUDIOMIXERCTL_PCM:
+ rc = AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
break;
case PDMAUDIOMIXERCTL_MIC_IN:
- rc = AudioMixerSinkSetVolume(pThis->pSinkMicIn, &Vol);
+ rc = AudioMixerSetSinkVolume(pThis->pSinkMicIn, &vol);
break;
case PDMAUDIOMIXERCTL_LINE_IN:
- rc = AudioMixerSinkSetVolume(pThis->pSinkLineIn, &Vol);
+ rc = AudioMixerSetSinkVolume(pThis->pSinkLineIn, &vol);
break;
default:
- AssertFailed();
rc = VERR_NOT_SUPPORTED;
break;
}
}
else
- rc = VINF_SUCCESS;
-
- ichac97MixerSet(pThis, index, uVal);
+ rc = VERR_NOT_SUPPORTED;
if (RT_FAILURE(rc))
- LogFlowFunc(("Failed with %Rrc\n", rc));
+ return rc;
+#else
+ rc = VINF_SUCCESS;
+#endif /* SOFT_VOLUME */
+
+ rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
+ lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
+
+ /*
+ * From AC'97 SoundMax Codec AD1981A: "Because AC '97 defines 6-bit volume registers, to
+ * maintain compatibility whenever the D5 or D13 bits are set to `1,' their respective
+ * lower five volume bits are automatically set to `1' by the Codec logic. On readback,
+ * all lower 5 bits will read ones whenever these bits are set to `1.'"
+ *
+ * Linux ALSA depends on this behavior.
+ */
+ if (val & RT_BIT(5))
+ val |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
+ if (val & RT_BIT(13))
+ val |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
+
+ ichac97MixerSet(pThis, index, val);
return rc;
}
@@ -1143,12 +872,12 @@ static PDMAUDIORECSOURCE ichac97IndextoRecSource(uint8_t i)
{
switch (i)
{
- case AC97_REC_MIC: return PDMAUDIORECSOURCE_MIC;
- case AC97_REC_CD: return PDMAUDIORECSOURCE_CD;
- case AC97_REC_VIDEO: return PDMAUDIORECSOURCE_VIDEO;
- case AC97_REC_AUX: return PDMAUDIORECSOURCE_AUX;
- case AC97_REC_LINE_IN: return PDMAUDIORECSOURCE_LINE;
- case AC97_REC_PHONE: return PDMAUDIORECSOURCE_PHONE;
+ case REC_MIC: return PDMAUDIORECSOURCE_MIC;
+ case REC_CD: return PDMAUDIORECSOURCE_CD;
+ case REC_VIDEO: return PDMAUDIORECSOURCE_VIDEO;
+ case REC_AUX: return PDMAUDIORECSOURCE_AUX;
+ case REC_LINE_IN: return PDMAUDIORECSOURCE_LINE_IN;
+ case REC_PHONE: return PDMAUDIORECSOURCE_PHONE;
default:
break;
}
@@ -1161,26 +890,27 @@ static uint8_t ichac97RecSourceToIndex(PDMAUDIORECSOURCE rs)
{
switch (rs)
{
- case PDMAUDIORECSOURCE_MIC: return AC97_REC_MIC;
- case PDMAUDIORECSOURCE_CD: return AC97_REC_CD;
- case PDMAUDIORECSOURCE_VIDEO: return AC97_REC_VIDEO;
- case PDMAUDIORECSOURCE_AUX: return AC97_REC_AUX;
- case PDMAUDIORECSOURCE_LINE: return AC97_REC_LINE_IN;
- case PDMAUDIORECSOURCE_PHONE: return AC97_REC_PHONE;
+ case PDMAUDIORECSOURCE_MIC: return REC_MIC;
+ case PDMAUDIORECSOURCE_CD: return REC_CD;
+ case PDMAUDIORECSOURCE_VIDEO: return REC_VIDEO;
+ case PDMAUDIORECSOURCE_AUX: return REC_AUX;
+ case PDMAUDIORECSOURCE_LINE_IN: return REC_LINE_IN;
+ case PDMAUDIORECSOURCE_PHONE: return REC_PHONE;
default:
break;
}
LogFlowFunc(("Unknown audio recording source %d using MIC\n", rs));
- return AC97_REC_MIC;
+ return REC_MIC;
}
static void ichac97RecordSelect(PAC97STATE pThis, uint32_t val)
{
- uint8_t rs = val & AC97_REC_MASK;
- uint8_t ls = (val >> 8) & AC97_REC_MASK;
+ uint8_t rs = val & REC_MASK;
+ uint8_t ls = (val >> 8) & REC_MASK;
PDMAUDIORECSOURCE ars = ichac97IndextoRecSource(rs);
PDMAUDIORECSOURCE als = ichac97IndextoRecSource(ls);
+ //AUD_set_record_source(&als, &ars);
rs = ichac97RecSourceToIndex(ars);
ls = ichac97RecSourceToIndex(als);
ichac97MixerSet(pThis, AC97_Record_Select, rs | (ls << 8));
@@ -1217,15 +947,15 @@ static int ichac97MixerReset(PAC97STATE pThis)
ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80);
ichac97MixerSet(pThis, AC97_MIC_ADC_Rate , 0xbb80);
- if (pThis->uCodecModel == AC97_CODEC_AD1980)
+ if (pThis->uCodecModel == Codec_AD1980)
{
/* Analog Devices 1980 (AD1980) */
- ichac97MixerSet(pThis, AC97_Reset , 0x0010); /* Headphones. */
+ ichac97MixerSet(pThis, AC97_Reset , 0x0010); /* Headphones. */
ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5370);
ichac97MixerSet(pThis, AC97_Headphone_Volume_Mute , 0x8000);
}
- else if (pThis->uCodecModel == AC97_CODEC_AD1981B)
+ else if (pThis->uCodecModel == Codec_AD1981B)
{
/* Analog Devices 1981B (AD1981B) */
ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
@@ -1239,10 +969,9 @@ static int ichac97MixerReset(PAC97STATE pThis)
}
ichac97RecordSelect(pThis, 0);
- ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER, 0x8000);
- ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT, 0x8808);
- ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
- ichac97MixerSetVolume(pThis, AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN, 0x8808);
+ ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME, 0x8000);
+ ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM, 0x8808);
+ ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
return VINF_SUCCESS;
}
@@ -1252,28 +981,26 @@ static int ichac97MixerReset(PAC97STATE pThis)
*
* @return IPRT status code.
* @param pThis
- * @param pStream
+ * @param pStrmSt
* @param cbMax
* @param pcbWritten
*/
-static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToWrite, uint32_t *pcbWritten)
+static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t cbMax, uint32_t *pcbWritten)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertReturn(cbToWrite, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+ AssertReturn(cbMax, VERR_INVALID_PARAMETER);
/* pcbWritten is optional. */
PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
- PAC97BMREGS pRegs = &pStream->Regs;
-
- uint32_t uAddr = pRegs->bd.addr;
+ PAC97BMREGS pRegs = &pStrmSt->Regs;
+ uint32_t addr = pRegs->bd.addr;
uint32_t cbWrittenTotal = 0;
+ uint32_t cbToRead = 0;
- Log3Func(("PICB=%RU16, cbToWrite=%RU32\n", pRegs->picb, cbToWrite));
-
- uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToWrite); /** @todo r=andy Assumes 16bit sample size. */
- if (!cbLeft)
+ uint32_t cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbMax);
+ if (!cbToWrite)
{
if (pcbWritten)
*pcbWritten = 0;
@@ -1282,79 +1009,67 @@ static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbT
int rc = VINF_SUCCESS;
- Assert(pStream->State.offFIFOW <= pStream->State.cbFIFOW);
- uint32_t cbFIFOW = pStream->State.cbFIFOW - pStream->State.offFIFOW;
- uint8_t *pu8FIFOW = &pStream->State.au8FIFOW[pStream->State.offFIFOW];
-
- uint32_t cbWritten = 0;
+ LogFlowFunc(("pReg=%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbMax, cbToWrite));
- while (cbLeft)
+ while (cbToWrite)
{
- uint32_t cbToRead = RT_MIN(cbLeft, cbFIFOW);
+ cbToRead = RT_MIN(cbToWrite, pThis->cbReadWriteBuf);
+ PDMDevHlpPhysRead(pDevIns, addr, pThis->pvReadWriteBuf, cbToRead); /** @todo Check rc? */
- PDMDevHlpPhysRead(pDevIns, uAddr, pu8FIFOW, cbToRead); /** @todo r=andy Check rc? */
+ uint32_t cbWritten;
-#ifdef AC97_DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- RTFileOpen(&fh, AC97_DEBUG_DUMP_PCM_DATA_PATH "ac97WriteAudio.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- RTFileWrite(fh, pu8FIFOW, cbToRead, NULL);
- RTFileClose(fh);
-#endif
- /*
- * Write data to the mixer sink.
- */
- rc = AudioMixerSinkWrite(pThis->pSinkOut, AUDMIXOP_COPY, pu8FIFOW, cbToRead, &cbWritten);
- if (RT_FAILURE(rc))
- break;
+ /* Just multiplex the output to the connected backends.
+ * No need to utilize the virtual mixer here (yet). */
+ PAC97DRIVER pDrv;
+ RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+ {
+ int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+ pThis->pvReadWriteBuf, cbToRead, &cbWritten);
+ RT_NOREF(rc2);
+ LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWritten=%RU32\n", pDrv->uLUN, rc2, cbWritten));
+ }
- /* Advance. */
- Assert(cbLeft >= cbWritten);
- cbLeft -= cbWritten;
- cbWrittenTotal += cbWritten;
- uAddr += cbWritten;
- Assert(cbWrittenTotal <= cbToWrite);
+ LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbLeft=%RU32\n",
+ cbToRead, cbToWrite, cbToWrite - cbWrittenTotal));
- LogFlowFunc(("%RU32 / %RU32\n", cbWrittenTotal, cbToWrite));
+ Assert(cbToWrite >= cbToRead);
+ cbToWrite -= cbToRead;
+ addr += cbToRead;
+ cbWrittenTotal += cbToRead;
}
- /* Set new buffer descriptor address. */
- pRegs->bd.addr = uAddr;
+ pRegs->bd.addr = addr;
if (RT_SUCCESS(rc))
{
- if (!cbLeft) /* All data written? */
+ if (!cbToWrite) /* All data written? */
{
- if (cbWritten < 4)
+ if (cbToRead < 4)
{
- AssertMsgFailed(("Unable to save last written sample, cbWritten < 4 (is %RU32)\n", cbWritten));
+ AssertMsgFailed(("Unable to save last written sample, cbToRead < 4 (is %RU32)\n", cbToRead));
pThis->last_samp = 0;
}
else
- pThis->last_samp = *(uint32_t *)&pStream->State.au8FIFOW[pStream->State.offFIFOW + cbWritten - 4];
+ pThis->last_samp = *(uint32_t *)&pThis->pvReadWriteBuf[cbToRead - 4];
}
if (pcbWritten)
*pcbWritten = cbWrittenTotal;
}
- if (RT_FAILURE(rc))
- LogFlowFunc(("Failed with %Rrc\n", rc));
-
+ LogFlowFunc(("cbWrittenTotal=%RU32, rc=%Rrc\n", cbWrittenTotal, rc));
return rc;
}
static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
{
- LogFlowFunc(("cbElapsed=%RU32\n", cbElapsed));
-
if (!(pThis->bup_flag & BUP_SET))
{
if (pThis->bup_flag & BUP_LAST)
{
unsigned int i;
uint32_t *p = (uint32_t*)pThis->silence;
- for (i = 0; i < sizeof(pThis->silence) / 4; i++) /** @todo r=andy Assumes 16-bit samples, stereo. */
+ for (i = 0; i < sizeof(pThis->silence) / 4; i++)
*p++ = pThis->last_samp;
}
else
@@ -1367,13 +1082,28 @@ static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
{
uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence));
uint32_t cbWrittenToStream;
+ int rc2;
- int rc2 = AudioMixerSinkWrite(pThis->pSinkOut, AUDMIXOP_COPY,
- pThis->silence, cbToWrite, &cbWrittenToStream);
- if (RT_SUCCESS(rc2))
+ PAC97DRIVER pDrv;
+ RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
{
- if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
- LogFlowFunc(("Warning: Only written %RU32 / %RU32 bytes, expect lags\n", cbWrittenToStream, cbToWrite));
+ if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut))
+ {
+ rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+ pThis->silence, cbToWrite, &cbWrittenToStream);
+ if (RT_SUCCESS(rc2))
+ {
+ if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
+ LogFlowFunc(("\tLUN#%RU8: Warning: Only written %RU32 / %RU32 bytes, expect lags\n",
+ pDrv->uLUN, cbWrittenToStream, cbToWrite));
+ }
+ }
+ else /* Stream disabled, not fatal. */
+ {
+ cbWrittenToStream = 0;
+ rc2 = VERR_NOT_AVAILABLE;
+ /* Keep going. */
+ }
}
/* Always report all data as being written;
@@ -1383,25 +1113,25 @@ static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
}
}
-static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToRead, uint32_t *pcbRead)
+static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t cbMax, uint32_t *pcbRead)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertReturn(cbToRead, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
+ AssertReturn(cbMax, VERR_INVALID_PARAMETER);
/* pcbRead is optional. */
PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
- PAC97BMREGS pRegs = &pStream->Regs;
+ PAC97BMREGS pRegs = &pStrmSt->Regs;
/* Select audio sink to process. */
- AssertMsg(pStream->u8Strm != AC97SOUNDSOURCE_PO_INDEX, ("Can't read from output\n"));
- PAUDMIXSINK pSink = pStream->u8Strm == AC97SOUNDSOURCE_MC_INDEX ? pThis->pSinkMicIn : pThis->pSinkLineIn;
+ AssertMsg(pStrmSt->u8Strm != PO_INDEX, ("Can't read from output\n"));
+ PAUDMIXSINK pSink = pStrmSt->u8Strm == MC_INDEX ? pThis->pSinkMicIn : pThis->pSinkLineIn;
AssertPtr(pSink);
uint32_t cbRead = 0;
- cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1),
- RT_MIN(pStream->State.cbFIFOW, cbToRead)); /** @todo r=andy Assumes 16bit samples. */
+ uint32_t cbMixBuf = cbMax;
+ uint32_t cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1), cbMixBuf);
if (!cbToRead)
{
@@ -1412,19 +1142,24 @@ static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbTo
int rc;
- rc = AudioMixerSinkRead(pSink, AUDMIXOP_BLEND, &pStream->State.au8FIFOW[pStream->State.offFIFOW], cbToRead, &cbRead);
- if ( RT_SUCCESS(rc)
- && cbRead)
+ uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbMixBuf);
+ if (pvMixBuf)
{
- PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, &pStream->State.au8FIFOW[pStream->State.offFIFOW], cbRead);
- pRegs->bd.addr += cbRead;
+ rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pvMixBuf, cbToRead, &cbRead);
+ if ( RT_SUCCESS(rc)
+ && cbRead)
+ {
+ PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, pvMixBuf, cbRead);
+ pRegs->bd.addr += cbRead;
+ }
+
+ RTMemFree(pvMixBuf);
}
+ else
+ rc = VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
{
- if (!cbRead)
- rc = VINF_EOF;
-
if (pcbRead)
*pcbRead = cbRead;
}
@@ -1434,46 +1169,6 @@ static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbTo
#ifndef VBOX_WITH_AUDIO_CALLBACKS
-static void ichac97TimerMaybeStart(PAC97STATE pThis)
-{
- if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
- return;
-
- if (!pThis->pTimer)
- return;
-
- if (ASMAtomicReadBool(&pThis->fTimerActive) == true) /* Alredy started? */
- return;
-
- LogFlowFunc(("Starting timer\n"));
-
- /* Set timer flag. */
- ASMAtomicXchgBool(&pThis->fTimerActive, true);
-
- /* Update current time timestamp. */
- pThis->uTimerTS = TMTimerGet(pThis->pTimer);
-
- /* Fire off timer. */
- TMTimerSet(pThis->pTimer, 0 /* u64Expire */);
-}
-
-static void ichac97TimerMaybeStop(PAC97STATE pThis)
-{
- if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
- return;
-
- if (!pThis->pTimer)
- return;
-
- if (ASMAtomicReadBool(&pThis->fTimerActive) == false) /* Already stopped? */
- return;
-
- LogFlowFunc(("Stopping timer\n"));
-
- /* Set timer flag. */
- ASMAtomicXchgBool(&pThis->fTimerActive, false);
-}
-
static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
{
RT_NOREF(pDevIns);
@@ -1481,99 +1176,134 @@ static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void
Assert(pThis == PDMINS_2_DATA(pDevIns, PAC97STATE));
AssertPtr(pThis);
- int rc = RTCritSectEnter(&pThis->csTimer);
- if (RT_SUCCESS(rc))
- {
- STAM_PROFILE_START(&pThis->StatTimer, a);
+ STAM_PROFILE_START(&pThis->StatTimer, a);
- uint64_t cTicksNow = TMTimerGet(pTimer);
+ uint32_t cbInMax = 0;
+ uint32_t cbOutMin = UINT32_MAX;
- /* Update current time timestamp. */
- pThis->uTimerTS = cTicksNow;
+ PAC97DRIVER pDrv;
- /* Flag indicating whether to kick the timer again for the next DMA transfer or sink processing. */
- bool fDoNextTransfer = false;
+ uint64_t cTicksNow = TMTimerGet(pTimer);
+ uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS;
+ uint64_t cTicksPerSec = TMTimerGetFreq(pTimer);
- uint32_t cbToProcess;
+ pThis->uTimerTS = cTicksNow;
- rc = AudioMixerSinkUpdate(pThis->pSinkLineIn);
- if (RT_SUCCESS(rc))
- {
- cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkLineIn);
- if (cbToProcess)
- rc = ichac97TransferAudio(pThis, &pThis->StreamLineIn, cbToProcess, NULL /* pcbProcessed */);
+ /*
+ * Calculate the mixer's (fixed) sampling rate.
+ */
+ AssertPtr(pThis->pMixer);
- if (AudioMixerSinkGetStatus(pThis->pSinkLineIn) & AUDMIXSINK_STS_DIRTY)
- fDoNextTransfer = true;
- }
+ PDMAUDIOSTREAMCFG mixerStrmCfg;
+ int rc = AudioMixerGetDeviceFormat(pThis->pMixer, &mixerStrmCfg);
+ AssertRC(rc);
- rc = AudioMixerSinkUpdate(pThis->pSinkMicIn);
- if (RT_SUCCESS(rc))
- {
- cbToProcess = AudioMixerSinkGetReadable(pThis->pSinkMicIn);
- if (cbToProcess)
- rc = ichac97TransferAudio(pThis, &pThis->StreamMicIn, cbToProcess, NULL /* pcbProcessed */);
+ PDMPCMPROPS mixerStrmProps;
+ rc = DrvAudioStreamCfgToProps(&mixerStrmCfg, &mixerStrmProps);
+ AssertRC(rc);
- if (AudioMixerSinkGetStatus(pThis->pSinkMicIn) & AUDMIXSINK_STS_DIRTY)
- fDoNextTransfer = true;
- }
+ uint32_t cMixerSamplesMin = (int)((2 * cTicksElapsed * mixerStrmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
+ uint32_t cbMixerSamplesMin = cMixerSamplesMin << mixerStrmProps.cShift;
- rc = AudioMixerSinkUpdate(pThis->pSinkOut);
+ RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+ {
+ uint32_t cbIn = 0;
+ uint32_t cbOut = 0;
+
+ rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
+ &cbIn, &cbOut, NULL /* cSamplesLive */);
if (RT_SUCCESS(rc))
- {
- cbToProcess = AudioMixerSinkGetWritable(pThis->pSinkOut);
- if (cbToProcess)
- rc = ichac97TransferAudio(pThis, &pThis->StreamOut, cbToProcess, NULL /* pcbProcessed */);
+ rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* cSamplesPlayed */);
- if (AudioMixerSinkGetStatus(pThis->pSinkOut) & AUDMIXSINK_STS_DIRTY)
- fDoNextTransfer = true;
- }
+ Log3Func(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
- if (fDoNextTransfer)
+ /* If we there was an error handling (available) output or there simply is no output available,
+ * then calculate the minimum data rate which must be processed by the device emulation in order
+ * to function correctly.
+ *
+ * This is not the optimal solution, but as we have to deal with this on a timer-based approach
+ * (until we have the audio callbacks) we need to have device' DMA engines running. */
+ if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
{
- /* Kick the timer again. */
- uint64_t cTicks = pThis->cTimerTicks;
- /** @todo adjust cTicks down by now much cbOutMin represents. */
- TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
+ /* Use the mixer's (fixed) sampling rate. */
+ cbOut = RT_MAX(cbOut, cbMixerSamplesMin);
}
else
{
- LogFunc(("Stopping timer\n"));
- LogRel3(("AC97: Stopping timer\n"));
+ const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
+ if ( RT_FAILURE(rc)
+ || !fIsActiveOut)
+ {
+ uint32_t cSamplesMin = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
+ uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
+
+ Log3Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
+
+ cbOut = RT_MAX(cbOut, cbSamplesMin);
+ }
}
- STAM_PROFILE_STOP(&pThis->StatTimer, a);
+ cbOutMin = RT_MIN(cbOutMin, cbOut);
+ cbInMax = RT_MAX(cbInMax, cbIn);
+ }
- int rc2 = RTCritSectLeave(&pThis->csTimer);
- if (RT_SUCCESS(rc))
- rc2 = rc;
+ Log3Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
+
+ if (cbOutMin == UINT32_MAX)
+ cbOutMin = 0;
+
+ /*
+ * Playback.
+ */
+ if (cbOutMin)
+ {
+ Assert(cbOutMin != UINT32_MAX);
+ ichac97TransferAudio(pThis, PO_INDEX, cbOutMin); /** @todo Add rc! */
}
+
+ /*
+ * Recording.
+ */
+ if (cbInMax)
+ ichac97TransferAudio(pThis, PI_INDEX, cbInMax); /** @todo Add rc! */
+
+ /* Kick the timer again. */
+ uint64_t cTicks = pThis->cTimerTicks;
+ /** @todo adjust cTicks down by now much cbOutMin represents. */
+ TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
+
+ STAM_PROFILE_STOP(&pThis->StatTimer, a);
}
-#endif /* !VBOX_WITH_AUDIO_CALLBACKS */
+#endif
-static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t cbToProcess, uint32_t *pcbProcessed)
+static int ichac97TransferAudio(PAC97STATE pThis, AC97SOUNDSOURCE enmSrc, uint32_t cbElapsed)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbProcessed is optional. */
-
- int rc = RTCritSectEnter(&pStream->CritSect);
- if (RT_FAILURE(rc))
- return rc;
+ LogFlowFunc(("pThis=%p, enmSrc=%RU32, cbElapsed=%RU32\n", pThis, enmSrc, cbElapsed));
- LogFunc(("[SD%RU8] cbToProcess=%RU32\n", pStream->u8Strm, cbToProcess));
+ PAC97STREAM pStrmSt;
+ switch (enmSrc)
+ {
+ case PI_INDEX: pStrmSt = &pThis->StrmStLineIn; break;
+ case MC_INDEX: pStrmSt = &pThis->StrmStMicIn; break;
+ case PO_INDEX: pStrmSt = &pThis->StrmStOut; break;
+ default:
+ {
+ AssertMsgFailed(("Unknown source index %ld\n", enmSrc));
+ return VERR_NOT_SUPPORTED;
+ }
+ }
- PAC97BMREGS pRegs = &pStream->Regs;
+ PAC97BMREGS pRegs = &pStrmSt->Regs;
- if (pRegs->sr & AC97_SR_DCH) /* Controller halted? */
+ if (pRegs->sr & SR_DCH) /* Controller halted? */
{
- if (pRegs->cr & AC97_CR_RPBM) /* Bus master operation starts. */
+ if (pRegs->cr & CR_RPBM)
{
- switch (pStream->u8Strm)
+ switch (enmSrc)
{
- case AC97SOUNDSOURCE_PO_INDEX:
- ichac97WriteBUP(pThis, cbToProcess);
+ case PO_INDEX:
+ ichac97WriteBUP(pThis, cbElapsed);
break;
default:
@@ -1581,42 +1311,18 @@ static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t
}
}
- if (pcbProcessed)
- *pcbProcessed = 0;
-
- Log3Func(("[SD%RU8] Halted\n", pStream->u8Strm));
-
- rc = RTCritSectLeave(&pStream->CritSect);
- AssertRC(rc);
-
return VINF_SUCCESS;
}
- /* BCIS flag still set? Skip iteration. */
- if (pRegs->sr & AC97_SR_BCIS)
- {
- Log3Func(("[SD%RU8] BCIS set\n", pStream->u8Strm));
-
- if (pcbProcessed)
- *pcbProcessed = 0;
-
- rc = RTCritSectLeave(&pStream->CritSect);
- AssertRC(rc);
-
- return VINF_SUCCESS;
- }
-
- uint32_t cbLeft = RT_MIN((uint32_t)(pRegs->picb << 1), cbToProcess);
- uint32_t cbTotal = 0;
-
- Log3Func(("[SD%RU8] cbLeft=%RU32\n", pStream->u8Strm, cbLeft));
+ int rc = VINF_SUCCESS;
+ uint32_t cbWrittenTotal = 0;
- while (cbLeft)
+ while (cbElapsed >> 1)
{
if (!pRegs->bd_valid)
{
LogFlowFunc(("Invalid buffer descriptor, fetching next one ...\n"));
- ichac97StreamFetchBDLE(pThis, pStream);
+ ichac97StreamFetchBDLE(pThis, pStrmSt);
}
if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */
@@ -1625,114 +1331,96 @@ static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t
pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len));
if (pRegs->civ == pRegs->lvi)
{
- pRegs->sr |= AC97_SR_DCH; /** @todo r=andy Also set CELV? */
+ pRegs->sr |= SR_DCH; /* CELV? */
pThis->bup_flag = 0;
rc = VINF_EOF;
break;
}
- pRegs->sr &= ~AC97_SR_CELV;
+ pRegs->sr &= ~SR_CELV;
pRegs->civ = pRegs->piv;
- pRegs->piv = (pRegs->piv + 1) % 32; /** @todo r=andy Define for max BDLEs? */
+ pRegs->piv = (pRegs->piv + 1) % 32;
- ichac97StreamFetchBDLE(pThis, pStream);
+ ichac97StreamFetchBDLE(pThis, pStrmSt);
continue;
}
- uint32_t cbToTransfer, cbTransferred;
- switch (pStream->u8Strm)
+ uint32_t cbTransferred;
+ switch (enmSrc)
{
- case AC97SOUNDSOURCE_PO_INDEX:
+ case PO_INDEX:
{
- cbToTransfer = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
-
- rc = ichac97WriteAudio(pThis, pStream, cbToTransfer, &cbTransferred);
+ rc = ichac97WriteAudio(pThis, pStrmSt, cbElapsed, &cbTransferred);
if ( RT_SUCCESS(rc)
&& cbTransferred)
{
- cbTotal += cbTransferred;
- Assert(cbLeft >= cbTransferred);
- cbLeft -= cbTransferred;
- Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
- pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
+ cbWrittenTotal += cbTransferred;
+ Assert(cbElapsed >= cbTransferred);
+ cbElapsed -= cbTransferred;
+ Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
+ pRegs->picb -= (cbTransferred >> 1);
}
break;
}
- case AC97SOUNDSOURCE_PI_INDEX:
- case AC97SOUNDSOURCE_MC_INDEX:
+ case PI_INDEX:
+ case MC_INDEX:
{
- cbToTransfer = RT_MIN((uint32_t)(pRegs->picb << 1), cbLeft); /** @todo r=andy Assumes 16bit samples. */
-
- rc = ichac97ReadAudio(pThis, pStream, cbToTransfer, &cbTransferred);
+ rc = ichac97ReadAudio(pThis, pStrmSt, cbElapsed, &cbTransferred);
if ( RT_SUCCESS(rc)
&& cbTransferred)
{
- cbTotal += cbTransferred;
- Assert(cbLeft >= cbTransferred);
- cbLeft -= cbTransferred;
- Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
- pRegs->picb -= (cbTransferred >> 1); /** @todo r=andy Assumes 16bit samples. */
+ Assert(cbElapsed >= cbTransferred);
+ cbElapsed -= cbTransferred;
+ Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
+ pRegs->picb -= (cbTransferred >> 1);
}
break;
}
default:
- AssertMsgFailed(("Stream #%RU8 not supported\n", pStream->u8Strm));
+ AssertMsgFailed(("Source %RU32 not supported\n", enmSrc));
rc = VERR_NOT_SUPPORTED;
break;
}
- LogFlowFunc(("[SD%RU8]: %RU32 / %RU32, rc=%Rrc\n", pStream->u8Strm, cbTotal, cbToProcess, rc));
+ LogFlowFunc(("pReg->picb=%#x, cbWrittenTotal=%RU32\n", pRegs->picb, cbWrittenTotal));
if (!pRegs->picb)
{
- uint32_t new_sr = pRegs->sr & ~AC97_SR_CELV;
+ uint32_t new_sr = pRegs->sr & ~SR_CELV;
- if (pRegs->bd.ctl_len & AC97_BD_IOC)
+ if (pRegs->bd.ctl_len & BD_IOC)
{
- new_sr |= AC97_SR_BCIS;
+ new_sr |= SR_BCIS;
}
if (pRegs->civ == pRegs->lvi)
{
- /* Did we run out of data? */
- LogFunc(("Underrun CIV (%RU8) == LVI (%RU8)\n", pRegs->civ, pRegs->lvi));
-
- new_sr |= AC97_SR_LVBCI | AC97_SR_DCH | AC97_SR_CELV;
- pThis->bup_flag = (pRegs->bd.ctl_len & AC97_BD_BUP) ? BUP_LAST : 0;
+ LogFlowFunc(("Underrun civ (%RU8) == lvi (%RU8)\n", pRegs->civ, pRegs->lvi));
+ new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
+ pThis->bup_flag = (pRegs->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
rc = VINF_EOF;
}
else
{
pRegs->civ = pRegs->piv;
- pRegs->piv = (pRegs->piv + 1) % 32; /** @todo r=andy Define for max BDLEs? */
- ichac97StreamFetchBDLE(pThis, pStream);
+ pRegs->piv = (pRegs->piv + 1) % 32;
+ ichac97StreamFetchBDLE(pThis, pStrmSt);
}
- ichac97StreamUpdateSR(pThis, pStream, new_sr);
+ ichac97StreamUpdateStatus(pThis, pStrmSt, new_sr);
}
- if (/* All data processed? */
- rc == VINF_EOF
- /* ... or an error occurred? */
- || RT_FAILURE(rc))
+ if ( RT_FAILURE(rc)
+ || rc == VINF_EOF) /* All data processed? */
{
break;
}
}
- int rc2 = RTCritSectLeave(&pStream->CritSect);
- AssertRC(rc2);
-
- if (RT_SUCCESS(rc))
- {
- if (pcbProcessed)
- *pcbProcessed = cbTotal;
- }
-
LogFlowFuncLeaveRC(rc);
return rc;
}
@@ -1740,26 +1428,17 @@ static int ichac97TransferAudio(PAC97STATE pThis, PAC97STREAM pStream, uint32_t
/**
* @callback_method_impl{FNIOMIOPORTIN}
*/
-static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32Val, unsigned cbVal)
+static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
+ uint32_t *pu32Val, unsigned cbVal)
{
RT_NOREF(pDevIns);
- PAC97STATE pThis = (PAC97STATE)pvUser;
+ PAC97STATE pThis = (PAC97STATE)pvUser;
/* Get the index of the NABMBAR port. */
const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
- PAC97STREAM pStream = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
- PAC97BMREGS pRegs = NULL;
-
- if (pStream)
- {
- pRegs = &pStream->Regs;
-
- int rc2 = RTCritSectEnter(&pStream->CritSect);
- AssertRC(rc2);
- }
-
- int rc = VINF_SUCCESS;
+ PAC97STREAM pStrmSt = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
+ PAC97BMREGS pRegs = pStrmSt ? &pStrmSt->Regs : NULL;
switch (cbVal)
{
@@ -1767,9 +1446,9 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
{
switch (uPortIdx)
{
- case AC97_CAS:
+ case CAS:
/* Codec Access Semaphore Register */
- Log3Func(("CAS %d\n", pThis->cas));
+ LogFlowFunc(("CAS %d\n", pThis->cas));
*pu32Val = pThis->cas;
pThis->cas = 1;
break;
@@ -1778,39 +1457,39 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
case MC_CIV:
/* Current Index Value Register */
*pu32Val = pRegs->civ;
- Log3Func(("CIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+ LogFlowFunc(("CIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
break;
case PI_LVI:
case PO_LVI:
case MC_LVI:
/* Last Valid Index Register */
*pu32Val = pRegs->lvi;
- Log3Func(("LVI[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+ LogFlowFunc(("LVI[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
break;
case PI_PIV:
case PO_PIV:
case MC_PIV:
/* Prefetched Index Value Register */
*pu32Val = pRegs->piv;
- Log3Func(("PIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+ LogFlowFunc(("PIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
break;
case PI_CR:
case PO_CR:
case MC_CR:
/* Control Register */
*pu32Val = pRegs->cr;
- Log3Func(("CR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+ LogFlowFunc(("CR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
break;
case PI_SR:
case PO_SR:
case MC_SR:
/* Status Register (lower part) */
- *pu32Val = RT_LO_U8(pRegs->sr);
- Log3Func(("SRb[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+ *pu32Val = pRegs->sr & 0xff; /** @todo r=andy Use RT_LO_U8. */
+ LogFlowFunc(("SRb[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
break;
default:
*pu32Val = UINT32_MAX;
- LogFunc(("U nabm readb %#x -> %#x\n", Port, *pu32Val));
+ LogFlowFunc(("U nabm readb %#x -> %#x\n", Port, *pu32Val));
break;
}
break;
@@ -1825,18 +1504,18 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
case MC_SR:
/* Status Register */
*pu32Val = pRegs->sr;
- Log3Func(("SR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+ LogFlowFunc(("SR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
break;
case PI_PICB:
case PO_PICB:
case MC_PICB:
- /* Position in Current Buffer */
+ /* Position in Current Buffer Register */
*pu32Val = pRegs->picb;
- Log3Func(("PICB[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+ LogFlowFunc(("PICB[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
break;
default:
*pu32Val = UINT32_MAX;
- LogFunc(("U nabm readw %#x -> %#x\n", Port, *pu32Val));
+ LogFlowFunc(("U nabm readw %#x -> %#x\n", Port, *pu32Val));
break;
}
break;
@@ -1851,7 +1530,7 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
case MC_BDBAR:
/* Buffer Descriptor Base Address Register */
*pu32Val = pRegs->bdbar;
- Log3Func(("BMADDR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
+ LogFlowFunc(("BMADDR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
break;
case PI_CIV:
case PO_CIV:
@@ -1860,8 +1539,8 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
* Last Valid Index Register +
* Status Register */
*pu32Val = pRegs->civ | (pRegs->lvi << 8) | (pRegs->sr << 16); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
- Log3Func(("CIV LVI SR[%d] -> %#x, %#x, %#x\n",
- AC97_PORT2IDX(uPortIdx), pRegs->civ, pRegs->lvi, pRegs->sr));
+ LogFlowFunc(("CIV LVI SR[%d] -> %#x, %#x, %#x\n",
+ AC97_PORT2IDX(uPortIdx), pRegs->civ, pRegs->lvi, pRegs->sr));
break;
case PI_PICB:
case PO_PICB:
@@ -1870,41 +1549,31 @@ static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser,
* Prefetched Index Value Register +
* Control Register */
*pu32Val = pRegs->picb | (pRegs->piv << 16) | (pRegs->cr << 24); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
- Log3Func(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n",
- AC97_PORT2IDX(uPortIdx), *pu32Val, pRegs->picb, pRegs->piv, pRegs->cr));
+ LogFlowFunc(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n",
+ AC97_PORT2IDX(uPortIdx), *pu32Val, pRegs->picb, pRegs->piv, pRegs->cr));
break;
- case AC97_GLOB_CNT:
+ case GLOB_CNT:
/* Global Control */
*pu32Val = pThis->glob_cnt;
- Log3Func(("glob_cnt -> %#x\n", *pu32Val));
+ LogFlowFunc(("glob_cnt -> %#x\n", *pu32Val));
break;
- case AC97_GLOB_STA:
+ case GLOB_STA:
/* Global Status */
- *pu32Val = pThis->glob_sta | AC97_GS_S0CR;
- Log3Func(("glob_sta -> %#x\n", *pu32Val));
+ *pu32Val = pThis->glob_sta | GS_S0CR;
+ LogFlowFunc(("glob_sta -> %#x\n", *pu32Val));
break;
default:
*pu32Val = UINT32_MAX;
- LogFunc(("U nabm readl %#x -> %#x\n", Port, *pu32Val));
+ LogFlowFunc(("U nabm readl %#x -> %#x\n", Port, *pu32Val));
break;
}
break;
}
default:
- {
- AssertFailed();
- rc = VERR_IOM_IOPORT_UNUSED;
- }
- }
-
- if (pStream)
- {
- int rc2 = RTCritSectLeave(&pStream->CritSect);
- AssertRC(rc2);
+ return VERR_IOM_IOPORT_UNUSED;
}
-
- return rc;
+ return VINF_SUCCESS;
}
/**
@@ -1919,20 +1588,8 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
/* Get the index of the NABMBAR register. */
const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
- PAC97STREAM pStream = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
- PAC97BMREGS pRegs = NULL;
-
- PAUDMIXSINK pSink = NULL;
-
- if (pStream)
- {
- pRegs = &pStream->Regs;
- pSink = ichac97IndexToSink(pThis, pStream->u8Strm);
- AssertPtr(pSink);
-
- int rc2 = RTCritSectEnter(&pStream->CritSect);
- AssertRC(rc2);
- }
+ PAC97STREAM pStrmSt = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
+ PAC97BMREGS pRegs = pStrmSt ? &pStrmSt->Regs : NULL;
switch (cbVal)
{
@@ -1940,79 +1597,62 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
{
switch (uPortIdx)
{
- /*
- * Last Valid Index.
- */
case PI_LVI:
case PO_LVI:
case MC_LVI:
- {
- if ( (pRegs->cr & AC97_CR_RPBM)
- && (pRegs->sr & AC97_SR_DCH))
+ /* Last Valid Index */
+ if ((pRegs->cr & CR_RPBM) && (pRegs->sr & SR_DCH))
{
- pRegs->sr &= ~(AC97_SR_DCH | AC97_SR_CELV);
+ pRegs->sr &= ~(SR_DCH | SR_CELV);
pRegs->civ = pRegs->piv;
pRegs->piv = (pRegs->piv + 1) % 32;
- ichac97StreamFetchBDLE(pThis, pStream);
+ ichac97StreamFetchBDLE(pThis, pStrmSt);
}
pRegs->lvi = u32Val % 32;
- Log3Func(("[SD%RU8] LVI <- %#x\n", pStream->u8Strm, u32Val));
+ LogFlowFunc(("LVI[%d] <- %#x\n", AC97_PORT2IDX(uPortIdx), u32Val));
break;
- }
-
- /*
- * Control Registers.
- */
case PI_CR:
case PO_CR:
case MC_CR:
{
- if (u32Val & AC97_CR_RR) /* Busmaster reset */
+ /* Control Register */
+ if (u32Val & CR_RR) /* Busmaster reset */
{
- ichac97StreamResetBMRegs(pThis, pStream);
+ ichac97StreamResetBMRegs(pThis, pStrmSt);
}
else
{
- pRegs->cr = u32Val & AC97_CR_VALID_MASK;
- if (!(pRegs->cr & AC97_CR_RPBM))
+ pRegs->cr = u32Val & CR_VALID_MASK;
+ if (!(pRegs->cr & CR_RPBM))
{
- ichac97StreamEnable(pThis, pStream, false /* fActive */);
-
- pRegs->sr |= AC97_SR_DCH;
+ ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
+ pRegs->sr |= SR_DCH;
}
else
{
pRegs->civ = pRegs->piv;
pRegs->piv = (pRegs->piv + 1) % 32;
- pRegs->sr &= ~AC97_SR_DCH;
+ ichac97StreamFetchBDLE(pThis, pStrmSt);
- /* Fetch the initial BDLE descriptor. */
- ichac97StreamFetchBDLE(pThis, pStream);
-
- ichac97StreamEnable(pThis, pStream, true /* fActive */);
+ pRegs->sr &= ~SR_DCH;
+ ichac97StreamSetActive(pThis, pStrmSt, true /* fActive */);
}
}
- Log3Func(("[SD%RU8] CR <- %#x (cr %#x)\n", pStream->u8Strm, u32Val, pRegs->cr));
+ LogFlowFunc(("CR[%d] <- %#x (cr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->cr));
break;
}
-
- /*
- * Status Registers.
- */
case PI_SR:
case PO_SR:
case MC_SR:
- {
- pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
- ichac97StreamUpdateSR(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
- Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8Strm, u32Val, pRegs->sr));
+ /* Status Register */
+ pRegs->sr |= u32Val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+ ichac97StreamUpdateStatus(pThis, pStrmSt, pRegs->sr & ~(u32Val & SR_WCLEAR_MASK));
+ LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->sr));
break;
- }
-
default:
- LogFunc(("Unimplemented: %#x <- %#x (Byte)\n", Port, u32Val));
+ LogFlowFunc(("U nabm writeb %#x <- %#x\n", Port, u32Val));
break;
}
break;
@@ -2026,12 +1666,12 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
case PO_SR:
case MC_SR:
/* Status Register */
- pRegs->sr |= u32Val & ~(AC97_SR_RO_MASK | AC97_SR_WCLEAR_MASK);
- ichac97StreamUpdateSR(pThis, pStream, pRegs->sr & ~(u32Val & AC97_SR_WCLEAR_MASK));
- Log3Func(("[SD%RU8] SR <- %#x (sr %#x)\n", pStream->u8Strm, u32Val, pRegs->sr));
+ pRegs->sr |= u32Val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
+ ichac97StreamUpdateStatus(pThis, pStrmSt, pRegs->sr & ~(u32Val & SR_WCLEAR_MASK));
+ LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->sr));
break;
default:
- LogFunc(("Unimplemented: %#x <- %#x (Word)\n", Port, u32Val));
+ LogFlowFunc(("U nabm writew %#x <- %#x\n", Port, u32Val));
break;
}
break;
@@ -2046,26 +1686,26 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
case MC_BDBAR:
/* Buffer Descriptor list Base Address Register */
pRegs->bdbar = u32Val & ~3;
- Log3Func(("[SD%RU8] BDBAR <- %#x (bdbar %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->bdbar));
+ LogFlowFunc(("BDBAR[%d] <- %#x (bdbar %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->bdbar));
break;
- case AC97_GLOB_CNT:
+ case GLOB_CNT:
/* Global Control */
- if (u32Val & AC97_GC_WR)
+ if (u32Val & GC_WR)
ichac97WarmReset(pThis);
- if (u32Val & AC97_GC_CR)
+ if (u32Val & GC_CR)
ichac97ColdReset(pThis);
- if (!(u32Val & (AC97_GC_WR | AC97_GC_CR)))
- pThis->glob_cnt = u32Val & AC97_GC_VALID_MASK;
- Log3Func(("glob_cnt <- %#x (glob_cnt %#x)\n", u32Val, pThis->glob_cnt));
+ if (!(u32Val & (GC_WR | GC_CR)))
+ pThis->glob_cnt = u32Val & GC_VALID_MASK;
+ LogFlowFunc(("glob_cnt <- %#x (glob_cnt %#x)\n", u32Val, pThis->glob_cnt));
break;
- case AC97_GLOB_STA:
+ case GLOB_STA:
/* Global Status */
- pThis->glob_sta &= ~(u32Val & AC97_GS_WCLEAR_MASK);
- pThis->glob_sta |= (u32Val & ~(AC97_GS_WCLEAR_MASK | AC97_GS_RO_MASK)) & AC97_GS_VALID_MASK;
- Log3Func(("glob_sta <- %#x (glob_sta %#x)\n", u32Val, pThis->glob_sta));
+ pThis->glob_sta &= ~(u32Val & GS_WCLEAR_MASK);
+ pThis->glob_sta |= (u32Val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
+ LogFlowFunc(("glob_sta <- %#x (glob_sta %#x)\n", u32Val, pThis->glob_sta));
break;
default:
- LogFunc(("Unimplemented: %#x <- %#x (DWord)\n", Port, u32Val));
+ LogFlowFunc(("U nabm writel %#x <- %#x\n", Port, u32Val));
break;
}
break;
@@ -2075,13 +1715,6 @@ static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser
AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cbVal, u32Val));
break;
}
-
- if (pStream)
- {
- int rc2 = RTCritSectLeave(&pStream->CritSect);
- AssertRC(rc2);
- }
-
return VINF_SUCCESS;
}
@@ -2093,13 +1726,11 @@ static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser,
RT_NOREF(pDevIns);
PAC97STATE pThis = (PAC97STATE)pvUser;
- int rc = VINF_SUCCESS;
-
switch (cbVal)
{
case 1:
{
- Log3Func(("U nam readb %#x\n", Port));
+ LogFlowFunc(("U nam readb %#x\n", Port));
pThis->cas = 0;
*pu32Val = UINT32_MAX;
break;
@@ -2114,7 +1745,7 @@ static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser,
{
default:
*pu32Val = ichac97MixerGet(pThis, index);
- Log3Func(("nam readw %#x -> %#x\n", Port, *pu32Val));
+ LogFlowFunc(("nam readw %#x -> %#x\n", Port, *pu32Val));
break;
}
break;
@@ -2122,26 +1753,23 @@ static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser,
case 4:
{
- Log3Func(("U nam readl %#x\n", Port));
+ LogFlowFunc(("U nam readl %#x\n", Port));
pThis->cas = 0;
*pu32Val = UINT32_MAX;
break;
}
default:
- {
- AssertFailed();
- rc = VERR_IOM_IOPORT_UNUSED;
- }
+ return VERR_IOM_IOPORT_UNUSED;
}
-
- return rc;
+ return VINF_SUCCESS;
}
/**
* @callback_method_impl{FNIOMIOPORTOUT}
*/
-static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32Val, unsigned cbVal)
+static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns,
+ void *pvUser, RTIOPORT Port, uint32_t u32Val, unsigned cbVal)
{
RT_NOREF(pDevIns);
PAC97STATE pThis = (PAC97STATE)pvUser;
@@ -2150,7 +1778,7 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
{
case 1:
{
- Log3Func(("U nam writeb %#x <- %#x\n", Port, u32Val));
+ LogFlowFunc(("U nam writeb %#x <- %#x\n", Port, u32Val));
pThis->cas = 0;
break;
}
@@ -2170,25 +1798,19 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
ichac97MixerSet(pThis, index, u32Val);
break;
case AC97_Master_Volume_Mute:
- if (pThis->uCodecModel == AC97_CODEC_AD1980)
- {
- if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_LOSEL)
- break; /* Register controls surround (rear), do nothing. */
- }
- ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32Val);
+ if (pThis->uCodecModel == Codec_AD1980)
+ if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_LOSEL)
+ break; /* Register controls surround (rear), do nothing. */
+ ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
break;
case AC97_Headphone_Volume_Mute:
- if (pThis->uCodecModel == AC97_CODEC_AD1980)
- {
- if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
- {
+ if (pThis->uCodecModel == Codec_AD1980)
+ if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_HPSEL)
/* Register controls PCM (front) outputs. */
- ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME_MASTER, u32Val);
- }
- }
+ ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
break;
case AC97_PCM_Out_Volume_Mute:
- ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_FRONT, u32Val);
+ ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_PCM, u32Val);
break;
case AC97_Line_In_Volume_Mute:
ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_LINE_IN, u32Val);
@@ -2198,60 +1820,60 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
break;
case AC97_Vendor_ID1:
case AC97_Vendor_ID2:
- LogFunc(("Attempt to write vendor ID to %#x\n", u32Val));
+ LogFlowFunc(("Attempt to write vendor ID to %#x\n", u32Val));
break;
case AC97_Extended_Audio_ID:
- LogFunc(("Attempt to write extended audio ID to %#x\n", u32Val));
+ LogFlowFunc(("Attempt to write extended audio ID to %#x\n", u32Val));
break;
case AC97_Extended_Audio_Ctrl_Stat:
- if (!(u32Val & AC97_EACS_VRA))
+ if (!(u32Val & EACS_VRA))
{
ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 48000);
- ichac97StreamReOpen(pThis, &pThis->StreamOut);
+ ichac97StreamReInit(pThis, &pThis->StrmStOut);
ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate, 48000);
- ichac97StreamReOpen(pThis, &pThis->StreamLineIn);
+ ichac97StreamReInit(pThis, &pThis->StrmStLineIn);
}
- if (!(u32Val & AC97_EACS_VRM))
+ if (!(u32Val & EACS_VRM))
{
ichac97MixerSet(pThis, AC97_MIC_ADC_Rate, 48000);
- ichac97StreamReOpen(pThis, &pThis->StreamMicIn);
+ ichac97StreamReInit(pThis, &pThis->StrmStMicIn);
}
- LogFunc(("Setting extended audio control to %#x\n", u32Val));
+ LogFlowFunc(("Setting extended audio control to %#x\n", u32Val));
ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32Val);
break;
case AC97_PCM_Front_DAC_Rate:
- if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
+ if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
{
ichac97MixerSet(pThis, index, u32Val);
- LogFunc(("Set front DAC rate to %RU32\n", u32Val));
- ichac97StreamReOpen(pThis, &pThis->StreamOut);
+ LogFlowFunc(("Set front DAC rate to %RU32\n", u32Val));
+ ichac97StreamReInit(pThis, &pThis->StrmStOut);
}
else
- AssertMsgFailed(("Attempt to set front DAC rate to %RU32, but VRA is not set\n", u32Val));
+ LogFlowFunc(("Attempt to set front DAC rate to %RU32, but VRA is not set\n", u32Val));
break;
case AC97_MIC_ADC_Rate:
- if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRM)
+ if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM)
{
ichac97MixerSet(pThis, index, u32Val);
- LogFunc(("Set MIC ADC rate to %RU32\n", u32Val));
- ichac97StreamReOpen(pThis, &pThis->StreamMicIn);
+ LogFlowFunc(("Set MIC ADC rate to %RU32\n", u32Val));
+ ichac97StreamReInit(pThis, &pThis->StrmStMicIn);
}
else
- AssertMsgFailed(("Attempt to set MIC ADC rate to %RU32, but VRM is not set\n", u32Val));
+ LogFlowFunc(("Attempt to set MIC ADC rate to %RU32, but VRM is not set\n", u32Val));
break;
case AC97_PCM_LR_ADC_Rate:
- if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & AC97_EACS_VRA)
+ if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
{
ichac97MixerSet(pThis, index, u32Val);
- LogFunc(("Set front LR ADC rate to %RU32\n", u32Val));
- ichac97StreamReOpen(pThis, &pThis->StreamLineIn);
+ LogFlowFunc(("Set front LR ADC rate to %RU32\n", u32Val));
+ ichac97StreamReInit(pThis, &pThis->StrmStLineIn);
}
else
- AssertMsgFailed(("Attempt to set LR ADC rate to %RU32, but VRA is not set\n", u32Val));
+ LogFlowFunc(("Attempt to set LR ADC rate to %RU32, but VRA is not set\n", u32Val));
break;
default:
- LogFunc(("U nam writew %#x <- %#x\n", Port, u32Val));
+ LogFlowFunc(("U nam writew %#x <- %#x\n", Port, u32Val));
ichac97MixerSet(pThis, index, u32Val);
break;
}
@@ -2260,7 +1882,7 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
case 4:
{
- Log3Func(("U nam writel %#x <- %#x\n", Port, u32Val));
+ LogFlowFunc(("U nam writel %#x <- %#x\n", Port, u32Val));
pThis->cas = 0;
break;
}
@@ -2280,7 +1902,7 @@ static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns, void *pvUser,
static DECLCALLBACK(int) ichac97IOPortMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
{
- RT_NOREF(cb, enmType);
+ RT_NOREF(enmType, cb);
PAC97STATE pThis = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
RTIOPORT Port = (RTIOPORT)GCPhysAddress;
@@ -2310,20 +1932,20 @@ DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID)
{
switch (uID)
{
- case AC97SOUNDSOURCE_PI_INDEX: return &pThis->StreamLineIn;
- case AC97SOUNDSOURCE_MC_INDEX: return &pThis->StreamMicIn;
- case AC97SOUNDSOURCE_PO_INDEX: return &pThis->StreamOut;
- default: break;
+ case PI_INDEX: return &pThis->StrmStLineIn;
+ case MC_INDEX: return &pThis->StrmStMicIn;
+ case PO_INDEX: return &pThis->StrmStOut;
+ default: break;
}
return NULL;
}
#ifdef IN_RING3
-static int ichac97SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
+static int ichac97SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStrmSt)
{
RT_NOREF(pDevIns);
- PAC97BMREGS pRegs = &pStream->Regs;
+ PAC97BMREGS pRegs = &pStrmSt->Regs;
SSMR3PutU32(pSSM, pRegs->bdbar);
SSMR3PutU8( pSSM, pRegs->civ);
@@ -2346,39 +1968,42 @@ static DECLCALLBACK(int) ichac97SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
{
PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
- LogFlowFuncEnter();
-
SSMR3PutU32(pSSM, pThis->glob_cnt);
SSMR3PutU32(pSSM, pThis->glob_sta);
SSMR3PutU32(pSSM, pThis->cas);
/** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
/* Note: The order the streams are saved here is critical, so don't touch. */
- int rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamLineIn);
+ int rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStLineIn);
AssertRC(rc2);
- rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamOut);
+ rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStOut);
AssertRC(rc2);
- rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StreamMicIn);
+ rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStMicIn);
AssertRC(rc2);
SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
- uint8_t active[AC97SOUNDSOURCE_LAST_INDEX];
+ uint8_t active[LAST_INDEX];
- active[AC97SOUNDSOURCE_PI_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamLineIn) ? 1 : 0;
- active[AC97SOUNDSOURCE_PO_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamOut) ? 1 : 0;
- active[AC97SOUNDSOURCE_MC_INDEX] = ichac97StreamIsEnabled(pThis, &pThis->StreamMicIn) ? 1 : 0;
+ PAC97DRIVER pDrv;
+ RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+ {
+ PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
+ AssertPtr(pCon);
+ active[PI_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->LineIn.pStrmIn) ? 1 : 0;
+ active[PO_INDEX] = pCon->pfnIsActiveOut(pCon, pDrv->Out.pStrmOut) ? 1 : 0;
+ active[MC_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->MicIn.pStrmIn) ? 1 : 0;
+ }
SSMR3PutMem(pSSM, active, sizeof(active));
- LogFlowFuncLeaveRC(VINF_SUCCESS);
return VINF_SUCCESS;
}
-static int ichac97LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStream)
+static int ichac97LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStrmSt)
{
RT_NOREF(pDevIns);
- PAC97BMREGS pRegs = &pStream->Regs;
+ PAC97BMREGS pRegs = &pStrmSt->Regs;
SSMR3GetU32(pSSM, &pRegs->bdbar);
SSMR3GetU8( pSSM, &pRegs->civ);
@@ -2401,8 +2026,6 @@ static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, ui
{
PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
- LogRel2(("ichac97LoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
-
AssertMsgReturn (uVersion == AC97_SSM_VERSION, ("%RU32\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
@@ -2412,43 +2035,47 @@ static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, ui
/** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
/* Note: The order the streams are loaded here is critical, so don't touch. */
- int rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamLineIn);
+ int rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStLineIn);
AssertRC(rc2);
- rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamOut);
+ rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStOut);
AssertRC(rc2);
- rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StreamMicIn);
+ rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStMicIn);
AssertRC(rc2);
SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
/** @todo r=andy Stream IDs are hardcoded to certain streams. */
- uint8_t uaStrmsActive[AC97SOUNDSOURCE_LAST_INDEX];
+ uint8_t uaStrmsActive[LAST_INDEX];
SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive));
ichac97RecordSelect(pThis, ichac97MixerGet(pThis, AC97_Record_Select));
# define V_(a, b) ichac97MixerSetVolume(pThis, a, b, ichac97MixerGet(pThis, a))
- V_(AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER);
- V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_FRONT);
+ V_(AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME);
+ V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM);
V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
- V_(AC97_Mic_Volume_Mute, PDMAUDIOMIXERCTL_MIC_IN);
# undef V_
- if (pThis->uCodecModel == AC97_CODEC_AD1980)
- if (ichac97MixerGet(pThis, AC97_AD_Misc) & AC97_AD_MISC_HPSEL)
- ichac97MixerSetVolume(pThis, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME_MASTER,
+ if (pThis->uCodecModel == Codec_AD1980)
+ if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_HPSEL)
+ ichac97MixerSetVolume(pThis, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME,
ichac97MixerGet(pThis, AC97_Headphone_Volume_Mute));
- rc2 = ichac97StreamsInit(pThis);
- if (RT_SUCCESS(rc2))
- {
- /** @todo r=andy Stream IDs are hardcoded to certain streams. */
- rc2 = ichac97StreamEnable(pThis, &pThis->StreamLineIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PI_INDEX]));
- if (RT_SUCCESS(rc2))
- rc2 = ichac97StreamEnable(pThis, &pThis->StreamMicIn, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_MC_INDEX]));
- if (RT_SUCCESS(rc2))
- rc2 = ichac97StreamEnable(pThis, &pThis->StreamOut, RT_BOOL(uaStrmsActive[AC97SOUNDSOURCE_PO_INDEX]));
- }
+ int rc;
+ rc = ichac97StreamInit(pThis, &pThis->StrmStLineIn, PI_INDEX);
+ AssertRC(rc);
+ rc = ichac97StreamInit(pThis, &pThis->StrmStMicIn, MC_INDEX);
+ AssertRC(rc);
+ rc = ichac97StreamInit(pThis, &pThis->StrmStOut, PO_INDEX);
+ AssertRC(rc);
- pThis->bup_flag = 0;
+ /** @todo r=andy Stream IDs are hardcoded to certain streams. */
+ rc = ichac97StreamSetActive(pThis, &pThis->StrmStLineIn, RT_BOOL(uaStrmsActive[PI_INDEX]));
+ AssertRC(rc);
+ rc = ichac97StreamSetActive(pThis, &pThis->StrmStMicIn, RT_BOOL(uaStrmsActive[MC_INDEX]));
+ AssertRC(rc);
+ rc = ichac97StreamSetActive(pThis, &pThis->StrmStOut, RT_BOOL(uaStrmsActive[PO_INDEX]));
+ AssertRC(rc);
+
+ pThis->bup_flag = 0;
pThis->last_samp = 0;
return VINF_SUCCESS;
@@ -2469,30 +2096,6 @@ static DECLCALLBACK(void *) ichac97QueryInterface(struct PDMIBASE *pInterface, c
/**
- * Powers off the device.
- *
- * @param pDevIns Device instance to power off.
- */
-static DECLCALLBACK(void) ichac97PowerOff(PPDMDEVINS pDevIns)
-{
- PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
-
- LogRel2(("AC97: Powering off ...\n"));
-
- /**
- * Note: Destroy the mixer while powering off and *not* in ichac97Destruct,
- * giving the mixer the chance to release any references held to
- * PDM audio streams it maintains.
- */
- if (pThis->pMixer)
- {
- AudioMixerDestroy(pThis->pMixer);
- pThis->pMixer = NULL;
- }
-}
-
-
-/**
* @interface_method_impl{PDMDEVREG,pfnReset}
*
* @remarks The original sources didn't install a reset handler, but it seems to
@@ -2507,9 +2110,9 @@ static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
/*
* Reset the device state (will need pDrv later).
*/
- ichac97StreamResetBMRegs(pThis, &pThis->StreamLineIn);
- ichac97StreamResetBMRegs(pThis, &pThis->StreamMicIn);
- ichac97StreamResetBMRegs(pThis, &pThis->StreamOut);
+ ichac97StreamResetBMRegs(pThis, &pThis->StrmStLineIn);
+ ichac97StreamResetBMRegs(pThis, &pThis->StrmStMicIn);
+ ichac97StreamResetBMRegs(pThis, &pThis->StrmStOut);
/*
* Reset the mixer too. The Windows XP driver seems to rely on
@@ -2519,11 +2122,25 @@ static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
ichac97MixerReset(pThis);
/*
+ * Stop any audio currently playing.
+ */
+ PAC97DRIVER pDrv;
+ RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
+ {
+ pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, false /* Disable */);
+ /* Ignore rc. */
+ pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, false /* Disable */);
+ /* Ditto. */
+ pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, false /* Disable */);
+ /* Ditto. */
+ }
+
+ /*
* Reset all streams.
*/
- ichac97StreamReset(pThis, &pThis->StreamLineIn);
- ichac97StreamReset(pThis, &pThis->StreamMicIn);
- ichac97StreamReset(pThis, &pThis->StreamOut);
+ ichac97StreamReset(pThis, &pThis->StrmStLineIn);
+ ichac97StreamReset(pThis, &pThis->StrmStMicIn);
+ ichac97StreamReset(pThis, &pThis->StrmStOut);
LogRel(("AC97: Reset\n"));
}
@@ -2534,33 +2151,35 @@ static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
*/
static DECLCALLBACK(int) ichac97Destruct(PPDMDEVINS pDevIns)
{
+ PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
LogFlowFuncEnter();
- ichac97StreamDestroy(&pThis->StreamLineIn);
- ichac97StreamDestroy(&pThis->StreamMicIn);
- ichac97StreamDestroy(&pThis->StreamOut);
-
- PAC97DRIVER pDrv, pDrvNext;
- RTListForEachSafe(&pThis->lstDrv, pDrv, pDrvNext, AC97DRIVER, Node)
+ PAC97DRIVER pDrv;
+ while (!RTListIsEmpty(&pThis->lstDrv))
{
+ pDrv = RTListGetFirst(&pThis->lstDrv, AC97DRIVER, Node);
+
RTListNodeRemove(&pDrv->Node);
RTMemFree(pDrv);
}
- /* Sanity. */
- Assert(RTListIsEmpty(&pThis->lstDrv));
+ if (pThis->pMixer)
+ {
+ AudioMixerDestroy(pThis->pMixer);
+ pThis->pMixer = NULL;
+ }
- int rc;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- rc = RTCritSectDelete(&pThis->csTimer);
-#else
- rc = VINF_SUCCESS;
-#endif
+ if (pThis->pvReadWriteBuf)
+ {
+ RTMemFree(pThis->pvReadWriteBuf);
+ pThis->pvReadWriteBuf = NULL;
+ pThis->cbReadWriteBuf = 0;
+ }
- LogFlowFuncLeaveRC(rc);
- return rc;
+ LogFlowFuncLeave();
+ return VINF_SUCCESS;
}
@@ -2613,7 +2232,7 @@ static DECLCALLBACK(int) ichac97AttachInternal(PPDMDEVINS pDevIns, PAC97DRIVER p
* host backend. This might change in the future.
*/
if (pDrv->uLUN == 0)
- pDrv->Flags |= PDMAUDIODRVFLAGS_PRIMARY;
+ pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
@@ -2698,7 +2317,7 @@ static int ichac97Reattach(PAC97STATE pThis, PAC97DRIVER pDrv, uint8_t uLUN, con
#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
- int rc;
+ int rc = VINF_SUCCESS;
do
{
PCFGMNODE pLunL0;
@@ -2731,13 +2350,14 @@ static int ichac97Reattach(PAC97STATE pThis, PAC97DRIVER pDrv, uint8_t uLUN, con
static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
{
RT_NOREF(iInstance);
+ PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+
PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
/* NB: This must be done *before* any possible failure (and running the destructor). */
RTListInit(&pThis->lstDrv);
Assert(iInstance == 0);
- PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
/*
* Validations.
@@ -2759,7 +2379,7 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
#ifndef VBOX_WITH_AUDIO_CALLBACKS
uint16_t uTimerHz;
- rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, AC97_TIMER_HZ /* Default value, if not set. */);
+ rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("AC'97 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
@@ -2771,11 +2391,11 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
* 48 kHz rate, which is exactly what we need. Same goes for AD1981B.
*/
if (!strcmp(szCodec, "STAC9700"))
- pThis->uCodecModel = AC97_CODEC_STAC9700;
+ pThis->uCodecModel = Codec_STAC9700;
else if (!strcmp(szCodec, "AD1980"))
- pThis->uCodecModel = AC97_CODEC_AD1980;
+ pThis->uCodecModel = Codec_AD1980;
else if (!strcmp(szCodec, "AD1981B"))
- pThis->uCodecModel = AC97_CODEC_AD1981B;
+ pThis->uCodecModel = Codec_AD1981B;
else
{
return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
@@ -2807,12 +2427,12 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */ Assert(pThis->PciDev.abConfig[0x3c] == 0x00);
PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */ Assert(pThis->PciDev.abConfig[0x3d] == 0x01);
- if (pThis->uCodecModel == AC97_CODEC_AD1980)
+ if (pThis->uCodecModel == Codec_AD1980)
{
PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
PCIDevSetSubSystemId (&pThis->PciDev, 0x0177); /* 2e ro. */
}
- else if (pThis->uCodecModel == AC97_CODEC_AD1981B)
+ else if (pThis->uCodecModel == Codec_AD1981B)
{
PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
PCIDevSetSubSystemId (&pThis->PciDev, 0x01ad); /* 2e ro. */
@@ -2875,15 +2495,25 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
rc = AudioMixerCreate("AC'97 Mixer", 0 /* uFlags */, &pThis->pMixer);
if (RT_SUCCESS(rc))
{
+ /* Set a default audio format for our mixer. */
+ PDMAUDIOSTREAMCFG streamCfg;
+ streamCfg.uHz = 44100;
+ streamCfg.cChannels = 2;
+ streamCfg.enmFormat = AUD_FMT_S16;
+ streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+ rc = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
+ AssertRC(rc);
+
/* Add all required audio sinks. */
- int rc2 = AudioMixerCreateSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOut);
- AssertRC(rc2);
+ rc = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
+ AssertRC(rc);
- rc2 = AudioMixerCreateSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
- AssertRC(rc2);
+ rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
+ AssertRC(rc);
- rc2 = AudioMixerCreateSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
- AssertRC(rc2);
+ rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
+ AssertRC(rc);
}
}
@@ -2891,7 +2521,15 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
if (RT_SUCCESS(rc))
{
- ichac97StreamsInit(pThis);
+ rc = ichac97StreamInit(pThis, &pThis->StrmStLineIn, PI_INDEX);
+ if (RT_FAILURE(rc))
+ return rc;
+ rc = ichac97StreamInit(pThis, &pThis->StrmStMicIn, MC_INDEX);
+ if (RT_FAILURE(rc))
+ return rc;
+ rc = ichac97StreamInit(pThis, &pThis->StrmStOut, PO_INDEX);
+ if (RT_FAILURE(rc))
+ return rc;
PAC97DRIVER pDrv;
RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
@@ -2900,15 +2538,15 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
* Only primary drivers are critical for the VM to run. Everything else
* might not worth showing an own error message box in the GUI.
*/
- if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
+ if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
continue;
PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
AssertPtr(pCon);
- bool fValidLineIn = AudioMixerStreamIsValid(pDrv->LineIn.pMixStrm);
- bool fValidMicIn = AudioMixerStreamIsValid(pDrv->MicIn.pMixStrm);
- bool fValidOut = AudioMixerStreamIsValid(pDrv->Out.pMixStrm);
+ bool fValidLineIn = pCon->pfnIsValidIn(pCon, pDrv->LineIn.pStrmIn);
+ bool fValidMicIn = pCon->pfnIsValidIn (pCon, pDrv->MicIn.pStrmIn);
+ bool fValidOut = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
if ( !fValidLineIn
&& !fValidMicIn
@@ -2916,14 +2554,9 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
{
LogRel(("AC97: Falling back to NULL backend (no sound audible)\n"));
- /* Destroy the streams before re-attaching the NULL driver. */
- ichac97StreamsDestroy(pThis);
-
ichac97Reset(pDevIns);
ichac97Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
- ichac97StreamsInit(pThis);
-
PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
N_("No audio devices could be opened. Selecting the NULL audio backend "
"with the consequence that no sound is audible"));
@@ -2933,38 +2566,36 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
bool fWarn = false;
PDMAUDIOBACKENDCFG backendCfg;
- int rc2 = pCon->pfnGetConfig(pCon, &backendCfg);
+ int rc2 = pCon->pfnGetConfiguration(pCon, &backendCfg);
if (RT_SUCCESS(rc2))
{
- if (backendCfg.cSources)
+ if (backendCfg.cMaxHstStrmsIn)
{
/* If the audio backend supports two or more input streams at once,
* warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
- if (backendCfg.cMaxStreamsIn >= 2)
+ if (backendCfg.cMaxHstStrmsIn >= 2)
fWarn = !fValidLineIn || !fValidMicIn;
/* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
* *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
* One of the two simply is not in use then. */
- else if (backendCfg.cMaxStreamsIn == 1)
+ else if (backendCfg.cMaxHstStrmsIn == 1)
fWarn = !fValidLineIn && !fValidMicIn;
/* Don't warn if our backend is not able of supporting any input streams at all. */
}
if ( !fWarn
- && backendCfg.cSinks)
+ && backendCfg.cMaxHstStrmsOut)
{
fWarn = !fValidOut;
}
}
else
- {
- LogRel(("AC97: Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n", pDrv->uLUN, rc2));
- fWarn = true;
- }
+ AssertReleaseMsgFailed(("Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n",
+ pDrv->uLUN, rc2));
if (fWarn)
{
- char szMissingStreams[255] = "";
+ char szMissingStreams[255];
size_t len = 0;
if (!fValidLineIn)
{
@@ -2994,23 +2625,30 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
}
}
+ if (RT_SUCCESS(rc))
+ {
+ pThis->cbReadWriteBuf = _4K; /** @todo Make this configurable. */
+ pThis->pvReadWriteBuf = (uint8_t *)RTMemAllocZ(pThis->cbReadWriteBuf);
+ if (!pThis->pvReadWriteBuf)
+ rc = VERR_NO_MEMORY;
+ }
+
# ifndef VBOX_WITH_AUDIO_CALLBACKS
if (RT_SUCCESS(rc))
{
- rc = RTCritSectInit(&pThis->csTimer);
+ /* Start the emulation timer. */
+ rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
+ TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
+ AssertRCReturn(rc, rc);
+
if (RT_SUCCESS(rc))
{
- /* Start the emulation timer. */
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
- TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
- AssertRCReturn(rc, rc);
+ pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
+ pThis->uTimerTS = TMTimerGet(pThis->pTimer);
+ LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
- if (RT_SUCCESS(rc))
- {
- pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
- pThis->uTimerTS = TMTimerGet(pThis->pTimer);
- LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
- }
+ /* Fire off timer. */
+ TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
}
}
# else
@@ -3021,7 +2659,7 @@ static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCF
{
/* Only register primary driver.
* The device emulation does the output multiplexing then. */
- if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
+ if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
continue;
PDMAUDIOCALLBACK AudioCallbacks[2];
@@ -3109,7 +2747,7 @@ const PDMDEVREG g_DeviceICHAC97 =
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
- ichac97PowerOff,
+ NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
diff --git a/src/VBox/Devices/Audio_50/DevIchHdaCodec.h b/src/VBox/Devices/Audio/DevIchHdaCodec.h
similarity index 100%
rename from src/VBox/Devices/Audio_50/DevIchHdaCodec.h
rename to src/VBox/Devices/Audio/DevIchHdaCodec.h
diff --git a/src/VBox/Devices/Audio/DevSB16.cpp b/src/VBox/Devices/Audio/DevSB16.cpp
index 0e1fe32..81d0026 100644
--- a/src/VBox/Devices/Audio/DevSB16.cpp
+++ b/src/VBox/Devices/Audio/DevSB16.cpp
@@ -1,6 +1,8 @@
/* $Id: DevSB16.cpp $ */
/** @file
* DevSB16 - VBox SB16 Audio Controller.
+ *
+ * @todo hiccups on NT4 and Win98.
*/
/*
@@ -41,7 +43,6 @@
#define LOG_GROUP LOG_GROUP_DEV_SB16
#include <VBox/log.h>
#include <iprt/assert.h>
-#include <iprt/file.h>
#ifdef IN_RING3
# include <iprt/mem.h>
# include <iprt/string.h>
@@ -57,20 +58,6 @@
#include "AudioMixer.h"
#include "DrvAudio.h"
-#if 0
-/*
- * SB16_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
- * to a file on the host. Be sure to adjust SB16_DEBUG_DUMP_PCM_DATA_PATH
- * to your needs before using this!
- */
-# define SB16_DEBUG_DUMP_PCM_DATA
-# ifdef RT_OS_WINDOWS
-# define SB16_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
-# else
-# define SB16_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
-# endif
-#endif
-
/** Current saved state version. */
#define SB16_SAVE_STATE_VERSION 2
/** The version used in VirtualBox version 3.0 and earlier. This didn't include the config dump. */
@@ -89,7 +76,9 @@ static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
typedef struct SB16OUTPUTSTREAM
{
/** PCM output stream. */
- R3PTRTYPE(PPDMAUDIOSTREAM) pStream;
+ R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
+ /** Mixer handle for output stream. */
+ R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
} SB16OUTPUTSTREAM, *PSB16OUTPUTSTREAM;
/**
@@ -179,14 +168,13 @@ typedef struct SB16STATE
int align;
RTLISTANCHOR lstDrv;
- /** Number of active (running) SDn streams. */
- uint8_t cStreamsActive;
+ /** The device' software mixer. */
+ R3PTRTYPE(PAUDIOMIXER) pMixer;
+ /** Audio sink for PCM output. */
+ R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
#ifndef VBOX_WITH_AUDIO_CALLBACKS
/** The timer for pumping data thru the attached LUN drivers. */
PTMTIMERR3 pTimerIO;
- /** Flag indicating whether the timer is active or not. */
- bool fTimerActive;
- uint8_t u8Padding1[7];
/** The timer interval for pumping data thru the LUN drivers in timer ticks. */
uint64_t cTimerTicksIO;
/** Timestamp of the last timer callback (sb16TimerIO).
@@ -203,11 +191,6 @@ typedef struct SB16STATE
} SB16STATE, *PSB16STATE;
static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
-static void sb16CloseOut(PSB16STATE pThis);
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
-static void sb16TimerMaybeStart(PSB16STATE pThis);
-static void sb16TimerMaybeStop(PSB16STATE pThis);
-#endif
/**
* Attach command, internal version.
@@ -224,7 +207,7 @@ static void sb16TimerMaybeStop(PSB16STATE pThis);
* @param uLUN The logical unit which is being detached.
* @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
*/
-static int sb16AttachInternal(PPDMDEVINS pDevIns, PSB16DRIVER pDrv, unsigned uLUN, uint32_t fFlags)
+static DECLCALLBACK(int) sb16AttachInternal(PPDMDEVINS pDevIns, PSB16DRIVER pDrv, unsigned uLUN, uint32_t fFlags)
{
RT_NOREF(fFlags);
PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
@@ -258,7 +241,7 @@ static int sb16AttachInternal(PPDMDEVINS pDevIns, PSB16DRIVER pDrv, unsigned uLU
* host backend. This might change in the future.
*/
if (pDrv->uLUN == 0)
- pDrv->Flags |= PDMAUDIODRVFLAGS_PRIMARY;
+ pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
@@ -374,7 +357,6 @@ static int sb16Reattach(PSB16STATE pThis, PSB16DRIVER pDrv, uint8_t uLUN, const
return rc;
}
-
static int magic_of_irq(int irq)
{
switch (irq)
@@ -415,8 +397,8 @@ static int irq_of_magic(int magic)
return -1;
}
-#if 0 // unused // def DEBUG
-DECLINLINE(void) log_dsp(PSB16STATE pThis)
+#if 0 // unused
+static inline void log_dsp(PSB16STATE pThis)
{
LogFlowFunc(("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
pThis->fmt_stereo ? "Stereo" : "Mono",
@@ -443,34 +425,21 @@ static void sb16Control(PSB16STATE pThis, int hold)
LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma));
- PDMDevHlpDMASetDREQ(pThis->pDevInsR3, dma, hold);
-
+ PSB16DRIVER pDrv;
if (hold)
{
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- pThis->cStreamsActive++;
- sb16TimerMaybeStart(pThis);
-#endif
- PDMDevHlpDMASchedule(pThis->pDevInsR3);
+ PDMDevHlpDMASetDREQ (pThis->pDevInsR3, dma, 1);
+ PDMDevHlpDMASchedule (pThis->pDevInsR3);
+ RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+ pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
+ pDrv->Out.pStrmOut, true /* fEnable */);
}
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
else
{
- if (pThis->cStreamsActive)
- pThis->cStreamsActive--;
- sb16TimerMaybeStop(pThis);
- }
-#endif
-
- PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- if (!pDrv->Out.pStream)
- continue;
-
- int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream,
- hold == 1 ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
- LogFlowFunc(("%s: rc=%Rrc\n", pDrv->Out.pStream->szName, rc2)); NOREF(rc2);
+ PDMDevHlpDMASetDREQ (pThis->pDevInsR3, dma, 0);
+ RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+ pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
+ pDrv->Out.pStrmOut, false /* fEnable */);
}
}
@@ -490,13 +459,10 @@ static void continue_dma8(PSB16STATE pThis)
if (pThis->freq > 0)
{
PDMAUDIOSTREAMCFG streamCfg;
- RT_ZERO(streamCfg);
- streamCfg.enmDir = PDMAUDIODIR_OUT;
- streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
- streamCfg.uHz = pThis->freq;
- streamCfg.cChannels = 1 << pThis->fmt_stereo;
- streamCfg.enmFormat = pThis->fmt;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+ streamCfg.uHz = pThis->freq;
+ streamCfg.cChannels = 1 << pThis->fmt_stereo;
+ streamCfg.enmFormat = pThis->fmt;
+ streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
int rc = sb16OpenOut(pThis, &streamCfg);
AssertRC(rc);
@@ -507,7 +473,7 @@ static void continue_dma8(PSB16STATE pThis)
static void dma_cmd8(PSB16STATE pThis, int mask, int dma_len)
{
- pThis->fmt = PDMAUDIOFMT_U8;
+ pThis->fmt = AUD_FMT_U8;
pThis->use_hdma = 0;
pThis->fmt_bits = 8;
pThis->fmt_signed = 0;
@@ -610,9 +576,9 @@ static void dma_cmd(PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
if (16 == pThis->fmt_bits)
- pThis->fmt = pThis->fmt_signed ? PDMAUDIOFMT_S16 : PDMAUDIOFMT_U16;
+ pThis->fmt = pThis->fmt_signed ? AUD_FMT_S16 : AUD_FMT_U16;
else
- pThis->fmt = pThis->fmt_signed ? PDMAUDIOFMT_S8 : PDMAUDIOFMT_U8;
+ pThis->fmt = pThis->fmt_signed ? AUD_FMT_S8 : AUD_FMT_U8;
pThis->left_till_irq = pThis->block_size;
@@ -628,13 +594,10 @@ static void dma_cmd(PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
if (pThis->freq)
{
PDMAUDIOSTREAMCFG streamCfg;
- RT_ZERO(streamCfg);
- streamCfg.enmDir = PDMAUDIODIR_OUT;
- streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
- streamCfg.uHz = pThis->freq;
- streamCfg.cChannels = 1 << pThis->fmt_stereo;
- streamCfg.enmFormat = pThis->fmt;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+ streamCfg.uHz = pThis->freq;
+ streamCfg.cChannels = 1 << pThis->fmt_stereo;
+ streamCfg.enmFormat = pThis->fmt;
+ streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
int rc = sb16OpenOut(pThis, &streamCfg);
AssertRC(rc);
@@ -1122,15 +1085,8 @@ static void sb16SetMasterVolume(PSB16STATE pThis)
/* There's no mute switch, only volume controls. */
uint8_t lvol = sb16MixRegToVol(pThis, 0x30);
uint8_t rvol = sb16MixRegToVol(pThis, 0x31);
-
- PDMAUDIOVOLUME Vol = { false /* fMute */, lvol, rvol };
-
- PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnStreamSetVolume(pDrv->pConnector, pDrv->Out.pStream, &Vol);
- AssertRC(rc2);
- }
+ PDMAUDIOVOLUME vol = { false, lvol, rvol };
+ AudioMixerSetMasterVolume(pThis->pMixer, &vol);
}
static void sb16SetPcmOutVolume(PSB16STATE pThis)
@@ -1138,36 +1094,22 @@ static void sb16SetPcmOutVolume(PSB16STATE pThis)
/* There's no mute switch, only volume controls. */
uint8_t lvol = sb16MixRegToVol(pThis, 0x32);
uint8_t rvol = sb16MixRegToVol(pThis, 0x33);
-
- PDMAUDIOVOLUME Vol = { false /* fMute */, lvol, rvol };
-
- PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnStreamSetVolume(pDrv->pConnector, pDrv->Out.pStream, &Vol);
- AssertRC(rc2);
- }
+ PDMAUDIOVOLUME vol = { false, lvol, rvol };
+ AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
}
static void sb16ResetLegacy(PSB16STATE pThis)
{
- LogFlowFuncEnter();
-
- sb16CloseOut(pThis);
-
pThis->freq = 11025;
pThis->fmt_signed = 0;
pThis->fmt_bits = 8;
pThis->fmt_stereo = 0;
PDMAUDIOSTREAMCFG streamCfg;
- RT_ZERO(streamCfg);
- streamCfg.enmDir = PDMAUDIODIR_OUT;
- streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
- streamCfg.uHz = pThis->freq;
- streamCfg.cChannels = 1; /* Mono */
- streamCfg.enmFormat = PDMAUDIOFMT_U8;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+ streamCfg.uHz = pThis->freq;
+ streamCfg.cChannels = 1; /* Mono */
+ streamCfg.enmFormat = AUD_FMT_U8;
+ streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
int rc2 = sb16OpenOut(pThis, &streamCfg);
AssertRC(rc2);
@@ -1196,14 +1138,13 @@ static void sb16Reset(PSB16STATE pThis)
dsp_out_data(pThis, 0xaa);
sb16SpeakerControl(pThis, 0);
-
sb16Control(pThis, 0);
sb16ResetLegacy(pThis);
}
static IO_WRITE_PROTO(dsp_write)
{
- RT_NOREF(pDevIns, cb);
+ RT_NOREF(cb);
PSB16STATE pThis = (PSB16STATE)opaque;
int iport = nport - pThis->port;
@@ -1220,7 +1161,7 @@ static IO_WRITE_PROTO(dsp_write)
if (0 && pThis->highspeed)
{
pThis->highspeed = 0;
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
+ PDMDevHlpISASetIrq(pDevIns, pThis->irq, 0);
sb16Control(pThis, 0);
}
else
@@ -1376,6 +1317,19 @@ static IO_READ_PROTO(dsp_read)
static void sb16MixerReset(PSB16STATE pThis)
{
+ PSB16DRIVER pDrv;
+
+ RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+ pDrv->Out.phStrmOut = NULL;
+
+ pThis->pSinkOutput = NULL;
+
+ if (pThis->pMixer)
+ {
+ AudioMixerDestroy(pThis->pMixer);
+ pThis->pMixer = NULL;
+ }
+
memset(pThis->mixer_regs, 0xff, 0x7f);
memset(pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
@@ -1405,6 +1359,25 @@ static void sb16MixerReset(PSB16STATE pThis)
for (int i = 0x44; i < 0x48; i++)
pThis->mixer_regs[i] = 0x80;
+ int rc2 = AudioMixerCreate("SB16 Mixer", 0 /* uFlags */, &pThis->pMixer);
+ if (RT_SUCCESS(rc2))
+ {
+ /* Set a default audio format for our mixer. */
+ PDMAUDIOSTREAMCFG streamCfg;
+ streamCfg.uHz = 44100;
+ streamCfg.cChannels = 2;
+ streamCfg.enmFormat = AUD_FMT_S16;
+ streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+ rc2 = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
+ AssertRC(rc2);
+
+ /* Add all required audio sinks. */
+ rc2 = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
+ AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
+ AssertRC(rc2);
+ }
+
/* Update the master (mixer) and PCM out volumes. */
sb16SetMasterVolume(pThis);
sb16SetPcmOutVolume(pThis);
@@ -1638,7 +1611,8 @@ static IO_READ_PROTO(mixer_read)
return VINF_SUCCESS;
}
-static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos, uint32_t dma_len, int len)
+static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos,
+ uint32_t dma_len, int len)
{
uint8_t tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
uint32_t cbToWrite = len;
@@ -1656,29 +1630,19 @@ static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos, uint32_
int rc = PDMDevHlpDMAReadMemory(pThis->pDevInsR3, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc));
-#ifdef SB16_DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- RTFileOpen(&fh, SB16_DEBUG_DUMP_PCM_DATA_PATH "sb16WriteAudio.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- RTFileWrite(fh, tmpbuf, cbToRead, NULL);
- RTFileClose(fh);
-#endif
- /*
- * Write data to the backends.
- */
- uint32_t cbWritten = 0;
+ uint32_t cbWritten;
+ /* Just multiplex the output to the connected backends.
+ * No need to utilize the virtual mixer here (yet). */
PSB16DRIVER pDrv;
RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
{
- int rc2 = pDrv->pConnector->pfnStreamWrite(pDrv->pConnector, pDrv->Out.pStream, tmpbuf, cbToRead, &cbWritten);
- if (RT_FAILURE(rc2))
- LogFlowFunc(("Failed writing to stream '%s': %Rrc\n", &pDrv->Out.pStream->szName, rc2));
+ int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
+ tmpbuf, cbToRead, &cbWritten);
+ RT_NOREF(rc2);
+ LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWritten=%RU32\n", pDrv->uLUN, rc2, cbWritten));
}
- LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbWritten=%RU32, cbLeft=%RU32, rc=%Rrc\n",
- cbToRead, cbToWrite, cbWritten, cbToWrite - cbWrittenTotal, rc));
-
Assert(cbToWrite >= cbToRead);
cbToWrite -= cbToRead;
dma_pos = (dma_pos + cbToRead) % dma_len;
@@ -1707,15 +1671,36 @@ static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsi
if (pThis->left_till_irq < 0)
pThis->left_till_irq = pThis->block_size;
- free = dma_len;
+ PSB16DRIVER pDrv;
- if (free <= 0)
- return dma_pos;
+ uint32_t cbOutMin = UINT32_MAX;
+ uint32_t cbOut;
+ RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+ {
+ int rc2 = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
+ NULL /* pcbIn */, &cbOut, NULL /* pcSamplesLive */);
+ if (RT_SUCCESS(rc2))
+ cbOutMin = RT_MIN(cbOutMin, cbOut);
+ }
+
+ LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
+ if (cbOutMin == UINT32_MAX)
+ {
+ free = dma_len;
+ }
+ else
+ {
+ free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
+ if ((free <= 0) || !dma_len)
+ return dma_pos;
+ }
copy = free;
till = pThis->left_till_irq;
- Log3Func(("pos %d/%d free %5d till %5d\n", dma_pos, dma_len, free, till));
+#ifdef DEBUG_SB16_MOST
+ LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
+#endif
if (copy >= till)
{
@@ -1737,7 +1722,7 @@ static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsi
if (pThis->left_till_irq <= 0)
{
pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
+ PDMDevHlpISASetIrq(pDevIns, pThis->irq, 1);
if (0 == pThis->dma_auto)
{
sb16Control(pThis, 0);
@@ -1745,9 +1730,11 @@ static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsi
}
}
- Log3Func(("pos %d/%d free %5d till %5d copy %5d written %5d block_size %5d\n",
- dma_pos, dma_len, free, pThis->left_till_irq, copy, written,
- pThis->block_size));
+#ifdef DEBUG_SB16_MOST
+ LogFlowFunc(("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
+ dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
+ pThis->block_size));
+#endif
while (pThis->left_till_irq <= 0)
pThis->left_till_irq += pThis->block_size;
@@ -1755,42 +1742,6 @@ static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsi
return dma_pos;
}
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
-
-static void sb16TimerMaybeStart(PSB16STATE pThis)
-{
- LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
-
- if (pThis->cStreamsActive == 0) /* Only start the timer if there are no active streams. */
- return;
-
- if (!pThis->pTimerIO)
- return;
-
- /* Set timer flag. */
- ASMAtomicXchgBool(&pThis->fTimerActive, true);
-
- /* Update current time timestamp. */
- pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
-
- /* Fire off timer. */
- TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
-}
-
-static void sb16TimerMaybeStop(PSB16STATE pThis)
-{
- LogFlowFunc(("cStreamsActive=%RU8\n", pThis->cStreamsActive));
-
- if (pThis->cStreamsActive) /* Some streams still active? Bail out. */
- return;
-
- if (!pThis->pTimerIO)
- return;
-
- /* Set timer flag. */
- ASMAtomicXchgBool(&pThis->fTimerActive, false);
-}
-
static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
{
RT_NOREF(pDevIns);
@@ -1798,100 +1749,101 @@ static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void
Assert(pThis == PDMINS_2_DATA(pDevIns, PSB16STATE));
AssertPtr(pThis);
+ uint32_t cbInMax = 0;
+ uint32_t cbOutMin = UINT32_MAX;
+
+ PSB16DRIVER pDrv;
+
uint64_t cTicksNow = TMTimerGet(pTimer);
- bool fIsPlaying = false; /* Whether one or more streams are still playing. */
- bool fDoTransfer = false;
+ uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTSIO;
+ uint64_t cTicksPerSec = TMTimerGetFreq(pTimer);
pThis->uTimerTSIO = cTicksNow;
- PSB16DRIVER pDrv;
+ /*
+ * Calculate the mixer's (fixed) sampling rate.
+ */
+ AssertPtr(pThis->pMixer);
+
+ PDMAUDIOSTREAMCFG mixerStrmCfg;
+ int rc = AudioMixerGetDeviceFormat(pThis->pMixer, &mixerStrmCfg);
+ AssertRC(rc);
+
+ PDMPCMPROPS mixerStrmProps;
+ rc = DrvAudioStreamCfgToProps(&mixerStrmCfg, &mixerStrmProps);
+ AssertRC(rc);
+
+ uint32_t cMixerSamplesMin = (int)((2 * cTicksElapsed * mixerStrmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
+ uint32_t cbMixerSamplesMin = cMixerSamplesMin << mixerStrmProps.cShift;
+
RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
{
- PPDMAUDIOSTREAM pStream = pDrv->Out.pStream;
- if (!pStream)
- continue;
+ uint32_t cbIn = 0;
+ uint32_t cbOut = 0;
-#ifdef DEBUG
- PSB16DRIVER pDrvPrev = RTListNodeGetPrev(&pDrv->Node, SB16DRIVER, Node);
- if ( pDrvPrev
- && !RTListNodeIsDummy(&pThis->lstDrv, pDrvPrev, SB16DRIVER, Node))
- {
- PPDMAUDIOSTREAM pStreamPrev = pDrvPrev->Out.pStream;
- AssertPtr(pStreamPrev);
+ rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
+ &cbIn, &cbOut, NULL /* cSamplesLive */);
+ if (RT_SUCCESS(rc))
+ rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* cSamplesPlayed */);
- /*
- * Sanity. Make sure that all streams have the same configuration
- * to get SB16's DMA transfers right.
- *
- * SB16 only allows one output configuration per serial data out,
- * so check if all streams have the same configuration.
- */
- AssertMsg(pStream->Cfg.uHz == pStreamPrev->Cfg.uHz,
- ("%RU32Hz vs. %RU32Hz\n", pStream->Cfg.uHz, pStreamPrev->Cfg.uHz));
- AssertMsg(pStream->Cfg.cChannels == pStreamPrev->Cfg.cChannels,
- ("%RU8 vs. %RU8 channels\n", pStream->Cfg.cChannels, pStreamPrev->Cfg.cChannels));
- AssertMsg(pStream->Cfg.enmFormat == pStreamPrev->Cfg.enmFormat,
- ("%d vs. %d format\n", pStream->Cfg.enmFormat, pStreamPrev->Cfg.enmFormat));
- }
+#ifdef DEBUG_TIMER
+ LogFlowFunc(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
#endif
- PPDMIAUDIOCONNECTOR pConn = pDrv->pConnector;
- if (!pConn)
+ /* If we there was an error handling (available) output or there simply is no output available,
+ * then calculate the minimum data rate which must be processed by the device emulation in order
+ * to function correctly.
+ *
+ * This is not the optimal solution, but as we have to deal with this on a timer-based approach
+ * (until we have the audio callbacks) we need to have device' DMA engines running. */
+ if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
+ {
+ /* Use the mixer's (fixed) sampling rate. */
+ cbOut = RT_MAX(cbOut, cbMixerSamplesMin);
continue;
+ }
- int rc2 = pConn->pfnStreamIterate(pConn, pStream);
- if (RT_SUCCESS(rc2))
+ const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
+ if ( RT_FAILURE(rc)
+ || !fIsActiveOut)
{
- if (pStream->enmDir == PDMAUDIODIR_IN)
- {
- /** @todo Implement recording! */
- }
- else
- {
- rc2 = pConn->pfnStreamPlay(pConn, pStream, NULL /* cPlayed */);
- if (RT_FAILURE(rc2))
- {
- LogFlowFunc(("%s: Failed playing stream, rc=%Rrc\n", pStream->szName, rc2));
- continue;
- }
- }
+ uint32_t cSamplesMin = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
+ uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
- if (pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY)
- {
- /* Only do the next DMA transfer if we're able to write the entire
- * next data block. */
- fDoTransfer = pConn->pfnStreamGetWritable(pConn, pStream) >= (uint32_t)pThis->block_size;
- }
+ Log2Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
+
+ cbOut = RT_MAX(cbOut, cbSamplesMin);
}
- PDMAUDIOSTRMSTS strmSts = pConn->pfnStreamGetStatus(pConn, pStream);
- fIsPlaying |= ( (strmSts & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- || (strmSts & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE));
+ cbOutMin = RT_MIN(cbOutMin, cbOut);
+ cbInMax = RT_MAX(cbInMax, cbIn);
}
- bool fTimerActive = ASMAtomicReadBool(&pThis->fTimerActive);
- bool fKickTimer = fTimerActive || fIsPlaying;
+ Log2Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
- LogFlowFunc(("fTimerActive=%RTbool, fIsPlaying=%RTbool\n", fTimerActive, fIsPlaying));
+ if (cbOutMin == UINT32_MAX)
+ cbOutMin = 0;
- if (fDoTransfer)
+ /*
+ * Playback.
+ */
+ if (cbOutMin)
{
- /* Schedule the next transfer. */
- PDMDevHlpDMASchedule(pThis->pDevInsR3);
+ Assert(cbOutMin != UINT32_MAX);
- /* Kick the timer at least one more time. */
- fKickTimer = true;
+ /* New space available, see if we can transfer more. */
+ PDMDevHlpDMASchedule(pThis->pDevInsR3);
}
- if (fKickTimer)
- {
- /* Kick the timer again. */
- uint64_t cTicks = pThis->cTimerTicksIO;
- /** @todo adjust cTicks down by now much cbOutMin represents. */
- TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
- }
-}
+ /*
+ * Recording.
+ */
+ /** @todo Implement recording. */
-#endif /* !VBOX_WITH_AUDIO_CALLBACKS */
+ /* Kick the timer again. */
+ uint64_t cTicks = pThis->cTimerTicksIO;
+ /** @todo adjust cTicks down by now much cbOutMin represents. */
+ TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
+}
static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
{
@@ -1947,8 +1899,9 @@ static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
}
-static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis)
+static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis, int version_id)
{
+ RT_NOREF(version_id);
SSMR3GetS32(pSSM, &pThis->irq);
SSMR3GetS32(pSSM, &pThis->dma);
SSMR3GetS32(pSSM, &pThis->hdma);
@@ -2003,10 +1956,10 @@ static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis)
PSB16DRIVER pDrv;
RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
{
- if (pDrv->Out.pStream)
+ if (pDrv->Out.pStrmOut)
{
- pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStream);
- pDrv->Out.pStream = NULL;
+ pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStrmOut);
+ pDrv->Out.pStrmOut = NULL;
}
}
#endif
@@ -2016,13 +1969,10 @@ static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis)
if (pThis->freq)
{
PDMAUDIOSTREAMCFG streamCfg;
- RT_ZERO(streamCfg);
- streamCfg.enmDir = PDMAUDIODIR_OUT;
- streamCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
- streamCfg.uHz = pThis->freq;
- streamCfg.cChannels = 1 << pThis->fmt_stereo;
- streamCfg.enmFormat = pThis->fmt;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+ streamCfg.uHz = pThis->freq;
+ streamCfg.cChannels = 1 << pThis->fmt_stereo;
+ streamCfg.enmFormat = pThis->fmt;
+ streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
int rc = sb16OpenOut(pThis, &streamCfg);
AssertRC(rc);
@@ -2102,88 +2052,56 @@ static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint3
if (uPass != SSM_PASS_FINAL)
return VINF_SUCCESS;
- sb16Load(pSSM, pThis);
+ sb16Load(pSSM, pThis, uVersion);
return VINF_SUCCESS;
}
static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
-
- AssertReturn(pCfg->enmDir == PDMAUDIODIR_OUT, VERR_INVALID_PARAMETER);
- Assert(DrvAudioHlpStreamCfgIsValid(pCfg));
-
- /* Set a default audio format for the host. */
- PDMAUDIOSTREAMCFG CfgHost;
- CfgHost.enmDir = PDMAUDIODIR_OUT;
- CfgHost.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
- CfgHost.uHz = pCfg->uHz;
- CfgHost.cChannels = pCfg->cChannels;
- CfgHost.enmFormat = PDMAUDIOFMT_S16;
- CfgHost.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- RTStrPrintf(CfgHost.szName, sizeof(CfgHost.szName), "sb16.po");
-
- uint8_t uLUN = 0;
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
int rc = VINF_SUCCESS;
PSB16DRIVER pDrv;
+ uint8_t uLUN = 0;
+
RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
{
- if (!RTStrPrintf(pCfg->szName, sizeof(pCfg->szName), "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
- pDrv->uLUN, CfgHost.szName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel"))
+ char *pszDesc;
+ if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] sb16.po", uLUN) <= 0)
{
- rc = VERR_BUFFER_OVERFLOW;
+ rc = VERR_NO_MEMORY;
break;
}
- int rc2;
-
- if (pDrv->Out.pStream)
+ int rc2 = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
+ LogFlowFunc(("LUN#%RU8: Created output with rc=%Rrc\n", uLUN, rc));
+ if (rc2 == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
{
- pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream);
-
- rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
- if (RT_SUCCESS(rc2))
- pDrv->Out.pStream = NULL;
+ AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
+ rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
+ pDrv->pConnector, pDrv->Out.pStrmOut,
+ 0 /* uFlags */,
+ &pDrv->Out.phStrmOut);
}
- else
- rc2 = VINF_SUCCESS;
- if (RT_SUCCESS(rc2))
+ RTStrFree(pszDesc);
+
+ if (RT_FAILURE(rc2))
{
- rc2 = pDrv->pConnector->pfnStreamCreate(pDrv->pConnector, &CfgHost, pCfg, &pDrv->Out.pStream);
- if (RT_SUCCESS(rc2))
- pDrv->pConnector->pfnStreamRetain(pDrv->pConnector, pDrv->Out.pStream);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ break;
}
- LogFlowFunc(("LUN#%RU8: Created output \"%s\", rc=%Rrc\n", pDrv->uLUN, pCfg->szName, rc2));
-
uLUN++;
}
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static void sb16CloseOut(PSB16STATE pThis)
-{
- AssertPtrReturnVoid(pThis);
-
- LogFlowFuncEnter();
+ /* Ensure volume gets propagated. */
+ AudioMixerInvalidate(pThis->pMixer);
- PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnStreamControl(pDrv->pConnector, pDrv->Out.pStream, PDMAUDIOSTREAMCMD_DISABLE);
- AssertRC(rc2);
- }
-
- LogFlowFuncLeave();
+ return rc;
}
/**
@@ -2232,47 +2150,24 @@ static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, cons
}
/**
- * Powers off the device.
- *
- * @param pDevIns Device instance to power off.
+ * @interface_method_impl{PDMDEVREG,pfnDestruct}
*/
-static DECLCALLBACK(void) sb16PowerOff(PPDMDEVINS pDevIns)
+static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
{
+ PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
- LogRel2(("SB16: Powering off ...\n"));
-
PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- if (pDrv->Out.pStream)
- {
- pDrv->pConnector->pfnStreamRelease(pDrv->pConnector, pDrv->Out.pStream);
-
- int rc2 = pDrv->pConnector->pfnStreamDestroy(pDrv->pConnector, pDrv->Out.pStream);
- if (RT_SUCCESS(rc2))
- pDrv->Out.pStream = NULL;
- }
- }
-}
-/**
- * @interface_method_impl{PDMDEVREG,pfnDestruct}
- */
-static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
-{
- PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
- PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
+ RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
+ pDrv->Out.phStrmOut = NULL;
- LogFlowFuncEnter();
+ pThis->pSinkOutput = NULL;
- PSB16DRIVER pDrv;
- while (!RTListIsEmpty(&pThis->lstDrv))
+ if (pThis->pMixer)
{
- pDrv = RTListGetFirst(&pThis->lstDrv, SB16DRIVER, Node);
-
- RTListNodeRemove(&pDrv->Node);
- RTMemFree(pDrv);
+ AudioMixerDestroy(pThis->pMixer);
+ pThis->pMixer = NULL;
}
return VINF_SUCCESS;
@@ -2335,7 +2230,7 @@ static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
#ifndef VBOX_WITH_AUDIO_CALLBACKS
uint16_t uTimerHz;
- rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 25 /* Hz */);
+ rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("SB16 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
@@ -2428,14 +2323,14 @@ static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
* Only primary drivers are critical for the VM to run. Everything else
* might not worth showing an own error message box in the GUI.
*/
- if (!(pDrv->Flags & PDMAUDIODRVFLAGS_PRIMARY))
+ if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
continue;
PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
AssertPtr(pCon);
- /** @todo No input streams available for SB16 yet. */
- bool fValidOut = pCon->pfnStreamGetStatus(pCon, pDrv->Out.pStream) & PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
+ /* Note: No input streams available for SB16 yet. */
+ bool fValidOut = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
if (!fValidOut)
{
LogRel(("SB16: Falling back to NULL backend (no sound audible)\n"));
@@ -2454,16 +2349,17 @@ static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
{
rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
- if (RT_SUCCESS(rc))
+ if (RT_FAILURE(rc))
+ AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
+ else
{
pThis->cTimerTicksIO = TMTimerGetFreq(pThis->pTimerIO) / uTimerHz;
pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicksIO, uTimerHz));
- sb16TimerMaybeStart(pThis);
+ /* Fire off timer. */
+ TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
}
- else
- AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
}
#else
if (RT_SUCCESS(rc))
@@ -2475,7 +2371,7 @@ static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
{
/* Only register primary driver.
* The device emulation does the output multiplexing then. */
- if (pDrv->Flags != PDMAUDIODRVFLAGS_PRIMARY)
+ if (pDrv->Flags != PDMAUDIODRVFLAG_PRIMARY)
continue;
PDMAUDIOCALLBACK AudioCallbacks[2];
@@ -2547,7 +2443,7 @@ const PDMDEVREG g_DeviceSB16 =
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
- sb16PowerOff,
+ NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
diff --git a/src/VBox/Devices/Audio/DrvAudio.cpp b/src/VBox/Devices/Audio/DrvAudio.cpp
index 39c6533..a7b8992 100644
--- a/src/VBox/Devices/Audio/DrvAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvAudio.cpp
@@ -17,6 +17,30 @@
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
* --------------------------------------------------------------------
+ *
+ * This code is based on: audio.c from QEMU AUDIO subsystem.
+ *
+ * QEMU Audio subsystem
+ *
+ * Copyright (c) 2003-2005 Vassili Karpov (malc)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
*/
#define LOG_GROUP LOG_GROUP_DRV_AUDIO
#include <VBox/log.h>
@@ -40,18 +64,94 @@
#include "DrvAudio.h"
#include "AudioMixBuffer.h"
-static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream);
-static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd);
-static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd);
-static int drvAudioStreamDestroyInBackendInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream);
-static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream);
-static int drvAudioStreamInitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest);
-static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream);
-static int drvAudioStreamReInitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream);
+typedef struct fixed_settings
+{
+ int enabled;
+ int cStreams;
+ int greedy;
+ PDMAUDIOSTREAMCFG settings;
+} fixed_settings;
+
+static struct {
+ struct fixed_settings fixed_out;
+ struct fixed_settings fixed_in;
+ union {
+ int hz;
+ int64_t ticks;
+ } period;
+ int plive;
+} conf = {
+
+ /* Fixed output settings. */
+ { /* DAC fixed settings */
+ 1, /* enabled */
+ 1, /* cStreams */
+ 1, /* greedy */
+ {
+ 44100, /* freq */
+ 2, /* nchannels */
+ AUD_FMT_S16, /* fmt */
+ PDMAUDIOHOSTENDIANNESS
+ }
+ },
+
+ /* Fixed input settings. */
+ { /* ADC fixed settings */
+ 1, /* enabled */
+ 2, /* cStreams */
+ 1, /* greedy */
+ {
+ 44100, /* freq */
+ 2, /* nchannels */
+ AUD_FMT_S16, /* fmt */
+ PDMAUDIOHOSTENDIANNESS
+ }
+ },
+
+ { 200 }, /* frequency (in Hz) */
+ 0, /* plive */ /** @todo Disable pending live? */
+};
+
+static int drvAudioDestroyGstIn(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMIN pGstStrmIn);
+
+static int drvAudioAllocHstIn(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOHSTSTRMIN *ppHstStrmIn);
+static int drvAudioDestroyHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+
+int drvAudioAddHstOut(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+
+ int rc;
+ if ( conf.fixed_out.enabled /** @todo Get rid of these settings! */
+ && conf.fixed_out.greedy)
+ {
+ rc = drvAudioAllocHstOut(pThis, pszName, pCfg, &pHstStrmOut);
+ }
+ else
+ rc = VERR_NOT_FOUND;
+
+ if (RT_FAILURE(rc))
+ {
+ pHstStrmOut = drvAudioFindSpecificOut(pThis, NULL, pCfg);
+ if (!pHstStrmOut)
+ {
+ rc = drvAudioAllocHstOut(pThis, pszName, pCfg, &pHstStrmOut);
+ if (RT_FAILURE(rc))
+ pHstStrmOut = drvAudioFindAnyHstOut(pThis, NULL /* pHstStrmOut */);
+ }
+
+ rc = pHstStrmOut ? VINF_SUCCESS : rc;
+ }
-#ifndef VBOX_AUDIO_TESTCASE
+ if (RT_SUCCESS(rc))
+ *ppHstStrmOut = pHstStrmOut;
-# if 0 /* unused */
+ return rc;
+}
static PDMAUDIOFMT drvAudioGetConfFormat(PCFGMNODE pCfgHandle, const char *pszKey,
PDMAUDIOFMT enmDefault, bool *pfDefault)
@@ -71,8 +171,8 @@ static PDMAUDIOFMT drvAudioGetConfFormat(PCFGMNODE pCfgHandle, const char *pszKe
return enmDefault;
}
- PDMAUDIOFMT fmt = DrvAudioHlpStrToAudFmt(pszValue);
- if (fmt == PDMAUDIOFMT_INVALID)
+ PDMAUDIOFMT fmt = drvAudioHlpStringToFormat(pszValue);
+ if (fmt == AUD_FMT_INVALID)
{
*pfDefault = true;
return enmDefault;
@@ -128,46 +228,11 @@ static const char *drvAudioGetConfStr(PCFGMNODE pCfgHandle, const char *pszKey,
return pszValue;
}
-# endif /* unused */
-
-/**
- * Returns the host stream part of an audio stream pair, or NULL
- * if no host stream has been assigned / is not available.
- *
- * @returns IPRT status code.
- * @param pStream Audio stream to retrieve host stream part for.
- */
-DECLINLINE(PPDMAUDIOSTREAM) drvAudioGetHostStream(PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pStream, NULL);
-
- if (!pStream)
- return NULL;
-
- PPDMAUDIOSTREAM pHstStream = pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST
- ? pStream
- : pStream->pPair;
- if (pHstStream)
- {
- AssertReleaseMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,
- ("Stream '%s' resolved as host part is not marked as such (enmCtx=%RU32)\n",
- pHstStream->szName, pHstStream->enmCtx));
-
- AssertReleaseMsg(pHstStream->pPair != NULL,
- ("Stream '%s' resolved as host part has no guest part (anymore)\n", pHstStream->szName));
- }
- else
- LogRel(("Audio: Warning: Stream '%s' does not have a host stream (anymore)\n", pStream->szName));
-
- return pHstStream;
-}
-
-# if 0 /* unused */
-static int drvAudioProcessOptions(PCFGMNODE pCfgHandle, const char *pszPrefix, audio_option *paOpts, size_t cOpts)
+static int drvAudioProcessOptions(PCFGMNODE pCfgHandle, const char *pszPrefix, struct audio_option *opt)
{
AssertPtrReturn(pCfgHandle, VERR_INVALID_POINTER);
- AssertPtrReturn(pszPrefix, VERR_INVALID_POINTER);
- /* oaOpts and cOpts are optional. */
+ AssertPtrReturn(pszPrefix, VERR_INVALID_POINTER);
+ AssertPtrReturn(opt, VERR_INVALID_POINTER);
PCFGMNODE pCfgChildHandle = NULL;
PCFGMNODE pCfgChildChildHandle = NULL;
@@ -202,1024 +267,1340 @@ static int drvAudioProcessOptions(PCFGMNODE pCfgHandle, const char *pszPrefix, a
}
}
- for (size_t i = 0; i < cOpts; i++)
+ for (; opt->name; opt++)
{
- audio_option *pOpt = &paOpts[i];
- if (!pOpt->valp)
- {
- LogFlowFunc(("Option value pointer for `%s' is not set\n", pOpt->name));
+ LogFlowFunc(("Option value pointer for `%s' is not set\n",
+ opt->name));
+ if (!opt->valp) {
+ LogFlowFunc(("Option value pointer for `%s' is not set\n",
+ opt->name));
continue;
}
bool fUseDefault;
- switch (pOpt->tag)
+ switch (opt->tag)
{
case AUD_OPT_BOOL:
case AUD_OPT_INT:
{
- int *intp = (int *)pOpt->valp;
- *intp = drvAudioGetConfInt(pCfgHandle, pOpt->name, *intp, &fUseDefault);
+ int *intp = (int *)opt->valp;
+ *intp = drvAudioGetConfInt(pCfgHandle, opt->name, *intp, &fUseDefault);
break;
}
case AUD_OPT_FMT:
{
- PDMAUDIOFMT *fmtp = (PDMAUDIOFMT *)pOpt->valp;
- *fmtp = drvAudioGetConfFormat(pCfgHandle, pOpt->name, *fmtp, &fUseDefault);
+ PDMAUDIOFMT *fmtp = (PDMAUDIOFMT *)opt->valp;
+ *fmtp = drvAudioGetConfFormat(pCfgHandle, opt->name, *fmtp, &fUseDefault);
break;
}
case AUD_OPT_STR:
{
- const char **strp = (const char **)pOpt->valp;
- *strp = drvAudioGetConfStr(pCfgHandle, pOpt->name, *strp, &fUseDefault);
+ const char **strp = (const char **)opt->valp;
+ *strp = drvAudioGetConfStr(pCfgHandle, opt->name, *strp, &fUseDefault);
break;
}
default:
- LogFlowFunc(("Bad value tag for option `%s' - %d\n", pOpt->name, pOpt->tag));
+ LogFlowFunc(("Bad value tag for option `%s' - %d\n", opt->name, opt->tag));
fUseDefault = false;
break;
}
- if (!pOpt->overridenp)
- pOpt->overridenp = &pOpt->overriden;
+ if (!opt->overridenp)
+ opt->overridenp = &opt->overriden;
- *pOpt->overridenp = !fUseDefault;
+ *opt->overridenp = !fUseDefault;
}
return VINF_SUCCESS;
}
-# endif /* unused */
-#endif /* !VBOX_AUDIO_TESTCASE */
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamControl}
- */
-static DECLCALLBACK(int) drvAudioStreamControl(PPDMIAUDIOCONNECTOR pInterface,
- PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static bool drvAudioStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-
- if (!pStream)
- return VINF_SUCCESS;
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+ bool fValid = ( pCfg->cChannels == 1
+ || pCfg->cChannels == 2); /* Either stereo (2) or mono (1), per stream. */
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
+ fValid |= ( pCfg->enmEndianness == PDMAUDIOENDIANNESS_LITTLE
+ || pCfg->enmEndianness == PDMAUDIOENDIANNESS_BIG);
- LogFlowFunc(("[%s] enmStreamCmd=%RU32\n", pStream->szName, enmStreamCmd));
+ if (fValid)
+ {
+ switch (pCfg->enmFormat)
+ {
+ case AUD_FMT_S8:
+ case AUD_FMT_U8:
+ case AUD_FMT_S16:
+ case AUD_FMT_U16:
+ case AUD_FMT_S32:
+ case AUD_FMT_U32:
+ break;
+ default:
+ fValid = false;
+ break;
+ }
+ }
- rc = drvAudioStreamControlInternal(pThis, pStream, enmStreamCmd);
+ /** @todo Check for defined frequencies supported. */
+ fValid |= pCfg->uHz > 0;
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
+#ifdef DEBUG
+ drvAudioStreamCfgPrint(pCfg);
+#endif
- return rc;
+ LogFlowFunc(("pCfg=%p, fValid=%RTbool\n", pCfg, fValid));
+ return fValid;
}
/**
- * Controls an audio stream.
+ * Clears a sample buffer by the given amount of audio samples.
*
- * @returns IPRT status code.
- * @param pThis Pointer to driver instance.
- * @param pStream Stream to control.
- * @param enmStreamCmd Control command.
+ * @return IPRT status code.
+ * @param pPCMProps PCM properties to use for the buffer to clear.
+ * @param pvBuf Buffer to clear.
+ * @param cbBuf Size (in bytes) of the buffer.
+ * @param cSamples Number of audio samples to clear in the buffer.
*/
-static int drvAudioStreamControlInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+void DrvAudioClearBuf(PPDMPCMPROPS pPCMProps, void *pvBuf, size_t cbBuf, uint32_t cSamples)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturnVoid(pPCMProps);
+ AssertPtrReturnVoid(pvBuf);
+
+ if (!cbBuf || !cSamples)
+ return;
+
+ Log2Func(("pPCMInfo=%p, pvBuf=%p, cSamples=%RU32, fSigned=%RTbool, cBits=%RU8, cShift=%RU8\n",
+ pPCMProps, pvBuf, cSamples, pPCMProps->fSigned, pPCMProps->cBits, pPCMProps->cShift));
+
+ if (pPCMProps->fSigned)
+ {
+ memset(pvBuf, 0, cSamples << pPCMProps->cShift);
+ }
+ else
+ {
+ switch (pPCMProps->cBits)
+ {
+ case 8:
+ {
+ memset(pvBuf, 0x80, cSamples << pPCMProps->cShift);
+ break;
+ }
- LogFunc(("[%s] enmStreamCmd=%RU32\n", pStream->szName, enmStreamCmd));
+ case 16:
+ {
+ uint16_t *p = (uint16_t *)pvBuf;
+ int shift = pPCMProps->cChannels - 1;
+ short s = INT16_MAX;
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
- AssertPtr(pGstStream);
+ if (pPCMProps->fSwapEndian)
+ s = RT_BSWAP_U16(s);
- LogFlowFunc(("Status host=0x%x, guest=0x%x\n", pHstStream->fStatus, pGstStream->fStatus));
+ for (unsigned i = 0; i < cSamples << shift; i++)
+ p[i] = s;
- int rc = VINF_SUCCESS;
+ break;
+ }
+
+ case 32:
+ {
+ uint32_t *p = (uint32_t *)pvBuf;
+ int shift = pPCMProps->cChannels - 1;
+ int32_t s = INT32_MAX;
+
+ if (pPCMProps->fSwapEndian)
+ s = RT_BSWAP_U32(s);
+
+ for (unsigned i = 0; i < cSamples << shift; i++)
+ p[i] = s;
+
+ break;
+ }
+
+ default:
+ {
+ AssertMsgFailed(("Invalid bits: %RU8\n", pPCMProps->cBits));
+ break;
+ }
+ }
+ }
+}
+
+static int drvAudioControlHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+ int rc = RTCritSectEnter(&pHstStrmIn->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
switch (enmStreamCmd)
{
case PDMAUDIOSTREAMCMD_ENABLE:
{
- if (!(pGstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
+ if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
{
- if (pHstStream)
+ rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_ENABLE);
+ if (RT_SUCCESS(rc))
{
- /* Is a pending disable outstanding? Then disable first. */
- if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
- rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
-
- if (RT_SUCCESS(rc))
- rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_ENABLE);
+ pHstStrmIn->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
}
-
- pGstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
+ else
+ LogFlowFunc(("Backend reported an error when opening input stream, rc=%Rrc\n", rc));
}
+ else
+ rc = VINF_SUCCESS;
+
break;
}
case PDMAUDIOSTREAMCMD_DISABLE:
- case PDMAUDIOSTREAMCMD_PAUSE:
{
- if (pGstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+ if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
{
- /* Is the guest side stream still active?
- * Mark the host stream as pending disable and bail out. */
- if (pHstStream)
- {
- LogFunc(("[%s] Pending disable/pause\n", pHstStream->szName));
- pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
- }
-
- if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
+ rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_DISABLE);
+ if (RT_SUCCESS(rc))
{
- pGstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_ENABLED;
+ pHstStrmIn->fStatus = PDMAUDIOSTRMSTS_FLAG_NONE; /* Clear all. */
+ AudioMixBufClear(&pHstStrmIn->MixBuf);
}
- else if (enmStreamCmd == PDMAUDIOSTREAMCMD_PAUSE)
- pGstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
else
- AssertFailedBreakStmt(rc = VERR_NOT_IMPLEMENTED);
+ LogFlowFunc(("Backend vetoed closing output stream, rc=%Rrc\n", rc));
}
+ else
+ rc = VINF_SUCCESS;
+
+ break;
+ }
- if ( pHstStream
- && !(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE))
+ case PDMAUDIOSTREAMCMD_PAUSE:
+ {
+ if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED))
{
- rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, enmStreamCmd);
+ Assert(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
+ rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_PAUSE);
if (RT_SUCCESS(rc))
- pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+ {
+ LogFunc(("[%s] Pausing stream\n", pHstStrmIn->MixBuf.pszName));
+ pHstStrmIn->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
+ }
+ else
+ LogFlowFunc(("Backend vetoed pausing input stream, rc=%Rrc\n", rc));
}
+ else
+ rc = VINF_SUCCESS;
+
break;
}
case PDMAUDIOSTREAMCMD_RESUME:
{
- if (pGstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED)
+ if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED)
{
- if (pHstStream)
- rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_RESUME);
-
- pGstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
+ Assert(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
+ rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_RESUME);
+ if (RT_SUCCESS(rc))
+ {
+ pHstStrmIn->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
+ LogFunc(("[%s] Resumed stream\n", pHstStrmIn->MixBuf.pszName));
+ }
+ else
+ LogFlowFunc(("Backend vetoed resuming input stream, rc=%Rrc\n", rc));
}
+ else
+ rc = VINF_SUCCESS;
+
break;
}
default:
- AssertMsgFailed(("Command %RU32 not implemented\n", enmStreamCmd));
+ AssertMsgFailed(("Command %ld not implemented\n", enmStreamCmd));
rc = VERR_NOT_IMPLEMENTED;
break;
}
- if (RT_FAILURE(rc))
- LogFunc(("[%s] Failed with %Rrc\n", pStream->szName, rc));
+ int rc2 = RTCritSectLeave(&pHstStrmIn->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
return rc;
}
-/**
- * Controls a stream's backend.
- * If the stream has no backend available, VERR_NOT_FOUND is returned.
- *
- * @returns IPRT status code.
- * @param pThis Pointer to driver instance.
- * @param pStream Stream to control.
- * @param enmStreamCmd Control command.
- */
-static int drvAudioStreamControlInternalBackend(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static int drvAudioControlHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- if (!pHstStream) /* Stream does not have a host backend? Bail out. */
- return VERR_NOT_FOUND;
-
- LogFlowFunc(("[%s] enmStreamCmd=%RU32, fStatus=0x%x\n", pHstStream->szName, enmStreamCmd, pHstStream->fStatus));
-
- AssertPtr(pThis->pHostDrvAudio);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- int rc = VINF_SUCCESS;
+ int rc = RTCritSectEnter(&pHstStrmOut->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
switch (enmStreamCmd)
{
case PDMAUDIOSTREAMCMD_ENABLE:
{
- if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
+ if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
{
- LogRel2(("Audio: Enabling stream '%s'\n", pHstStream->szName));
- rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_ENABLE);
+ rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
if (RT_SUCCESS(rc))
{
- pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
+ Assert(!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE));
+ pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
+ LogFunc(("[%s] Enabled stream\n", pHstStrmOut->MixBuf.pszName));
}
else
- LogRel2(("Audio: Disabling stream '%s' failed with %Rrc\n", pHstStream->szName, rc));
+ LogFlowFunc(("[%s] Backend reported an error when enabling output stream, rc=%Rrc\n",
+ pHstStrmOut->MixBuf.pszName, rc));
}
+ else
+ rc = VINF_SUCCESS;
+
break;
}
case PDMAUDIOSTREAMCMD_DISABLE:
{
- if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+ if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
{
- LogRel2(("Audio: Disabling stream '%s'\n", pHstStream->szName));
- rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
+ rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
if (RT_SUCCESS(rc))
{
- pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_ENABLED;
- pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
- AudioMixBufReset(&pHstStream->MixBuf);
+ pHstStrmOut->fStatus = PDMAUDIOSTRMSTS_FLAG_NONE; /* Clear all. */
+ AudioMixBufClear(&pHstStrmOut->MixBuf);
+
+ LogFunc(("[%s] Disabled stream\n", pHstStrmOut->MixBuf.pszName));
}
else
- LogRel2(("Audio: Disabling stream '%s' failed with %Rrc\n", pHstStream->szName, rc));
+ LogFlowFunc(("[%s] Backend vetoed disabling output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
}
+ else
+ rc = VINF_SUCCESS;
+
break;
}
case PDMAUDIOSTREAMCMD_PAUSE:
{
- /* Only pause if the stream is enabled. */
- if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
- break;
-
- if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED))
+ if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED))
{
- LogRel2(("Audio: Pausing stream '%s'\n", pHstStream->szName));
- rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_PAUSE);
+ Assert(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
+ rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_PAUSE);
if (RT_SUCCESS(rc))
{
- pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
+ pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
+ LogFunc(("[%s] Pausing stream\n", pHstStrmOut->MixBuf.pszName));
}
else
- LogRel2(("Audio: Pausing stream '%s' failed with %Rrc\n", pHstStream->szName, rc));
+ LogFlowFunc(("[%s] Backend vetoed pausing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
}
+ else
+ rc = VINF_SUCCESS;
+
break;
}
case PDMAUDIOSTREAMCMD_RESUME:
{
- /* Only need to resume if the stream is enabled. */
- if (!(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
- break;
-
- if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED)
+ if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED)
{
- LogRel2(("Audio: Resuming stream '%s'\n", pHstStream->szName));
- rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_RESUME);
+ Assert(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
+ rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_RESUME);
if (RT_SUCCESS(rc))
{
- pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
+ pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
+ LogFunc(("[%s] Resumed stream\n", pHstStrmOut->MixBuf.pszName));
}
else
- LogRel2(("Audio: Resuming stream '%s' failed with %Rrc\n", pHstStream->szName, rc));
+ LogFlowFunc(("[%s] Backend vetoed resuming output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
}
+ else
+ rc = VINF_SUCCESS;
+
break;
}
default:
- {
- AssertMsgFailed(("Command %RU32 not implemented\n", enmStreamCmd));
+ AssertMsgFailed(("Command %ld not implemented\n", enmStreamCmd));
rc = VERR_NOT_IMPLEMENTED;
break;
- }
}
- if (RT_FAILURE(rc))
- LogFunc(("[%s] Failed with %Rrc\n", pStream->szName, rc));
+ int rc2 = RTCritSectLeave(&pHstStrmOut->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
return rc;
}
-/**
- * Initializes an audio stream with a given host and guest stream configuration.
- *
- * @returns IPRT status code.
- * @param pThis Pointer to driver instance.
- * @param pStream Stream to initialize.
- * @param pCfgHost Stream configuration to use for the host side (backend).
- * @param pCfgGuest Stream configuration to use for the guest side.
- */
-static int drvAudioStreamInitInternal(PDRVAUDIO pThis,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest)
+int drvAudioDestroyHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
- AssertPtr(pGstStream);
+ LogFlowFunc(("%s\n", pHstStrmOut->MixBuf.pszName));
- /*
- * Init host stream.
- */
+ int rc;
+ if (RTListIsEmpty(&pHstStrmOut->lstGstStrmOut))
+ {
+ rc = pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
+ if (RT_SUCCESS(rc))
+ {
+ drvAudioHstOutFreeRes(pHstStrmOut);
- /* Make the acquired host configuration the requested host configuration initially,
- * in case the backend does not report back an acquired configuration. */
- PDMAUDIOSTREAMCFG CfgHostAcq;
- memcpy(&CfgHostAcq, pCfgHost, sizeof(PDMAUDIOSTREAMCFG));
+ /* Remove from driver instance list. */
+ RTListNodeRemove(&pHstStrmOut->Node);
-#ifdef DEBUG
- LogFunc(("[%s] Requested host format:\n", pStream->szName));
- DrvAudioHlpStreamCfgPrint(pCfgHost);
-#else
- LogRel2(("Audio: Creating stream '%s'\n", pStream->szName));
- LogRel2(("Audio: Requested %s host format for '%s': %RU32Hz, %s, %RU8 %s\n",
- pCfgGuest->enmDir == PDMAUDIODIR_IN ? "recording" : "playback", pStream->szName,
- pCfgHost->uHz, DrvAudioHlpAudFmtToStr(pCfgHost->enmFormat),
- pCfgHost->cChannels, pCfgHost->cChannels == 0 ? "Channel" : "Channels"));
-#endif
+ if (RTCritSectIsInitialized(&pHstStrmOut->CritSect))
+ {
+ int rc2 = RTCritSectDelete(&pHstStrmOut->CritSect);
+ AssertRC(rc2);
+ }
- int rc = pThis->pHostDrvAudio->pfnStreamCreate(pThis->pHostDrvAudio, pHstStream,
- pCfgHost /* pCfgReq */, &CfgHostAcq /* pCfgAcq */);
- if (RT_FAILURE(rc))
+ RTMemFree(pHstStrmOut);
+ pThis->cFreeOutputStreams++;
+ return VINF_SUCCESS;
+ }
+ }
+ else
{
- LogRel2(("Audio: Creating stream '%s' in backend failed with %Rrc\n", pStream->szName, rc));
- return rc;
+ rc = VERR_ACCESS_DENIED;
+ LogFlowFunc(("[%s] Still is being used, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
}
- /* Only set the host's stream to initialized if we were able create the stream
- * in the host backend. This is necessary for trying to re-initialize the stream
- * at some later point in time. */
- pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
-
-#ifdef DEBUG
- LogFunc(("[%s] Acquired host format:\n", pStream->szName));
- DrvAudioHlpStreamCfgPrint(&CfgHostAcq);
-#else
- LogRel2(("Audio: Acquired %s host format for '%s': %RU32Hz, %s, %RU8 %s\n",
- pCfgGuest->enmDir == PDMAUDIODIR_IN ? "recording" : "playback", pStream->szName,
- CfgHostAcq.uHz, DrvAudioHlpAudFmtToStr(CfgHostAcq.enmFormat),
- CfgHostAcq.cChannels, CfgHostAcq.cChannels == 0 ? "Channel" : "Channels"));
-#endif
-
- /* No sample buffer size hint given by the backend? Default to some sane value. */
- if (!CfgHostAcq.cSampleBufferSize)
- CfgHostAcq.cSampleBufferSize = _1K; /** @todo Make this configurable? */
-
- PDMAUDIOPCMPROPS PCMProps;
- int rc2 = DrvAudioHlpStreamCfgToProps(&CfgHostAcq, &PCMProps);
- AssertRC(rc2);
-
- /* Destroy any former mixing buffer. */
- AudioMixBufDestroy(&pHstStream->MixBuf);
-
- LogFlowFunc(("[%s] cSamples=%RU32\n", pHstStream->szName, CfgHostAcq.cSampleBufferSize * 4));
+ return rc;
+}
- rc2 = AudioMixBufInit(&pHstStream->MixBuf, pHstStream->szName, &PCMProps, CfgHostAcq.cSampleBufferSize * 4);
- AssertRC(rc2);
+int drvAudioDestroyGstOut(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- /* Make a copy of the host stream configuration. */
- memcpy(&pHstStream->Cfg, pCfgHost, sizeof(PDMAUDIOSTREAMCFG));
+ if (!pGstStrmOut)
+ return VINF_SUCCESS;
- /*
- * Init guest stream.
- */
+ if (pGstStrmOut->State.cRefs > 1) /* Do other objects still have a reference to it? Bail out. */
+ return VERR_WRONG_ORDER;
- RT_ZERO(PCMProps);
- rc2 = DrvAudioHlpStreamCfgToProps(pCfgGuest, &PCMProps);
- AssertRC(rc2);
+ drvAudioGstOutFreeRes(pGstStrmOut);
- /* Destroy any former mixing buffer. */
- AudioMixBufDestroy(&pGstStream->MixBuf);
+ if (pGstStrmOut->pHstStrmOut)
+ {
+ /* Unregister from parent first. */
+ RTListNodeRemove(&pGstStrmOut->Node);
- LogFlowFunc(("[%s] cSamples=%RU32\n", pGstStream->szName, CfgHostAcq.cSampleBufferSize * 2));
+ /* Try destroying the associated host output stream. This could
+ * be skipped if there are other guest output streams with this
+ * host stream. */
+ drvAudioDestroyHstOut(pThis, pGstStrmOut->pHstStrmOut);
+ }
- rc2 = AudioMixBufInit(&pGstStream->MixBuf, pGstStream->szName, &PCMProps, CfgHostAcq.cSampleBufferSize * 2);
- AssertRC(rc2);
+ RTMemFree(pGstStrmOut);
-#ifdef VBOX_WITH_STATISTICS
- char szStatName[255];
-#endif
+ return VINF_SUCCESS;
+}
- if (pCfgGuest->enmDir == PDMAUDIODIR_IN)
+PPDMAUDIOHSTSTRMIN drvAudioFindNextHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+ if (pHstStrmIn)
{
- /* Host (Parent) -> Guest (Child). */
- rc2 = AudioMixBufLinkTo(&pHstStream->MixBuf, &pGstStream->MixBuf);
- AssertRC(rc2);
+ if (RTListNodeIsLast(&pThis->lstHstStrmIn, &pHstStrmIn->Node))
+ return NULL;
-#ifdef VBOX_WITH_STATISTICS
- RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesElapsed", pGstStream->szName);
- PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStream->In.StatBytesElapsed,
- szStatName, STAMUNIT_BYTES, "Elapsed bytes read.");
+ return RTListNodeGetNext(&pHstStrmIn->Node, PDMAUDIOHSTSTRMIN, Node);
+ }
- RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesRead", pGstStream->szName);
- PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStream->In.StatBytesTotalRead,
- szStatName, STAMUNIT_BYTES, "Total bytes read.");
+ return RTListGetFirst(&pThis->lstHstStrmIn, PDMAUDIOHSTSTRMIN, Node);
+}
- RTStrPrintf(szStatName, sizeof(szStatName), "Host/%s/SamplesCaptured", pHstStream->szName);
- PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pHstStream->In.StatSamplesCaptured,
- szStatName, STAMUNIT_COUNT, "Total samples captured.");
-#endif
- }
- else
- {
- /* Guest (Parent) -> Host (Child). */
- rc2 = AudioMixBufLinkTo(&pGstStream->MixBuf, &pHstStream->MixBuf);
- AssertRC(rc2);
+PPDMAUDIOHSTSTRMIN drvAudioFindNextEnabledHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+ while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
+ if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+ return pHstStrmIn;
-#ifdef VBOX_WITH_STATISTICS
- RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesElapsed", pGstStream->szName);
- PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStream->Out.StatBytesElapsed,
- szStatName, STAMUNIT_BYTES, "Elapsed bytes written.");
+ return NULL;
+}
- RTStrPrintf(szStatName, sizeof(szStatName), "Guest/%s/BytesRead", pGstStream->szName);
- PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pGstStream->Out.StatBytesTotalWritten,
- szStatName, STAMUNIT_BYTES, "Total bytes written.");
+PPDMAUDIOHSTSTRMIN drvAudioFindNextEqHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PPDMAUDIOSTREAMCFG pCfg)
+{
+ while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
+ if (drvAudioPCMPropsAreEqual(&pHstStrmIn->Props, pCfg))
+ return pHstStrmIn;
- RTStrPrintf(szStatName, sizeof(szStatName), "Host/%s/SamplesPlayed", pHstStream->szName);
- PDMDrvHlpSTAMRegCounterEx(pThis->pDrvIns, &pHstStream->Out.StatSamplesPlayed,
- szStatName, STAMUNIT_COUNT, "Total samples played.");
-#endif
- }
+ return NULL;
+}
- /* Make a copy of the host stream configuration. */
- memcpy(&pGstStream->Cfg, pCfgGuest, sizeof(PDMAUDIOSTREAMCFG));
+static int drvAudioHstInAdd(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PDMAUDIORECSOURCE enmRecSource,
+ PPDMAUDIOHSTSTRMIN *ppHstStrmIn)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppHstStrmIn, VERR_INVALID_POINTER);
- if (RT_FAILURE(rc))
- LogRel2(("Audio: Creating stream '%s' failed with %Rrc\n", pStream->szName, rc));
+ PPDMAUDIOHSTSTRMIN pHstStrmIn;
+ int rc = drvAudioAllocHstIn(pThis, pszName, pCfg, enmRecSource, &pHstStrmIn);
+ if (RT_SUCCESS(rc))
+ *ppHstStrmIn = pHstStrmIn;
- LogFlowFunc(("[%s] Returning %Rrc\n", pStream->szName, rc));
+ LogFlowFuncLeaveRC(rc);
return rc;
}
-/**
- * Re-initializes an audio stream with its existing host and guest stream configuration.
- *
- * @returns IPRT status code.
- * @param pThis Pointer to driver instance.
- * @param pStream Stream to re-initialize.
- */
-static int drvAudioStreamReInitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)
+int drvAudioGstOutInit(PPDMAUDIOGSTSTRMOUT pGstStrmOut, PPDMAUDIOHSTSTRMOUT pHostStrmOut,
+ const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pGstStrmOut, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostStrmOut, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- LogFlowFunc(("[%s]\n", pStream->szName));
+ int rc = DrvAudioStreamCfgToProps(pCfg, &pGstStrmOut->Props);
+ if (RT_SUCCESS(rc))
+ {
+ char *pszTemp;
+ if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
+ return VERR_NO_MEMORY;
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
- AssertPtr(pGstStream);
+ rc = AudioMixBufInit(&pGstStrmOut->MixBuf, pszTemp, &pGstStrmOut->Props, AudioMixBufSize(&pHostStrmOut->MixBuf));
+ if (RT_SUCCESS(rc))
+ rc = AudioMixBufLinkTo(&pGstStrmOut->MixBuf, &pHostStrmOut->MixBuf);
- int rc;
+ RTStrFree(pszTemp);
- if (/* Stream initialized? */
- (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
- /* Not in pending re-init before? */
- && !(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT))
- {
- /* Disable first. */
- rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_FAILURE(rc))
+ if (RT_SUCCESS(rc))
{
- LogFunc(("[%s] Error disabling stream, rc=%Rrc\n", pStream->szName, rc));
- return rc;
- }
+ pGstStrmOut->State.cRefs = 1;
+ pGstStrmOut->State.fActive = false;
+ pGstStrmOut->State.fEmpty = true;
- /* Give the backend the chance to clean up the old context. */
- rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream);
- if (RT_FAILURE(rc))
- {
- LogFunc(("[%s] Error destroying stream in backend, rc=%Rrc\n", pStream->szName, rc));
- return rc;
- }
+ pGstStrmOut->State.pszName = RTStrDup(pszName);
+ if (!pGstStrmOut->State.pszName)
+ return VERR_NO_MEMORY;
- /* Set the pending re-init bit. */
- pHstStream->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT;
- }
-
- LogFlowFunc(("[%s] Host status is 0x%x\n", pStream->szName, pHstStream->fStatus));
-
- /* Try to re-initialize the stream. */
- rc = drvAudioStreamInitInternal(pThis, pStream, &pHstStream->Cfg, &pGstStream->Cfg);
- if (RT_SUCCESS(rc))
- {
- /* Try to restore the previous stream status, if possible. */
- PDMAUDIOSTREAMCMD enmCmdRestore = PDMAUDIOSTREAMCMD_UNKNOWN;
-
- if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED) /* Stream was running before? */
- {
- LogFunc(("[%s] Re-enabling host stream ...\n", pStream->szName));
- enmCmdRestore = PDMAUDIOSTREAMCMD_ENABLE;
+ pGstStrmOut->pHstStrmOut = pHostStrmOut;
}
-
- if (enmCmdRestore != PDMAUDIOSTREAMCMD_UNKNOWN)
- rc = pThis->pHostDrvAudio->pfnStreamControl(pThis->pHostDrvAudio, pHstStream, PDMAUDIOSTREAMCMD_ENABLE);
-
- /* Re-initialization successful, remove bit again. */
- pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_REINIT;
}
- LogFunc(("[%s] Reinitialization returned %Rrc\n", pStream->szName, rc));
+ LogFlowFunc(("pszName=%s, rc=%Rrc\n", pszName, rc));
return rc;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamWrite}
- */
-static DECLCALLBACK(int) drvAudioStreamWrite(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
- const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+int drvAudioAllocHstOut(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- /* pcbWritten is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- if ( !pStream
- || !cbBuf)
+ if (!pThis->cFreeOutputStreams)
{
- if (pcbWritten)
- *pcbWritten = 0;
- return VINF_SUCCESS;
+ LogFlowFunc(("Maximum number of host output streams reached\n"));
+ return VERR_NO_MORE_HANDLES;
}
- AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT,
- ("Stream '%s' is not an output stream and therefore cannot be written to (direction is 0x%x)\n",
- pStream->szName, pStream->enmDir));
+ /* Validate backend configuration. */
+ if (!pThis->BackendCfg.cbStreamOut)
+ {
+ LogFlowFunc(("Backend output configuration not valid, bailing out\n"));
+ return VERR_INVALID_PARAMETER;
+ }
- uint32_t cbWritten = 0;
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = (PPDMAUDIOHSTSTRMOUT)RTMemAllocZ(pThis->BackendCfg.cbStreamOut);
+ if (!pHstStrmOut)
+ {
+ LogFlowFunc(("Error allocating host output stream with %zu bytes\n",
+ pThis->BackendCfg.cbStreamOut));
+ return VERR_NO_MEMORY;
+ }
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
+ int rc;
+ bool fInitialized = false;
do
{
- if ( pThis->pHostDrvAudio
- && pThis->pHostDrvAudio->pfnGetStatus
- && pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_OUT) != PDMAUDIOBACKENDSTS_RUNNING)
+ RTListInit(&pHstStrmOut->lstGstStrmOut);
+
+ /* Make the acquired configuration the requested configuration by default. */
+ PDMAUDIOSTREAMCFG CfgAcq;
+ memcpy(&CfgAcq, pCfg, sizeof(PDMAUDIOSTREAMCFG));
+
+ uint32_t cSamples;
+ rc = pThis->pHostDrvAudio->pfnInitOut(pThis->pHostDrvAudio, pHstStrmOut,
+ pCfg /* pCfgReq */, &CfgAcq /* pCfgAcq */,
+ &cSamples);
+ if (RT_FAILURE(rc))
{
- rc = VERR_NOT_AVAILABLE;
+ LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
break;
}
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- if (!pHstStream)
+ fInitialized = true;
+
+ char *pszTemp;
+ if (RTStrAPrintf(&pszTemp, "%s (Host)", pszName) <= 0)
{
- rc = VERR_NOT_AVAILABLE;
+ rc = VERR_NO_MEMORY;
break;
}
- PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+#ifdef DEBUG
+ LogFunc(("%s: Requested format:\n", pszTemp));
+ drvAudioStreamCfgPrint(pCfg);
+ LogFunc(("%s: Acquired format:\n", pszTemp));
+ drvAudioStreamCfgPrint(&CfgAcq);
+#else
+ LogRel2(("Audio: Acquired output format for '%s': %RU32Hz, %s, %RU8 %s\n",
+ pszTemp, CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
+ CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
+#endif
+ rc = DrvAudioStreamCfgToProps(&CfgAcq, &pHstStrmOut->Props);
+ if (RT_SUCCESS(rc))
+ {
+ rc = AudioMixBufInit(&pHstStrmOut->MixBuf, pszTemp, &pHstStrmOut->Props, cSamples);
+ if (RT_SUCCESS(rc))
+ rc = RTCritSectInit(&pHstStrmOut->CritSect);
- AssertMsg(pGstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
- ("Writing to disabled guest output stream \"%s\" not possible\n", pGstStream->szName));
+ if (RT_SUCCESS(rc))
+ {
+ RTListPrepend(&pThis->lstHstStrmOut, &pHstStrmOut->Node);
+ pThis->cFreeOutputStreams--;
+ }
+ }
- pGstStream->Out.tsLastWriteMS = RTTimeMilliTS();
+ RTStrFree(pszTemp);
- if (!AudioMixBufFreeBytes(&pGstStream->MixBuf))
- {
- LogRel2(("Audio: Guest stream '%s' full, expect stuttering audio output\n", pGstStream->szName));
- break;
- }
+ } while (0);
- uint32_t cWritten = 0;
- rc = AudioMixBufWriteCirc(&pGstStream->MixBuf, pvBuf, cbBuf, &cWritten);
- if (rc == VINF_BUFFER_OVERFLOW)
+ if (RT_FAILURE(rc))
+ {
+ if (fInitialized)
{
- LogRel2(("Audio: Lost audio samples from guest stream '%s', expect stuttering audio output\n", pGstStream->szName));
- rc = VINF_SUCCESS;
- break;
+ int rc2 = pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
+ AssertRC(rc2);
}
-#ifdef VBOX_WITH_STATISTICS
- STAM_COUNTER_ADD(&pThis->Stats.TotalBytesWritten, AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cWritten));
- STAM_COUNTER_ADD(&pGstStream->Out.StatBytesTotalWritten, AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cWritten));
-#endif
- cbWritten = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cWritten);
+ drvAudioHstOutFreeRes(pHstStrmOut);
+ RTMemFree(pHstStrmOut);
+ }
+ else
+ *ppHstStrmOut = pHstStrmOut;
- Log3Func(("[%s] cUsed=%RU32, cLive=%RU32\n",
- pGstStream->szName, AudioMixBufUsed(&pGstStream->MixBuf), AudioMixBufLive(&pGstStream->MixBuf)));
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
- } while (0);
+int drvAudioCreateStreamPairOut(PDRVAUDIO pThis, const char *pszName,
+ PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
+ /*
+ * Try figuring out which audio stream configuration this backend
+ * should use. If fixed output is enabled the backend will be tied
+ * to a fixed rate (in Hz, among other parameters), regardless of
+ * what the backend could do else.
+ */
+ PPDMAUDIOSTREAMCFG pBackendCfg;
+ if (conf.fixed_out.enabled)
+ pBackendCfg = &conf.fixed_out.settings;
+ else
+ pBackendCfg = pCfg;
+
+ AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
+
+ LogFlowFunc(("Using fixed audio output settings: %RTbool\n",
+ RT_BOOL(conf.fixed_out.enabled)));
+
+ PPDMAUDIOGSTSTRMOUT pGstStrmOut =
+ (PPDMAUDIOGSTSTRMOUT)RTMemAllocZ(sizeof(PDMAUDIOGSTSTRMOUT));
+ if (!pGstStrmOut)
+ {
+ LogFlowFunc(("Failed to allocate memory for guest output stream \"%s\"\n", pszName));
+ return VERR_NO_MEMORY;
+ }
+ /*
+ * The host stream always will get the backend audio stream configuration.
+ */
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut;
+ int rc = drvAudioAddHstOut(pThis, pszName, pBackendCfg, &pHstStrmOut);
+ if (RT_FAILURE(rc))
+ {
+ LogFlowFunc(("Error adding host output stream \"%s\", rc=%Rrc\n", pszName, rc));
+
+ RTMemFree(pGstStrmOut);
+ return rc;
+ }
+
+ /*
+ * The guest stream always will get the audio stream configuration told
+ * by the device emulation (which in turn was/could be set by the guest OS).
+ */
+ rc = drvAudioGstOutInit(pGstStrmOut, pHstStrmOut, pszName, pCfg);
if (RT_SUCCESS(rc))
{
- if (pcbWritten)
- *pcbWritten = cbWritten;
+ RTListPrepend(&pHstStrmOut->lstGstStrmOut, &pGstStrmOut->Node);
+
+ if (ppGstStrmOut)
+ *ppGstStrmOut = pGstStrmOut;
}
+ if (RT_FAILURE(rc))
+ drvAudioDestroyGstOut(pThis, pGstStrmOut);
+
+ LogFlowFuncLeaveRC(rc);
return rc;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamRetain}
- */
-static DECLCALLBACK(uint32_t) drvAudioStreamRetain(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+static int drvAudioCreateStreamPairIn(PDRVAUDIO pThis, const char *pszName, PDMAUDIORECSOURCE enmRecSource,
+ PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
{
- AssertPtrReturn(pInterface, UINT32_MAX);
- AssertPtrReturn(pStream, UINT32_MAX);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- NOREF(pInterface);
+ /*
+ * Try figuring out which audio stream configuration this backend
+ * should use for the audio input data. If fixed input is enabled
+ * the backend will be tied to a fixed rate (in Hz, among other parameters),
+ * regardless of what the backend initially wanted to use.
+ */
+ PPDMAUDIOSTREAMCFG pBackendCfg;
+ if (conf.fixed_in.enabled)
+ pBackendCfg = &conf.fixed_in.settings;
+ else
+ pBackendCfg = pCfg;
- return ++pStream->cRefs;
-}
+ AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamRelease}
- */
-static DECLCALLBACK(uint32_t) drvAudioStreamRelease(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, UINT32_MAX);
- AssertPtrReturn(pStream, UINT32_MAX);
+ LogFlowFunc(("Using fixed audio input settings: %RTbool\n",
+ RT_BOOL(conf.fixed_in.enabled)));
+
+ PPDMAUDIOGSTSTRMIN pGstStrmIn = (PPDMAUDIOGSTSTRMIN)RTMemAllocZ(sizeof(PDMAUDIOGSTSTRMIN));
+ if (!pGstStrmIn)
+ return VERR_NO_MEMORY;
- NOREF(pInterface);
+ /*
+ * The host stream always will get the backend audio stream configuration.
+ */
+ PPDMAUDIOHSTSTRMIN pHstStrmIn;
+ int rc = drvAudioHstInAdd(pThis, pszName, pBackendCfg, enmRecSource, &pHstStrmIn);
+ if (RT_FAILURE(rc))
+ {
+ LogFunc(("Failed to add host audio input stream \"%s\", rc=%Rrc\n", pszName, rc));
- if (pStream->cRefs > 1) /* 1 reference always is kept by this audio driver. */
- pStream->cRefs--;
+ RTMemFree(pGstStrmIn);
+ return rc;
+ }
- return pStream->cRefs;
+ /*
+ * The guest stream always will get the audio stream configuration told
+ * by the device emulation (which in turn was/could be set by the guest OS).
+ */
+ rc = drvAudioGstInInit(pGstStrmIn, pHstStrmIn, pszName, pCfg);
+ if (RT_SUCCESS(rc))
+ {
+ pHstStrmIn->pGstStrmIn = pGstStrmIn;
+
+ if (ppGstStrmIn)
+ *ppGstStrmIn = pGstStrmIn;
+ }
+ else
+ drvAudioDestroyGstIn(pThis, pGstStrmIn);
+
+ LogFlowFuncLeaveRC(rc);
+ return rc;
}
/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamIterate}
+ * Initializes a guest input stream.
+ *
+ * @return IPRT status code.
+ * @param pGstStrmIn Pointer to guest stream to initialize.
+ * @param pHstStrmIn Pointer to host input stream to associate this guest
+ * stream with.
+ * @param pszName Pointer to stream name to use for this stream.
+ * @param pCfg Pointer to stream configuration to use.
*/
-static DECLCALLBACK(int) drvAudioStreamIterate(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+int drvAudioGstInInit(PPDMAUDIOGSTSTRMIN pGstStrmIn, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcData is optional. */
+ AssertPtrReturn(pGstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+ int rc = DrvAudioStreamCfgToProps(pCfg, &pGstStrmIn->Props);
+ if (RT_SUCCESS(rc))
+ {
+ char *pszTemp;
+ if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
+ return VERR_NO_MEMORY;
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
+ rc = AudioMixBufInit(&pGstStrmIn->MixBuf, pszTemp, &pGstStrmIn->Props, AudioMixBufSize(&pHstStrmIn->MixBuf));
+ if (RT_SUCCESS(rc))
+ rc = AudioMixBufLinkTo(&pHstStrmIn->MixBuf, &pGstStrmIn->MixBuf);
- rc = drvAudioStreamIterateInternal(pThis, pStream);
+ RTStrFree(pszTemp);
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
+ if (RT_SUCCESS(rc))
+ {
+#ifdef DEBUG
+ drvAudioStreamCfgPrint(pCfg);
+#endif
+ pGstStrmIn->State.cRefs = 1;
+ pGstStrmIn->State.fActive = false;
+ pGstStrmIn->State.fEmpty = true;
- if (RT_FAILURE(rc))
- LogFlowFuncLeaveRC(rc);
+ pGstStrmIn->State.pszName = RTStrDup(pszName);
+ if (!pGstStrmIn->State.pszName)
+ return VERR_NO_MEMORY;
+ pGstStrmIn->pHstStrmIn = pHstStrmIn;
+ }
+ }
+
+ LogFlowFunc(("pszName=%s, rc=%Rrc\n", pszName, rc));
return rc;
}
-/**
- * Does one iteration of an audio stream.
- * This function gives the backend the chance of iterating / altering data and
- * does the actual mixing between the guest <-> host mixing buffers.
- *
- * @returns IPRT status code.
- * @param pThis Pointer to driver instance.
- * @param pStream Stream to iterate.
- *
- * @remark
- */
-static int drvAudioStreamIterateInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)
+static int drvAudioAllocHstIn(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg,
+ PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOHSTSTRMIN *ppHstStrmIn)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ if (!pThis->cFreeInputStreams)
+ {
+ LogFlowFunc(("No more input streams free to use, bailing out\n"));
+ return VERR_NO_MORE_HANDLES;
+ }
- if (!pStream)
- return VINF_SUCCESS;
+ /* Validate backend configuration. */
+ if (!pThis->BackendCfg.cbStreamIn)
+ {
+ LogFlowFunc(("Backend input configuration not valid, bailing out\n"));
+ return VERR_INVALID_PARAMETER;
+ }
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- AssertPtr(pHstStream);
- PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
- AssertPtr(pGstStream);
+ PPDMAUDIOHSTSTRMIN pHstStrmIn =
+ (PPDMAUDIOHSTSTRMIN)RTMemAllocZ(pThis->BackendCfg.cbStreamIn);
+ if (!pHstStrmIn)
+ {
+ LogFlowFunc(("Error allocating host innput stream with %RU32 bytes\n",
+ pThis->BackendCfg.cbStreamOut));
+ return VERR_NO_MEMORY;
+ }
int rc;
-
- /* Whether to try closing a pending to close stream. */
- bool fTryClosePending = false;
+ bool fInitialized = false;
do
{
- uint32_t cSamplesMixed = 0;
-
- rc = pThis->pHostDrvAudio->pfnStreamIterate(pThis->pHostDrvAudio, pHstStream);
+ /* Make the acquired configuration the requested configuration by default. */
+ PDMAUDIOSTREAMCFG CfgAcq;
+ memcpy(&CfgAcq, pCfg, sizeof(PDMAUDIOSTREAMCFG));
+
+#ifndef DEBUG
+ LogRel2(("Audio: Requested input format: %RU32Hz, %s, %RU8 %s\n",
+ CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
+ CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
+#endif
+ uint32_t cSamples;
+ rc = pThis->pHostDrvAudio->pfnInitIn(pThis->pHostDrvAudio, pHstStrmIn,
+ pCfg /* pCfgReq */, &CfgAcq /* pCfgAcq */,
+ enmRecSource, &cSamples);
if (RT_FAILURE(rc))
- break;
-
- if (pHstStream->enmDir == PDMAUDIODIR_IN)
{
- /* Has the host captured any samples which were not mixed to the guest side yet? */
- uint32_t cSamplesCaptured = AudioMixBufUsed(&pHstStream->MixBuf);
+ LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
+ break;
+ }
- Log3Func(("[%s] %RU32 samples captured\n", pHstStream->szName, cSamplesCaptured));
+ fInitialized = true;
- if (cSamplesCaptured)
- {
- /* When capturing samples, the guest is the parent while the host is the child.
- * So try mixing not yet mixed host-side samples to the guest-side buffer. */
- rc = AudioMixBufMixToParent(&pHstStream->MixBuf, cSamplesCaptured, &cSamplesMixed);
- if ( RT_SUCCESS(rc)
- && cSamplesMixed)
- {
- Log3Func(("[%s] %RU32 captured samples mixed\n", pHstStream->szName, cSamplesMixed));
- }
- else if (RT_FAILURE(rc))
- {
- if (rc == VERR_BUFFER_OVERFLOW)
- LogRel2(("Audio: Guest input stream '%s' full, expect stuttering audio capture\n", pGstStream->szName));
- else
- LogRel2(("Audio: Mixing to guest input stream '%s' failed: %Rrc\n", pGstStream->szName, rc));
- }
- }
- else
- {
- fTryClosePending = true;
- }
- }
- else if (pHstStream->enmDir == PDMAUDIODIR_OUT)
+ char *pszTemp;
+ if (RTStrAPrintf(&pszTemp, "%s (Host)", pszName) <= 0)
{
- /* When playing samples, the host is the parent while the guest is the child.
- * So try mixing not yet mixed guest-side samples to the host-side buffer. */
- rc = AudioMixBufMixToParent(&pGstStream->MixBuf, AudioMixBufUsed(&pGstStream->MixBuf), &cSamplesMixed);
- if ( RT_SUCCESS(rc)
- && cSamplesMixed)
- {
- Log3Func(("[%s] %RU32 samples mixed, guest has %RU32 samples left (%RU32 live)\n",
- pHstStream->szName, cSamplesMixed,
- AudioMixBufUsed(&pGstStream->MixBuf), AudioMixBufLive(&pGstStream->MixBuf)));
- }
- else if (RT_FAILURE(rc))
- {
- if (rc == VERR_BUFFER_OVERFLOW)
- LogRel2(("Audio: Host output stream '%s' full, expect stuttering audio output\n", pHstStream->szName));
- else
- LogRel2(("Audio: Mixing to host output stream '%s' failed: %Rrc\n", pHstStream->szName, rc));
- }
-
- uint32_t cSamplesLeft = AudioMixBufUsed(&pGstStream->MixBuf);
- if (!cSamplesLeft) /* No samples (anymore)? */
- {
- fTryClosePending = true;
- }
+ rc = VERR_NO_MEMORY;
+ break;
}
- else
- AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
- if (fTryClosePending)
+#ifdef DEBUG
+ LogFunc(("%s: Requested format:\n", pszTemp));
+ drvAudioStreamCfgPrint(pCfg);
+ LogFunc(("%s: Acquired format:\n", pszTemp));
+ drvAudioStreamCfgPrint(&CfgAcq);
+#else
+ LogRel2(("Audio: Acquired input format for '%s': %RU32Hz, %s, %RU8 %s\n",
+ pszTemp, CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
+ CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
+#endif
+ rc = DrvAudioStreamCfgToProps(&CfgAcq, &pHstStrmIn->Props);
+ if (RT_SUCCESS(rc))
{
- /* Has the host stream marked as disabled but there still were guest streams relying
- * on it? Check if the stream now can be closed and do so, if possible. */
- if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
+ rc = AudioMixBufInit(&pHstStrmIn->MixBuf, pszTemp, &pHstStrmIn->Props, cSamples);
+ if (RT_SUCCESS(rc))
+ rc = RTCritSectInit(&pHstStrmIn->CritSect);
+
+ if (RT_SUCCESS(rc))
{
- LogFunc(("[%s] Closing pending stream\n", pHstStream->szName));
- rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- {
- pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
- }
- else
- LogFunc(("%s: Backend vetoed against closing output stream, rc=%Rrc\n", pHstStream->szName, rc));
+ RTListPrepend(&pThis->lstHstStrmIn, &pHstStrmIn->Node);
+ pThis->cFreeInputStreams--;
}
}
- } while (0);
+ RTStrFree(pszTemp);
- /* Update timestamps. */
- pHstStream->tsLastIterateMS = RTTimeMilliTS();
- pGstStream->tsLastIterateMS = RTTimeMilliTS();
+ } while (0);
if (RT_FAILURE(rc))
- LogFunc(("Failed with %Rrc\n", rc));
+ {
+ if (fInitialized)
+ {
+ int rc2 = pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio,
+ pHstStrmIn);
+ AssertRC(rc2);
+ }
+
+ drvAudioHstInFreeRes(pHstStrmIn);
+ RTMemFree(pHstStrmIn);
+ }
+ else
+ *ppHstStrmIn = pHstStrmIn;
+ LogFlowFuncLeaveRC(rc);
return rc;
}
/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamPlay}
+ * Writes VM audio output data from the guest stream into the host stream.
+ * The attached host driver backend then will play out the audio in a
+ * later step then.
+ *
+ * @return IPRT status code.
+ * @return int
+ * @param pThis
+ * @param pGstStrmOut
+ * @param pvBuf
+ * @param cbBuf
+ * @param pcbWritten
*/
-static DECLCALLBACK(int) drvAudioStreamPlay(PPDMIAUDIOCONNECTOR pInterface,
- PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed)
+static DECLCALLBACK(int) drvAudioWrite(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut,
+ const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcSamplesPlayed is optional. */
-
PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+ AssertPtrReturn(pGstStrmOut, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
+ /* pcbWritten is optional. */
int rc = RTCritSectEnter(&pThis->CritSect);
if (RT_FAILURE(rc))
return rc;
- AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT,
- ("Stream '%s' is not an output stream and therefore cannot be played back (direction is 0x%x)\n",
- pStream->szName, pStream->enmDir));
+ if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
+ {
+ rc = RTCritSectLeave(&pThis->CritSect);
+ AssertRC(rc);
+
+ return VERR_NOT_AVAILABLE;
+ }
- uint32_t cSamplesPlayed = 0;
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- do
+ AssertMsg(pGstStrmOut->pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
+ ("Writing to disabled host output stream \"%s\" not possible\n",
+ pHstStrmOut->MixBuf.pszName));
+
+ if (!AudioMixBufFreeBytes(&pGstStrmOut->MixBuf))
{
- if (!pThis->pHostDrvAudio)
- {
- rc = VERR_NOT_AVAILABLE;
- break;
- }
+ if (pcbWritten)
+ *pcbWritten = 0;
+
+ return RTCritSectLeave(&pThis->CritSect);
+ }
+
+ /*
+ * First, write data from the device emulation into our
+ * guest mixing buffer.
+ */
+ uint32_t cWritten;
+ rc = AudioMixBufWriteAt(&pGstStrmOut->MixBuf, 0 /* Offset in samples */, pvBuf, cbBuf, &cWritten);
+
+ /*
+ * Second, mix the guest mixing buffer with the host mixing
+ * buffer so that the host backend can play the data lateron.
+ */
+ uint32_t cMixed;
+ if ( RT_SUCCESS(rc)
+ && cWritten)
+ {
+ rc = AudioMixBufMixToParent(&pGstStrmOut->MixBuf, cWritten, &cMixed);
+ }
+ else
+ cMixed = 0;
+
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Return the number of samples which actually have been mixed
+ * down to the parent, regardless how much samples were written
+ * into the children buffer.
+ */
+ if (pcbWritten)
+ *pcbWritten = AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cMixed);
+ }
+
+ LogFlowFunc(("%s -> %s: Written pvBuf=%p, cbBuf=%RU32, cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
+ pGstStrmOut->MixBuf.pszName, pHstStrmOut->MixBuf.pszName, pvBuf, cbBuf, cWritten,
+ AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cWritten), cMixed, rc));
+
+ int rc2 = RTCritSectLeave(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+
+ return rc;
+}
+
+PPDMAUDIOHSTSTRMOUT drvAudioFindAnyHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+ if (pHstStrmOut)
+ {
+ if (RTListNodeIsLast(&pThis->lstHstStrmOut, &pHstStrmOut->Node))
+ return NULL;
+
+ return RTListNodeGetNext(&pHstStrmOut->Node, PDMAUDIOHSTSTRMOUT, Node);
+ }
+
+ return RTListGetFirst(&pThis->lstHstStrmOut, PDMAUDIOHSTSTRMOUT, Node);
+}
+
+PPDMAUDIOHSTSTRMOUT drvAudioHstFindAnyEnabledOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHostStrmOut)
+{
+ while ((pHostStrmOut = drvAudioFindAnyHstOut(pThis, pHostStrmOut)))
+ {
+ if (pHostStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
+ return pHostStrmOut;
+ }
- /* Backend output (temporarily) disabled / unavailable? */
- if ( pThis->pHostDrvAudio->pfnGetStatus
- && pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_OUT) != PDMAUDIOBACKENDSTS_RUNNING)
+ return NULL;
+}
+
+PPDMAUDIOHSTSTRMOUT drvAudioFindSpecificOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PPDMAUDIOSTREAMCFG pCfg)
+{
+ while ((pHstStrmOut = drvAudioFindAnyHstOut(pThis, pHstStrmOut)))
+ {
+ if (drvAudioPCMPropsAreEqual(&pHstStrmOut->Props, pCfg))
+ return pHstStrmOut;
+ }
+
+ return NULL;
+}
+
+int drvAudioDestroyHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+ LogFlowFunc(("%s\n", pHstStrmIn->MixBuf.pszName));
+
+ int rc;
+ if (!pHstStrmIn->pGstStrmIn) /* No parent anymore? */
+ {
+ rc = pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio, pHstStrmIn);
+ if (RT_SUCCESS(rc))
{
- /* Pull the new config from the backend and check again. */
- rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
- AssertRC(rc);
+ drvAudioHstInFreeRes(pHstStrmIn);
- if ( !pThis->BackendCfg.cSinks
- || !pThis->BackendCfg.cMaxStreamsOut)
+ if (RTCritSectIsInitialized(&pHstStrmIn->CritSect))
{
- rc = VERR_NOT_AVAILABLE;
- break;
+ int rc2 = RTCritSectDelete(&pHstStrmIn->CritSect);
+ AssertRC(rc2);
}
+
+ /* Remove from driver instance list. */
+ RTListNodeRemove(&pHstStrmIn->Node);
+
+ RTMemFree(pHstStrmIn);
+ pThis->cFreeInputStreams++;
}
+ }
+ else
+ {
+ rc = VERR_ACCESS_DENIED;
+ LogFlowFunc(("[%s] Still is being used, rc=%Rrc\n", pHstStrmIn->MixBuf.pszName, rc));
+ }
+
+ return rc;
+}
+
+static int drvAudioDestroyGstIn(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMIN pGstStrmIn)
+{
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+
+ LogFlowFunc(("%s\n", pGstStrmIn->MixBuf.pszName));
+
+ if (!pGstStrmIn)
+ return VINF_SUCCESS;
+
+ if (pGstStrmIn->State.cRefs > 1) /* Do other objects still have a reference to it? Bail out. */
+ return VERR_WRONG_ORDER;
+
+ drvAudioGstInFreeRes(pGstStrmIn);
+
+ if (pGstStrmIn->pHstStrmIn)
+ {
+ /* Unlink child. */
+ pGstStrmIn->pHstStrmIn->pGstStrmIn = NULL;
+
+ /* Try destroying the associated host input stream. This could
+ * be skipped if there are other guest input streams with this
+ * host stream. */
+ drvAudioDestroyHstIn(pThis, pGstStrmIn->pHstStrmIn);
+ }
+
+ RTMemFree(pGstStrmIn);
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvAudioQueryStatus(PPDMIAUDIOCONNECTOR pInterface,
+ uint32_t *pcbAvailIn, uint32_t *pcbFreeOut,
+ uint32_t *pcSamplesLive)
+{
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ /* pcbAvailIn is optional. */
+ /* pcbFreeOut is optional. */
+ /* pcSamplesLive is optional. */
+
+ PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- AssertPtr(pHstStream);
- PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : NULL;
- AssertPtr(pGstStream);
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
- AssertReleaseMsgBreakStmt(pHstStream != NULL,
- ("%s: Host stream is NULL (cRefs=%RU32, fStatus=%x, enmCtx=%ld)\n",
- pStream->szName, pStream->cRefs, pStream->fStatus, pStream->enmCtx),
- rc = VERR_NOT_AVAILABLE);
- AssertReleaseMsgBreakStmt(pGstStream != NULL,
- ("%s: Guest stream is NULL (cRefs=%RU32, fStatus=%x, enmCtx=%ld)\n",
- pStream->szName, pStream->cRefs, pStream->fStatus, pStream->enmCtx),
- rc = VERR_NOT_AVAILABLE);
+ /*
+ * Playback.
+ */
+ uint32_t cSamplesLive = 0;
+ uint32_t cbFreeOut = UINT32_MAX;
- AssertPtr(pThis->pHostDrvAudio->pfnStreamGetStatus);
- PDMAUDIOSTRMSTS stsBackend = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+ while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
+ {
+ cSamplesLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
- if (!(stsBackend & PDMAUDIOSTRMSTS_FLAG_INITIALIZED))
+ /* Has this stream marked as disabled but there still were guest streams relying
+ * on it? Check if this stream now can be closed and do so, if possible. */
+ if ( (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
+ && !cSamplesLive)
{
- LogFunc(("[%s] Backend not initialized (anymore), re-initializing ...\n", pHstStream->szName));
- rc = drvAudioStreamReInitInternal(pThis, pStream);
- if (RT_FAILURE(rc))
+ /* Stop playing the current (pending) stream. */
+ int rc2 = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+ if (RT_SUCCESS(rc2))
{
- LogFunc(("[%s] Failed to re-initialize backend, rc=%Rrc\n", pHstStream->szName, rc));
- break;
+ pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+
+ LogFunc(("[%s] Disabling stream\n", pHstStrmOut->MixBuf.pszName));
}
+ else
+ LogFunc(("[%s] Backend vetoed against closing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc2));
+
+ continue;
}
- uint32_t cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
- if (cSamplesLive)
+ LogFlowFunc(("[%s] cSamplesLive=%RU32\n", pHstStrmOut->MixBuf.pszName, cSamplesLive));
+
+ /*
+ * No live samples to play at the moment?
+ *
+ * Tell the device emulation for each connected guest stream how many
+ * bytes are free so that the device emulation can continue writing data to
+ * these streams.
+ */
+ PPDMAUDIOGSTSTRMOUT pGstStrmOut;
+ uint32_t cbFree2 = UINT32_MAX;
+ RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
{
- if ( (stsBackend & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- && (stsBackend & PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE))
+ if (pGstStrmOut->State.fActive)
{
- AssertPtr(pThis->pHostDrvAudio->pfnStreamPlay);
- rc = pThis->pHostDrvAudio->pfnStreamPlay(pThis->pHostDrvAudio, pHstStream, NULL /* pvBuf */, 0 /* cbBuf */,
- &cSamplesPlayed);
- if (RT_FAILURE(rc))
- {
- int rc2 = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
- AssertRC(rc2);
- }
- else
- {
-#ifdef VBOX_WITH_STATISTICS
- STAM_COUNTER_ADD(&pThis->Stats.TotalSamplesPlayed, cSamplesPlayed);
- STAM_COUNTER_ADD(&pHstStream->Out.StatSamplesPlayed, cSamplesPlayed);
+ /* Tell the sound device emulation how many samples are free
+ * so that it can start writing PCM data to us. */
+ cbFree2 = RT_MIN(cbFree2, AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf,
+ AudioMixBufFree(&pGstStrmOut->MixBuf)));
+#ifdef DEBUG_andy
+ LogFlowFunc(("\t[%s] cbFreeOut=%RU32\n", pGstStrmOut->MixBuf.pszName, cbFree2));
#endif
- cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
- }
}
}
- if (!cSamplesLive)
+ cbFreeOut = RT_MIN(cbFreeOut, cbFree2);
+ }
+
+ /*
+ * Recording.
+ */
+ uint32_t cbAvailIn = 0;
+
+ PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
+ while ((pHstStrmIn = drvAudioFindNextEnabledHstIn(pThis, pHstStrmIn)))
+ {
+ /* Call the host backend to capture the audio input data. */
+ uint32_t cSamplesCaptured;
+ int rc2 = pThis->pHostDrvAudio->pfnCaptureIn(pThis->pHostDrvAudio, pHstStrmIn,
+ &cSamplesCaptured);
+ if (RT_FAILURE(rc2))
+ continue;
+
+ PPDMAUDIOGSTSTRMIN pGstStrmIn = pHstStrmIn->pGstStrmIn;
+ AssertPtrBreak(pGstStrmIn);
+
+ if (pGstStrmIn->State.fActive)
{
- /* Has the host stream marked as disabled but there still were guest streams relying
- * on it? Check if the stream now can be closed and do so, if possible. */
- if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
- {
- LogFunc(("[%s] Closing pending stream\n", pHstStream->szName));
- rc = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- {
- pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
- }
- else
- LogFunc(("[%s] Backend vetoed against closing output stream, rc=%Rrc\n", pHstStream->szName, rc));
- }
+ cbAvailIn = RT_MAX(cbAvailIn, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf,
+ AudioMixBufMixed(&pHstStrmIn->MixBuf)));
+#ifdef DEBUG_andy
+ LogFlowFunc(("\t[%s] cbAvailIn=%RU32\n", pHstStrmIn->MixBuf.pszName, cbAvailIn));
+#endif
}
+ }
- } while (0);
+ if (RT_SUCCESS(rc))
+ {
+ if (cbFreeOut == UINT32_MAX)
+ cbFreeOut = 0;
+
+ if (pcbAvailIn)
+ *pcbAvailIn = cbAvailIn;
+
+ if (pcbFreeOut)
+ *pcbFreeOut = cbFreeOut;
+
+ if (pcSamplesLive)
+ *pcSamplesLive = cSamplesLive;
+ }
int rc2 = RTCritSectLeave(&pThis->CritSect);
if (RT_SUCCESS(rc))
rc = rc2;
- if (RT_SUCCESS(rc))
- {
- if (pcSamplesPlayed)
- *pcSamplesPlayed = cSamplesPlayed;
- }
-
if (RT_FAILURE(rc))
- LogFlowFunc(("[%s] Failed with %Rrc\n", pStream->szName, rc));
+ LogFlowFuncLeaveRC(rc);
return rc;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamCapture}
- */
-static DECLCALLBACK(int) drvAudioStreamCapture(PPDMIAUDIOCONNECTOR pInterface,
- PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesCaptured)
+static DECLCALLBACK(int) drvAudioPlayOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed)
{
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ /* pcSamplesPlayed is optional. */
+
PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
int rc = RTCritSectEnter(&pThis->CritSect);
if (RT_FAILURE(rc))
return rc;
- AssertMsg(pStream->enmDir == PDMAUDIODIR_IN,
- ("Stream '%s' is not an input stream and therefore cannot be captured (direction is 0x%x)\n",
- pStream->szName, pStream->enmDir));
+ /* Backend output (temporarily) disabled / unavailable? */
+ if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
+ {
+ rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
+ AssertRC(rc);
- Log3Func(("[%s]\n", pStream->szName));
+ if (!pThis->BackendCfg.cMaxHstStrmsOut)
+ {
+ int rc2 = RTCritSectLeave(&pThis->CritSect);
+ AssertRC(rc2);
- uint32_t cSamplesCaptured = 0;
+ return VERR_NOT_AVAILABLE;
+ }
+ }
- do
+ /*
+ * Process all enabled host output streams.
+ */
+ uint32_t cSamplesPlayedMax = 0;
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+ while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
{
- /* Backend input (temporarily) disabled / unavailable? */
- if (pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
+#if 0
+ uint32_t cStreamsLive;
+ uint32_t cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive);
+ if (!cStreamsLive)
+ cSamplesLive = 0;
+
+ /* Has this stream marked as disabled but there still were guest streams relying
+ * on it? Check if this stream now can be closed and do so, if possible. */
+ if ( pHstStrmOut->fPendingDisable
+ && !cStreamsLive)
{
- rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
- AssertRC(rc);
-
- if ( !pThis->BackendCfg.cSources
- || !pThis->BackendCfg.cMaxStreamsIn)
+ /* Stop playing the current (pending) stream. */
+ int rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut,
+ PDMAUDIOSTREAMCMD_DISABLE);
+ if (RT_SUCCESS(rc2))
{
- rc = VERR_NOT_AVAILABLE;
- break;
+ pHstStrmOut->fEnabled = false;
+ pHstStrmOut->fPendingDisable = false;
+
+ LogFunc(("\t%p: Disabling stream\n", pHstStrmOut));
}
+ else
+ LogFunc(("\t%p: Backend vetoed against closing output stream, rc=%Rrc\n",
+ pHstStrmOut, rc2));
+
+ continue;
}
+#endif
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- AssertPtr(pHstStream);
- PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : NULL;
- AssertPtr(pGstStream);
+ uint32_t cSamplesPlayed = 0;
+ int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut, &cSamplesPlayed);
+ if (RT_FAILURE(rc2))
+ {
+ rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+ AssertRC(rc2);
+ }
+ else
+ cSamplesPlayedMax = RT_MAX(cSamplesPlayed, cSamplesPlayedMax);
- AssertReleaseMsgBreakStmt(pHstStream != NULL,
- ("%s: Host stream is NULL (cRefs=%RU32, fStatus=%x, enmCtx=%ld)\n",
- pStream->szName, pStream->cRefs, pStream->fStatus, pStream->enmCtx),
- rc = VERR_NOT_AVAILABLE);
- AssertReleaseMsgBreakStmt(pGstStream != NULL,
- ("%s: Guest stream is NULL (cRefs=%RU32, fStatus=%x, enmCtx=%ld)\n",
- pStream->szName, pStream->cRefs, pStream->fStatus, pStream->enmCtx),
- rc = VERR_NOT_AVAILABLE);
+ LogFlowFunc(("\t[%s] cSamplesPlayed=%RU32, cSamplesPlayedMax=%RU32, rc=%Rrc\n",
+ pHstStrmOut->MixBuf.pszName, cSamplesPlayed, cSamplesPlayedMax, rc2));
- AssertPtr(pThis->pHostDrvAudio->pfnStreamGetStatus);
- PDMAUDIOSTRMSTS stsBackend = pThis->pHostDrvAudio->pfnStreamGetStatus(pThis->pHostDrvAudio, pHstStream);
+ bool fNeedsCleanup = false;
- if (!(stsBackend & PDMAUDIOSTRMSTS_FLAG_INITIALIZED))
+ PPDMAUDIOGSTSTRMOUT pGstStrmOut;
+ RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
{
- LogFunc(("[%s] Backend not initialized (anymore), re-initializing ...\n", pHstStream->szName));
- rc = drvAudioStreamReInitInternal(pThis, pStream);
- break;
+ if ( !pGstStrmOut->State.fActive
+ && pGstStrmOut->State.fEmpty)
+ continue;
+
+ if (AudioMixBufIsEmpty(&pGstStrmOut->MixBuf))
+ {
+ pGstStrmOut->State.fEmpty = true;
+ fNeedsCleanup |= !pGstStrmOut->State.fActive;
+ }
}
- uint32_t cSamplesLive = AudioMixBufLive(&pGstStream->MixBuf);
- if (!cSamplesLive)
+ if (fNeedsCleanup)
{
- if ( (stsBackend & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- && (stsBackend & PDMAUDIOSTRMSTS_FLAG_DATA_READABLE))
+ RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
{
- rc = pThis->pHostDrvAudio->pfnStreamCapture(pThis->pHostDrvAudio, pHstStream, NULL /* pvBuf */, 0 /* cbBuf */,
- &cSamplesCaptured);
- if (RT_FAILURE(rc))
- {
- int rc2 = drvAudioStreamControlInternalBackend(pThis, pHstStream, PDMAUDIOSTREAMCMD_DISABLE);
- AssertRC(rc2);
- }
- else
- {
-#ifdef VBOX_WITH_STATISTICS
- STAM_COUNTER_ADD(&pHstStream->In.StatSamplesCaptured, cSamplesCaptured);
-#endif
- }
+ if (!pGstStrmOut->State.fActive)
+ drvAudioDestroyGstOut(pThis, pGstStrmOut);
}
-
- Log3Func(("[%s] strmSts=0x%x, cSamplesCaptured=%RU32, rc=%Rrc\n", pHstStream->szName, stsBackend, cSamplesCaptured, rc));
}
-
- } while (0);
+ }
if (RT_SUCCESS(rc))
{
- if (pcSamplesCaptured)
- *pcSamplesCaptured = cSamplesCaptured;
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = cSamplesPlayedMax;
}
int rc2 = RTCritSectLeave(&pThis->CritSect);
@@ -1233,16 +1614,8 @@ static DECLCALLBACK(int) drvAudioStreamCapture(PPDMIAUDIOCONNECTOR pInterface,
}
#ifdef VBOX_WITH_AUDIO_CALLBACKS
-/**
- * Duplicates an audio callback.
- *
- * @returns Pointer to duplicated callback, or NULL on failure.
- * @param pCB Callback to duplicate.
- */
static PPDMAUDIOCALLBACK drvAudioCallbackDuplicate(PPDMAUDIOCALLBACK pCB)
{
- AssertPtrReturn(pCB, VERR_INVALID_POINTER);
-
PPDMAUDIOCALLBACK pCBCopy = (PPDMAUDIOCALLBACK)RTMemDup((void *)pCB, sizeof(PDMAUDIOCALLBACK));
if (!pCBCopy)
return NULL;
@@ -1262,11 +1635,6 @@ static PPDMAUDIOCALLBACK drvAudioCallbackDuplicate(PPDMAUDIOCALLBACK pCB)
return pCBCopy;
}
-/**
- * Destroys a given callback.
- *
- * @param pCB Callback to destroy.
- */
static void drvAudioCallbackDestroy(PPDMAUDIOCALLBACK pCB)
{
if (!pCB)
@@ -1281,9 +1649,6 @@ static void drvAudioCallbackDestroy(PPDMAUDIOCALLBACK pCB)
RTMemFree(pCB);
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnRegisterCallbacks}
- */
static DECLCALLBACK(int) drvAudioRegisterCallbacks(PPDMIAUDIOCONNECTOR pInterface,
PPDMAUDIOCALLBACK paCallbacks, size_t cCallbacks)
{
@@ -1331,9 +1696,6 @@ static DECLCALLBACK(int) drvAudioRegisterCallbacks(PPDMIAUDIOCONNECTOR pInterfac
return rc;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnCallback}
- */
static DECLCALLBACK(int) drvAudioCallback(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIOCALLBACKTYPE enmType,
void *pvUser, size_t cbUser)
{
@@ -1386,10 +1748,10 @@ static DECLCALLBACK(int) drvAudioCallback(PPDMIAUDIOCONNECTOR pInterface, PDMAUD
* @param pThis Driver instance to be called.
* @param pCfgHandle CFGM configuration handle to use for this driver.
*/
-static int drvAudioHostInit(PDRVAUDIO pThis, PCFGMNODE pCfgHandle)
+static int drvAudioHostInit(PCFGMNODE pCfgHandle, PDRVAUDIO pThis)
{
/* pCfgHandle is optional. */
- NOREF(pCfgHandle);
+ RT_NOREF(pCfgHandle);
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
LogFlowFuncEnter();
@@ -1398,51 +1760,57 @@ static int drvAudioHostInit(PDRVAUDIO pThis, PCFGMNODE pCfgHandle)
int rc = pThis->pHostDrvAudio->pfnInit(pThis->pHostDrvAudio);
if (RT_FAILURE(rc))
{
- LogRel(("Audio: Initialization of host backend failed with %Rrc\n", rc));
+ LogFlowFunc(("Initialization of lower driver failed with rc=%Rrc\n", rc));
return VERR_AUDIO_BACKEND_INIT_FAILED;
}
/* Get the configuration data from backend. */
- rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, &pThis->BackendCfg);
+ rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
if (RT_FAILURE(rc))
{
- LogRel(("Audio: Getting host backend configuration failed with %Rrc\n", rc));
+ LogFlowFunc(("Getting backend configuration failed with rc=%Rrc\n", rc));
return VERR_AUDIO_BACKEND_INIT_FAILED;
}
- pThis->cStreamsFreeIn = 0;
- pThis->cStreamsFreeOut = 0;
+ uint32_t cMaxHstStrmsOut = pThis->BackendCfg.cMaxHstStrmsOut;
+ size_t cbHstStrmsOut = pThis->BackendCfg.cbStreamOut;
- if (pThis->BackendCfg.cSinks)
+ if (cbHstStrmsOut)
{
- Assert(pThis->BackendCfg.cbStreamOut);
-
- pThis->cStreamsFreeOut = pThis->BackendCfg.cMaxStreamsOut;
+ pThis->cFreeOutputStreams = cMaxHstStrmsOut;
}
+ else
+ pThis->cFreeOutputStreams = 0;
- if (pThis->BackendCfg.cSources)
- {
- Assert(pThis->BackendCfg.cbStreamIn);
+ uint32_t cMaxHstStrmsIn = pThis->BackendCfg.cMaxHstStrmsIn;
+ size_t cbHstStrmIn = pThis->BackendCfg.cbStreamIn;
- pThis->cStreamsFreeIn = pThis->BackendCfg.cMaxStreamsIn;
+ if (cbHstStrmIn)
+ {
+ /*
+ * Note:
+ * - Our AC'97 emulation has two inputs, line (ac97.pi) and microphone (ac97.mc).
+ * - Our HDA emulation currently has only line input (hda.pi).
+ */
+ pThis->cFreeInputStreams = cMaxHstStrmsIn;
}
+ else
+ pThis->cFreeInputStreams = 0;
+
+ LogFlowFunc(("cMaxHstStrmsOut=%RU32 (cb=%zu), cMaxHstStrmsIn=%RU32 (cb=%zu)\n",
+ cMaxHstStrmsOut, cbHstStrmsOut, cMaxHstStrmsIn, cbHstStrmIn));
- LogFlowFunc(("cStreamsFreeIn=%RU8, cStreamsFreeOut=%RU8\n", pThis->cStreamsFreeIn, pThis->cStreamsFreeOut));
+ LogFlowFunc(("cFreeInputStreams=%RU8, cFreeOutputStreams=%RU8\n",
+ pThis->cFreeInputStreams, pThis->cFreeOutputStreams));
- LogRel2(("Audio: Host audio backend supports %RU32 input streams and %RU32 output streams at once\n",
- /* Clamp for logging. Unlimited streams are defined by UINT32_MAX. */
- RT_MIN(64, pThis->cStreamsFreeIn), RT_MIN(64, pThis->cStreamsFreeOut)));
+ LogRel(("Audio: Host audio backend supports %RU32 output streams and %RU32 input streams at once\n",
+ /* Clamp for logging. Unlimited streams are defined by UINT32_MAX. */
+ RT_MIN(64, cMaxHstStrmsOut), RT_MIN(64, cMaxHstStrmsIn)));
LogFlowFuncLeave();
return VINF_SUCCESS;
}
-/**
- * Handles state changes for all audio streams.
- *
- * @param pDrvIns Pointer to driver instance.
- * @param enmCmd Stream command to set for all streams.
- */
static void drvAudioStateHandler(PPDMDRVINS pDrvIns, PDMAUDIOSTREAMCMD enmCmd)
{
PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
@@ -1453,146 +1821,275 @@ static void drvAudioStateHandler(PPDMDRVINS pDrvIns, PDMAUDIOSTREAMCMD enmCmd)
if (!pThis->pHostDrvAudio)
return;
- PPDMAUDIOSTREAM pHstStream;
- RTListForEach(&pThis->lstHstStreams, pHstStream, PDMAUDIOSTREAM, Node)
- drvAudioStreamControlInternalBackend(pThis, pHstStream, enmCmd);
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+ while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
+ drvAudioControlHstOut(pThis, pHstStrmOut, enmCmd);
+
+ PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
+ while ((pHstStrmIn = drvAudioFindNextEnabledHstIn(pThis, pHstStrmIn)))
+ drvAudioControlHstIn(pThis, pHstStrmIn, enmCmd);
}
-/**
- * Intializes an audio driver instance.
- *
- * @returns IPRT status code.
- * @param pDrvIns Pointer to driver instance.
- * @param pCfgHandle CFGM handle to use for configuration.
- */
-static int drvAudioInit(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
+static struct audio_option audio_options[] =
+{
+ /* DAC */
+ {"DACFixedSettings", AUD_OPT_BOOL, &conf.fixed_out.enabled,
+ "Use fixed settings for host DAC", NULL, 0},
+
+ {"DACFixedFreq", AUD_OPT_INT, &conf.fixed_out.settings.uHz,
+ "Frequency for fixed host DAC", NULL, 0},
+
+ {"DACFixedFmt", AUD_OPT_FMT, &conf.fixed_out.settings.enmFormat,
+ "Format for fixed host DAC", NULL, 0},
+
+ {"DACFixedChannels", AUD_OPT_INT, &conf.fixed_out.settings.cChannels,
+ "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
+
+ {"DACVoices", AUD_OPT_INT, &conf.fixed_out.cStreams, /** @todo Rename! */
+ "Number of streams for DAC", NULL, 0},
+
+ /* ADC */
+ {"ADCFixedSettings", AUD_OPT_BOOL, &conf.fixed_in.enabled,
+ "Use fixed settings for host ADC", NULL, 0},
+
+ {"ADCFixedFreq", AUD_OPT_INT, &conf.fixed_in.settings.uHz,
+ "Frequency for fixed host ADC", NULL, 0},
+
+ {"ADCFixedFmt", AUD_OPT_FMT, &conf.fixed_in.settings.enmFormat,
+ "Format for fixed host ADC", NULL, 0},
+
+ {"ADCFixedChannels", AUD_OPT_INT, &conf.fixed_in.settings.cChannels,
+ "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
+
+ {"ADCVoices", AUD_OPT_INT, &conf.fixed_in.cStreams, /** @todo Rename! */
+ "Number of streams for ADC", NULL, 0},
+
+ /* Misc */
+ {"TimerFreq", AUD_OPT_INT, &conf.period.hz,
+ "Timer frequency in Hz (0 - use lowest possible)", NULL, 0},
+
+ {"PLIVE", AUD_OPT_BOOL, &conf.plive,
+ "(undocumented)", NULL, 0}, /** @todo What is this? */
+
+ {NULL, AUD_OPT_INT, NULL, NULL, NULL, 0}
+};
+
+static DECLCALLBACK(int) drvAudioInit(PCFGMNODE pCfgHandle, PPDMDRVINS pDrvIns)
{
AssertPtrReturn(pCfgHandle, VERR_INVALID_POINTER);
- AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
+ AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
- LogRel2(("Audio: Verbose logging enabled\n"));
+ LogRel(("Audio: Using VBox 5.0.x audio code!\n"));
PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
- LogFlowFunc(("pThis=%p, pDrvIns=%p\n", pThis, pDrvIns));
+ LogFlowFunc(("pDrvAudio=%p, pDrvIns=%p\n", pThis, pDrvIns));
+
+ RTListInit(&pThis->lstHstStrmIn);
+ RTListInit(&pThis->lstHstStrmOut);
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+ RTListInit(&pThis->lstCBIn);
+ RTListInit(&pThis->lstCBOut);
+#endif
int rc = RTCritSectInit(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ {
+ rc = drvAudioProcessOptions(pCfgHandle, "AUDIO", audio_options);
+ /** @todo Check for invalid options? */
+
+ pThis->cFreeOutputStreams = conf.fixed_out.cStreams;
+ pThis->cFreeInputStreams = conf.fixed_in.cStreams;
- /** @todo Add audio driver options. */
+ if (!pThis->cFreeOutputStreams)
+ pThis->cFreeOutputStreams = 1;
+
+ if (!pThis->cFreeInputStreams)
+ pThis->cFreeInputStreams = 1;
+ }
/*
* If everything went well, initialize the lower driver.
*/
if (RT_SUCCESS(rc))
- rc = drvAudioHostInit(pThis, pCfgHandle);
+ rc = drvAudioHostInit(pCfgHandle, pThis);
LogFlowFuncLeaveRC(rc);
return rc;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamRead}
- */
-static DECLCALLBACK(int) drvAudioStreamRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream,
- void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static DECLCALLBACK(int) drvAudioRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn,
+ void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
{
PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- if (!pStream)
+ AssertPtrReturn(pGstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
+ AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
+ /* pcbWritten is optional. */
+
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_IN))
{
if (pcbRead)
*pcbRead = 0;
- return VINF_SUCCESS;
+
+ return RTCritSectLeave(&pThis->CritSect);
}
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
- /* pcbWritten is optional. */
+ PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- AssertMsg(pStream->enmDir == PDMAUDIODIR_IN,
- ("Stream '%s' is not an input stream and therefore cannot be read from (direction is 0x%x)\n",
- pStream->szName, pStream->enmDir));
+ AssertMsg(pGstStrmIn->pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
+ ("Reading from disabled host input stream \"%s\" not possible\n", pGstStrmIn->MixBuf.pszName));
- uint32_t cbRead = 0;
+ /*
+ * Read from the parent buffer (that is, the guest buffer) which
+ * should have the audio data in the format the guest needs.
+ */
+ uint32_t cRead;
+ rc = AudioMixBufReadCirc(&pGstStrmIn->MixBuf, pvBuf, cbBuf, &cRead);
+ if (RT_SUCCESS(rc))
+ {
+ AudioMixBufFinish(&pGstStrmIn->MixBuf, cRead);
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
+ if (pcbRead)
+ *pcbRead = AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead);
+ }
- do
- {
- if ( pThis->pHostDrvAudio
- && pThis->pHostDrvAudio->pfnGetStatus
- && pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, PDMAUDIODIR_IN) != PDMAUDIOBACKENDSTS_RUNNING)
- {
- rc = VERR_NOT_AVAILABLE;
- break;
- }
+ LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
+ cRead, AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead), rc));
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- if (!pHstStream)
- {
- rc = VERR_NOT_AVAILABLE;
- break;
- }
+ int rc2 = RTCritSectLeave(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+
+ return rc;
+}
+
+static DECLCALLBACK(int) drvAudioEnableOut(PPDMIAUDIOCONNECTOR pInterface,
+ PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable)
+{
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ /* pGstStrmOut is optional. */
- PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
+ PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
- AssertMsg(pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
- ("Reading from disabled host input stream '%s' not possible\n", pHstStream->szName));
+ int rc = VINF_SUCCESS;
- pGstStream->In.tsLastReadMS = RTTimeMilliTS();
+ if (pGstStrmOut)
+ {
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
+ AssertPtr(pHstStrmOut);
- Log3Func(("%s\n", pStream->szName));
+ if (fEnable)
+ {
+ /* Is a pending disable outstanding? Then disable first. */
+ if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
+ {
+ rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+ if (RT_SUCCESS(rc))
+ pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
+ }
- /*
- * Read from the parent buffer (that is, the guest buffer) which
- * should have the audio data in the format the guest needs.
- */
- uint32_t cRead;
- rc = AudioMixBufReadCirc(&pGstStream->MixBuf, pvBuf, cbBuf, &cRead);
- if (RT_SUCCESS(rc))
+ if (RT_SUCCESS(rc))
+ rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
+ }
+ else /* Disable */
{
- if (cRead)
+ if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
{
-#ifdef VBOX_WITH_STATISTICS
- STAM_COUNTER_ADD(&pThis->Stats.TotalBytesRead, AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead));
- STAM_COUNTER_ADD(&pGstStream->In.StatBytesTotalRead, AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead));
-#endif
- AudioMixBufFinish(&pGstStream->MixBuf, cRead);
+ uint32_t cGstStrmsActive = 0;
+
+ /*
+ * Check if there are any active guest streams assigned
+ * to this host stream which still are being marked as active.
+ *
+ * In that case we have to defer closing the host stream and
+ * wait until all guest streams have been finished.
+ */
+ PPDMAUDIOGSTSTRMOUT pIter;
+ RTListForEach(&pHstStrmOut->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
+ {
+ if (pIter->State.fActive)
+ {
+ cGstStrmsActive++;
+ break; /* At least one assigned & active guest stream is enough. */
+ }
+ }
+
+ /* Do we need to defer closing the host stream? */
+ if (cGstStrmsActive >= 1)
+ pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
- cbRead = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead);
+ /* Can we close the host stream now instead of deferring it? */
+ if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE))
+ rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
}
}
- Log3Func(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n", cRead, AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cRead), rc));
+ if (RT_SUCCESS(rc))
+ pGstStrmOut->State.fActive = fEnable;
- } while (0);
+ LogFlowFunc(("%s: fEnable=%RTbool, fStatus=0x%x, rc=%Rrc\n",
+ pGstStrmOut->MixBuf.pszName, fEnable, pHstStrmOut->fStatus, rc));
+ }
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
+ return rc;
+}
- if (RT_SUCCESS(rc))
+static DECLCALLBACK(int) drvAudioEnableIn(PPDMIAUDIOCONNECTOR pInterface,
+ PPDMAUDIOGSTSTRMIN pGstStrmIn, bool fEnable)
+{
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ /* pGstStrmIn is optional. */
+
+ PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
+
+ int rc = VINF_SUCCESS;
+
+ if (pGstStrmIn)
{
- if (pcbRead)
- *pcbRead = cbRead;
+ PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
+ AssertPtr(pHstStrmIn);
+
+ LogFlowFunc(("%s: fEnable=%RTbool\n", pGstStrmIn->MixBuf.pszName, fEnable));
+
+ rc = drvAudioControlHstIn(pThis, pHstStrmIn,
+ fEnable ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
+ if (RT_SUCCESS(rc))
+ pGstStrmIn->State.fActive = fEnable;
+
+ LogFlowFunc(("%s: fEnable=%RTbool, rc=%Rrc\n", pGstStrmIn->MixBuf.pszName, fEnable, rc));
}
return rc;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface,
- PPDMAUDIOSTREAMCFG pCfgHost, PPDMAUDIOSTREAMCFG pCfgGuest,
- PPDMAUDIOSTREAM *ppStream)
+static DECLCALLBACK(bool) drvAudioIsValidIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgHost, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgGuest, VERR_INVALID_POINTER);
- AssertPtrReturn(ppStream, VERR_INVALID_POINTER);
+ RT_NOREF(pInterface);
+ return (pGstStrmIn != NULL);
+}
+
+static DECLCALLBACK(bool) drvAudioIsValidOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+ RT_NOREF(pInterface);
+ return (pGstStrmOut != NULL);
+}
+
+static DECLCALLBACK(int) drvAudioCreateIn(PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
+ PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg,
+ PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
+{
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppGstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppGstStrmIn, VERR_INVALID_POINTER);
PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
@@ -1600,163 +2097,206 @@ static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface,
if (RT_FAILURE(rc))
return rc;
- LogFlowFunc(("Host=%s, Guest=%s\n", pCfgHost->szName, pCfgGuest->szName));
-#ifdef DEBUG
- DrvAudioHlpStreamCfgPrint(pCfgHost);
- DrvAudioHlpStreamCfgPrint(pCfgGuest);
-#endif
+ LogFlowFunc(("pszName=%s, pCfg=%p\n", pszName, pCfg));
- /*
- * The guest stream always will get the audio stream configuration told
- * by the device emulation (which in turn was/could be set by the guest OS).
- */
- PPDMAUDIOSTREAM pGstStrm = NULL;
+ if (!drvAudioStreamCfgIsValid(pCfg))
+ {
+ LogFunc(("Input stream configuration is not valid, bailing out\n"));
+ rc = VERR_INVALID_PARAMETER;
+ }
+
+ PPDMAUDIOGSTSTRMIN pGstStrmIn = *ppGstStrmIn;
+ if ( RT_SUCCESS(rc)
+ && pGstStrmIn
+ && drvAudioPCMPropsAreEqual(&pGstStrmIn->Props, pCfg))
+ {
+ LogFunc(("[%s] Exists and matches required configuration, skipping creation\n",
+ pGstStrmIn->MixBuf.pszName));
+ rc = VWRN_ALREADY_EXISTS;
+ }
- /** @todo Docs! */
- PPDMAUDIOSTREAM pHstStrm = NULL;
+ if (rc != VINF_SUCCESS) /* Note: Can be VWRN_ALREADY_EXISTS, so don't use VINF_SUCCESS here. */
+ {
+ int rc2 = RTCritSectLeave(&pThis->CritSect);
+ AssertRC(rc2);
-#define RC_BREAK(x) { rc = x; break; }
+ return rc;
+ }
- do
+ if ( !conf.fixed_in.enabled
+ && pGstStrmIn)
{
- if ( !DrvAudioHlpStreamCfgIsValid(pCfgHost)
- || !DrvAudioHlpStreamCfgIsValid(pCfgGuest))
- {
- RC_BREAK(VERR_INVALID_PARAMETER);
- }
+ drvAudioDestroyGstIn(pThis, pGstStrmIn);
+ pGstStrmIn = NULL;
+ }
- /* Make sure that both configurations actually intend the same thing. */
- if (pCfgHost->enmDir != pCfgGuest->enmDir)
- {
- AssertMsgFailed(("Stream configuration directions do not match\n"));
- RC_BREAK(VERR_INVALID_PARAMETER);
- }
+ if (pGstStrmIn)
+ {
+ PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
+ AssertPtr(pHstStrmIn);
- /* Note: cbHstStrm will contain sizeof(PDMAUDIOSTREAM) + additional data
- * which the host backend will need. */
- size_t cbHstStrm;
- if (pCfgHost->enmDir == PDMAUDIODIR_IN)
+ drvAudioGstInFreeRes(pGstStrmIn);
+
+ char *pszTemp;
+ if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
{
- if (!pThis->cStreamsFreeIn)
- LogFunc(("Warning: No more input streams free to use\n"));
+ RTMemFree(pGstStrmIn);
- /* Validate backend configuration. */
- if (!pThis->BackendCfg.cbStreamIn)
- {
- LogFunc(("Backend input configuration not valid, bailing out\n"));
- RC_BREAK(VERR_INVALID_PARAMETER);
- }
+ int rc2 = RTCritSectLeave(&pThis->CritSect);
+ AssertRC(rc2);
- cbHstStrm = pThis->BackendCfg.cbStreamIn;
+ return VERR_NO_MEMORY;
}
- else /* Out */
- {
- if (!pThis->cStreamsFreeOut)
- {
- LogFlowFunc(("Maximum number of host output streams reached\n"));
- RC_BREAK(VERR_AUDIO_NO_FREE_OUTPUT_STREAMS);
- }
- /* Validate backend configuration. */
- if (!pThis->BackendCfg.cbStreamOut)
- {
- LogFlowFunc(("Backend output configuration invalid, bailing out\n"));
- RC_BREAK(VERR_INVALID_PARAMETER);
- }
+ rc = drvAudioGstInInit(pGstStrmIn, pHstStrmIn, pszName, pCfg);
+
+ RTStrFree(pszTemp);
+ }
+ else
+ rc = drvAudioCreateStreamPairIn(pThis, pszName, enmRecSource, pCfg, &pGstStrmIn);
+
+ if (RT_SUCCESS(rc))
+ {
+ if (pGstStrmIn)
+ *ppGstStrmIn = pGstStrmIn;
+ }
+ else
+ {
+ switch (rc)
+ {
+ case VERR_NO_MORE_HANDLES: /** @todo Find a better rc. */
+ LogRel(("Audio: Skipping to create input stream \"%s\", " \
+ "as the host audio backend reached its maximum of concurrent audio input streams\n", pszName));
+ break;
- cbHstStrm = pThis->BackendCfg.cbStreamOut;
+ default:
+ break;
}
+ }
- pHstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(cbHstStrm);
- AssertPtrBreakStmt(pHstStrm, rc = VERR_NO_MEMORY);
+ int rc2 = RTCritSectLeave(&pThis->CritSect);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
- pHstStrm->enmCtx = PDMAUDIOSTREAMCTX_HOST;
- pHstStrm->enmDir = pCfgHost->enmDir;
+ LogFlowFuncLeaveRC(rc);
+ return rc;
+}
- pGstStrm = (PPDMAUDIOSTREAM)RTMemAllocZ(sizeof(PDMAUDIOSTREAM));
- AssertPtrBreakStmt(pGstStrm, rc = VERR_NO_MEMORY);
+static DECLCALLBACK(int) drvAudioCreateOut(PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
+ PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut)
+{
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppGstStrmOut, VERR_INVALID_POINTER);
- pGstStrm->enmCtx = PDMAUDIOSTREAMCTX_GUEST;
- pGstStrm->enmDir = pCfgGuest->enmDir;
+ PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
- /*
- * Init host stream.
- */
- RTStrPrintf(pHstStrm->szName, RT_ELEMENTS(pHstStrm->szName), "%s (Host)",
- strlen(pCfgHost->szName) ? pCfgHost->szName : "<Untitled>");
+ int rc = RTCritSectEnter(&pThis->CritSect);
+ if (RT_FAILURE(rc))
+ return rc;
- pHstStrm->pPair = pGstStrm;
+ LogFlowFunc(("pszName=%s, pCfg=%p\n", pszName, pCfg));
- /*
- * Init guest stream.
- */
- RTStrPrintf(pGstStrm->szName, RT_ELEMENTS(pGstStrm->szName), "%s (Guest)",
- strlen(pCfgGuest->szName) ? pCfgGuest->szName : "<Untitled>");
+ if (!drvAudioStreamCfgIsValid(pCfg))
+ {
+ LogFunc(("Output stream configuration is not valid, bailing out\n"));
+ rc = VERR_INVALID_PARAMETER;
+ }
- pGstStrm->fStatus = pHstStrm->fStatus; /* Reflect the host stream's status. */
- pGstStrm->pPair = pHstStrm;
+ PPDMAUDIOGSTSTRMOUT pGstStrmOut = *ppGstStrmOut;
+ if ( RT_SUCCESS(rc)
+ && pGstStrmOut
+ && drvAudioPCMPropsAreEqual(&pGstStrmOut->Props, pCfg))
+ {
+ LogFunc(("[%s] Exists and matches required configuration, skipping creation\n",
+ pGstStrmOut->MixBuf.pszName));
- /*
- * Try to init the rest.
- */
- rc = drvAudioStreamInitInternal(pThis, pHstStrm, pCfgHost, pCfgGuest);
- if (RT_FAILURE(rc))
- {
- LogFlowFunc(("Stream not available (yet)\n"));
- rc = VINF_SUCCESS;
- }
+ rc = VWRN_ALREADY_EXISTS;
+ }
- } while (0);
+ if (rc != VINF_SUCCESS) /* Note: Can be VWRN_ALREADY_EXISTS, so don't use VINF_SUCCESS here. */
+ {
+ int rc2 = RTCritSectLeave(&pThis->CritSect);
+ AssertRC(rc2);
-#undef RC_BREAK
+ return rc;
+ }
- if (RT_FAILURE(rc))
+#if 0
+ /* Any live samples that need to be updated after
+ * we set the new parameters? */
+ PPDMAUDIOGSTSTRMOUT pOldGstStrmOut = NULL;
+ uint32_t cLiveSamples = 0;
+
+ if ( conf.plive
+ && pGstStrmOut
+ && ( !pGstStrmOut->State.fActive
+ && !pGstStrmOut->State.fEmpty))
{
- if (pGstStrm)
+ cLiveSamples = pGstStrmOut->cTotalSamplesWritten;
+ if (cLiveSamples)
{
- int rc2 = drvAudioStreamUninitInternal(pThis, pGstStrm);
- if (RT_SUCCESS(rc2))
- {
- RTMemFree(pGstStrm);
- pGstStrm = NULL;
- }
+ pOldGstStrmOut = pGstStrmOut;
+ pGstStrmOut = NULL;
}
+ }
+#endif
- if (pHstStrm)
- {
- int rc2 = drvAudioStreamUninitInternal(pThis, pHstStrm);
- if (RT_SUCCESS(rc2))
- {
- RTMemFree(pHstStrm);
- pHstStrm = NULL;
- }
- }
+ if ( pGstStrmOut
+ && !conf.fixed_out.enabled)
+ {
+ drvAudioDestroyGstOut(pThis, pGstStrmOut);
+ pGstStrmOut = NULL;
+ }
+
+ if (pGstStrmOut)
+ {
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
+ AssertPtr(pHstStrmOut);
+
+ drvAudioGstOutFreeRes(pGstStrmOut);
+
+ rc = drvAudioGstOutInit(pGstStrmOut, pHstStrmOut, pszName, pCfg);
}
else
{
- /* Set initial reference counts. */
- RTListAppend(&pThis->lstGstStreams, &pGstStrm->Node);
- pGstStrm->cRefs = 1;
+ rc = drvAudioCreateStreamPairOut(pThis, pszName, pCfg, &pGstStrmOut);
+ if (RT_FAILURE(rc))
+ LogFunc(("Failed to create output stream \"%s\", rc=%Rrc\n", pszName, rc));
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ if (pGstStrmOut)
+ *ppGstStrmOut = pGstStrmOut;
+#if 0
+ /* Update remaining live samples with new rate. */
+ if (cLiveSamples)
+ {
+ AssertPtr(pOldGstStrmOut);
- RTListAppend(&pThis->lstHstStreams, &pHstStrm->Node);
- pHstStrm->cRefs = 1;
+ uint32_t cSamplesMixed =
+ (cLiveSamples << pOldGstStrmOut->Props.cShift)
+ * pOldGstStrmOut->Props.cbPerSec
+ / (*ppGstStrmOut)->Props.cbPerSec;
- if (pCfgHost->enmDir == PDMAUDIODIR_IN)
- {
- if (pThis->cStreamsFreeIn)
- pThis->cStreamsFreeIn--;
+ pGstStrmOut->cTotalSamplesWritten += cSamplesMixed;
}
- else /* Out */
+#endif
+ }
+ else
+ {
+ switch (rc)
{
- if (pThis->cStreamsFreeOut)
- pThis->cStreamsFreeOut--;
- }
+ case VERR_NO_MORE_HANDLES: /** @todo Find a better rc. */
+ LogRel(("Audio: Skipping to create output stream \"%s\", " \
+ "as the host audio backend reached its maximum of concurrent audio output streams\n", pszName));
+ break;
-#ifdef VBOX_WITH_STATISTICS
- STAM_COUNTER_ADD(&pThis->Stats.TotalStreamsCreated, 1);
-#endif
- /* Always return the guest-side part to the device emulation. */
- *ppStream = pGstStrm;
+ default:
+ break;
+ }
}
int rc2 = RTCritSectLeave(&pThis->CritSect);
@@ -1767,10 +2307,7 @@ static DECLCALLBACK(int) drvAudioStreamCreate(PPDMIAUDIOCONNECTOR pInterface,
return rc;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnGetConfig}
- */
-static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)
+static DECLCALLBACK(int) drvAudioGetConfiguration(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)
{
AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
@@ -1781,15 +2318,7 @@ static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMA
if (RT_FAILURE(rc))
return rc;
- if (pThis->pHostDrvAudio)
- {
- if (pThis->pHostDrvAudio->pfnGetConfig)
- rc = pThis->pHostDrvAudio->pfnGetConfig(pThis->pHostDrvAudio, pCfg);
- else
- rc = VERR_NOT_SUPPORTED;
- }
- else
- AssertFailed();
+ rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, pCfg);
int rc2 = RTCritSectLeave(&pThis->CritSect);
if (RT_SUCCESS(rc))
@@ -1799,363 +2328,74 @@ static DECLCALLBACK(int) drvAudioGetConfig(PPDMIAUDIOCONNECTOR pInterface, PPDMA
return rc;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioGetStatus(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)
-{
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- PDMAUDIOBACKENDSTS backendSts = PDMAUDIOBACKENDSTS_UNKNOWN;
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- {
- if ( pThis->pHostDrvAudio
- && pThis->pHostDrvAudio->pfnGetStatus)
- {
- backendSts = pThis->pHostDrvAudio->pfnGetStatus(pThis->pHostDrvAudio, enmDir);
- }
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
-
- LogFlowFuncLeaveRC(rc);
- return backendSts;
-}
-
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamGetReadable}
- */
-static DECLCALLBACK(uint32_t) drvAudioStreamGetReadable(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(bool) drvAudioIsActiveIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn)
{
- AssertPtrReturn(pInterface, 0);
- AssertPtrReturn(pStream, 0);
+ AssertPtrReturn(pInterface, false);
+ /* pGstStrmIn is optional. */
PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
int rc2 = RTCritSectEnter(&pThis->CritSect);
AssertRC(rc2);
- AssertMsg(pStream->enmDir == PDMAUDIODIR_IN, ("Can't read from a non-input stream\n"));
-
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- if (!pHstStream) /* No host stream available? Bail out early. */
- {
- rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- return 0;
- }
-
- uint32_t cReadable = 0;
-
- PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
- if (pGstStream)
- cReadable = AudioMixBufLive(&pGstStream->MixBuf);
-
- Log3Func(("[%s] cbReadable=%RU32 (%zu bytes)\n", pHstStream->szName, cReadable,
- AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cReadable)));
-
- uint32_t cbReadable = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cReadable);
+ bool fRet = pGstStrmIn ? pGstStrmIn->State.fActive : false;
rc2 = RTCritSectLeave(&pThis->CritSect);
AssertRC(rc2);
- /* Return bytes instead of audio samples. */
- return cbReadable;
+ return fRet;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamGetWritable}
- */
-static DECLCALLBACK(uint32_t) drvAudioStreamGetWritable(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(bool) drvAudioIsActiveOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
{
- AssertPtrReturn(pInterface, 0);
- AssertPtrReturn(pStream, 0);
+ AssertPtrReturn(pInterface, false);
+ /* pGstStrmOut is optional. */
PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
int rc2 = RTCritSectEnter(&pThis->CritSect);
AssertRC(rc2);
- AssertMsg(pStream->enmDir == PDMAUDIODIR_OUT, ("Can't write to a non-output stream\n"));
-
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- if (!pHstStream) /* No host stream available? Bail out early. */
- {
- rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- AssertMsgFailed(("Guest stream '%s' does not have a host stream attached\n", pStream->szName));
- return 0;
- }
-
- PPDMAUDIOSTREAM pGstStream = pHstStream->pPair;
- AssertPtr(pGstStream);
-
- uint32_t cWritable = AudioMixBufFree(&pGstStream->MixBuf);
-
- Log3Func(("[%s] cWritable=%RU32 (%zu bytes)\n", pHstStream->szName, cWritable,
- AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cWritable)));
-
- uint32_t cbWritable = AUDIOMIXBUF_S2B(&pGstStream->MixBuf, cWritable);
+ bool fRet = pGstStrmOut ? pGstStrmOut->State.fActive : false;
rc2 = RTCritSectLeave(&pThis->CritSect);
AssertRC(rc2);
- /* Return bytes instead of audio samples. */
- return cbWritable;
+ return fRet;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioStreamGetStatus(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(void) drvAudioDestroyIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn)
{
- AssertPtrReturn(pInterface, false);
-
- if (!pStream)
- return PDMAUDIOSTRMSTS_FLAG_NONE;
+ AssertPtrReturnVoid(pInterface);
+ /* pGstStrmIn is optional. */
PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
int rc2 = RTCritSectEnter(&pThis->CritSect);
AssertRC(rc2);
- PDMAUDIOSTRMSTS strmSts = PDMAUDIOSTRMSTS_FLAG_NONE;
-
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- if (pHstStream)
- {
- strmSts = pHstStream->fStatus;
- Log3Func(("[%s] strmSts=0x%x\n", pHstStream->szName, strmSts));
- }
+ if (pGstStrmIn)
+ drvAudioDestroyGstIn(pThis, pGstStrmIn);
rc2 = RTCritSectLeave(&pThis->CritSect);
AssertRC(rc2);
-
- return strmSts;
-}
-
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamSetVolume}
- */
-static DECLCALLBACK(int) drvAudioStreamSetVolume(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOVOLUME pVol)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pVol, VERR_INVALID_POINTER);
-
- LogFlowFunc(("%s: volL=%RU32, volR=%RU32, fMute=%RTbool\n", pStream->szName, pVol->uLeft, pVol->uRight, pVol->fMuted));
-
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
-
- AudioMixBufSetVolume(&pHstStream->MixBuf, pVol);
- AudioMixBufSetVolume(&pGstStream->MixBuf, pVol);
- return VINF_SUCCESS;
}
-/**
- * @interface_method_impl{PDMIAUDIOCONNECTOR,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvAudioStreamDestroy(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(void) drvAudioDestroyOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturnVoid(pInterface);
+ /* pGstStrmOut is optional. */
PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
- int rc = RTCritSectEnter(&pThis->CritSect);
- AssertRC(rc);
-
- PDMAUDIODIR enmDir = pStream->enmDir;
-
- LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
- if (pStream->cRefs > 1)
- rc = VERR_WRONG_ORDER;
-
- if (RT_SUCCESS(rc))
- {
- PPDMAUDIOSTREAM pHstStream = drvAudioGetHostStream(pStream);
- PPDMAUDIOSTREAM pGstStream = pHstStream ? pHstStream->pPair : pStream;
-
- LogRel2(("Audio: Destroying host stream '%s' (guest stream '%s')\n",
- pHstStream ? pHstStream->szName : "<None>",
- pGstStream ? pGstStream->szName : "<None>"));
-
- /* Should prevent double frees. */
- Assert(pHstStream != pGstStream);
-
- if (pHstStream)
- {
- rc = drvAudioStreamUninitInternal(pThis, pHstStream);
- if (RT_SUCCESS(rc))
- {
- RTListNodeRemove(&pHstStream->Node);
-
- RTMemFree(pHstStream);
- pHstStream = NULL;
- }
- else
- LogRel2(("Audio: Uninitializing host stream '%s' failed with %Rrc\n", pHstStream->szName, rc));
- }
-
- if ( RT_SUCCESS(rc)
- && pGstStream)
- {
- rc = drvAudioStreamUninitInternal(pThis, pGstStream);
- if (RT_SUCCESS(rc))
- {
- RTListNodeRemove(&pGstStream->Node);
-
- RTMemFree(pGstStream);
- pGstStream = NULL;
- }
- else
- LogRel2(("Audio: Uninitializing guest stream '%s' failed with %Rrc\n", pGstStream->szName, rc));
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- if (enmDir == PDMAUDIODIR_IN)
- {
- pThis->cStreamsFreeIn++;
- }
- else /* Out */
- {
- pThis->cStreamsFreeOut++;
- }
- }
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * Calls the backend to give it the chance to destroy its part of the audio stream.
- *
- * @returns IPRT status code.
- * @param pThis Pointer to driver instance.
- * @param pHstStream Host audio stream to call the backend destruction for.
- */
-static int drvAudioStreamDestroyInBackendInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pHstStream)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStream, VERR_INVALID_POINTER);
-
- AssertMsg(pHstStream->enmCtx == PDMAUDIOSTREAMCTX_HOST,
- ("Stream '%s' is not a host stream and therefore has no backend\n", pHstStream->szName));
-
- int rc = VINF_SUCCESS;
-
- LogFlowFunc(("%s: fStatus=0x%x\n", pHstStream->szName, pHstStream->fStatus));
-
- if (pHstStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
- {
- /* Check if the pointer to the host audio driver is still valid.
- * It can be NULL if we were called in drvAudioDestruct, for example. */
- if (pThis->pHostDrvAudio)
- rc = pThis->pHostDrvAudio->pfnStreamDestroy(pThis->pHostDrvAudio, pHstStream);
- if (RT_SUCCESS(rc))
- pHstStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
- }
-
- LogFlowFunc(("%s: Returning %Rrc\n", pHstStream->szName, rc));
- return rc;
-}
-
-/**
- * Uninitializes an audio stream.
- *
- * @returns IPRT status code.
- * @param pThis Pointer to driver instance.
- * @param pStream Pointer to audio stream to uninitialize.
- */
-static int drvAudioStreamUninitInternal(PDRVAUDIO pThis, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- LogFlowFunc(("%s: cRefs=%RU32\n", pStream->szName, pStream->cRefs));
-
- if (pStream->cRefs > 1)
- return VERR_WRONG_ORDER;
-
- int rc = VINF_SUCCESS;
-
- if (pStream->enmCtx == PDMAUDIOSTREAMCTX_GUEST)
- {
- if (pStream->fStatus & PDMAUDIOSTRMSTS_FLAG_INITIALIZED)
- {
- rc = drvAudioStreamControlInternal(pThis, pStream, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- pStream->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
- }
-
- if (pStream->enmDir == PDMAUDIODIR_IN)
- {
-#ifdef VBOX_WITH_STATISTICS
- PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->In.StatBytesElapsed);
- PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->In.StatBytesTotalRead);
-#endif
- }
- else if (pStream->enmDir == PDMAUDIODIR_OUT)
- {
-#ifdef VBOX_WITH_STATISTICS
- PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->Out.StatBytesElapsed);
- PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->Out.StatBytesTotalWritten);
-#endif
- }
- }
- else if (pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST)
- {
- rc = drvAudioStreamDestroyInBackendInternal(pThis, pStream);
-
- if (pStream->enmDir == PDMAUDIODIR_IN)
- {
-#ifdef VBOX_WITH_STATISTICS
- PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->In.StatSamplesCaptured);
-#endif
- }
- else if (pStream->enmDir == PDMAUDIODIR_OUT)
- {
-#ifdef VBOX_WITH_STATISTICS
- PDMDrvHlpSTAMDeregister(pThis->pDrvIns, &pStream->Out.StatSamplesPlayed);
-#endif
- }
- }
- else
- AssertFailedReturn(VERR_NOT_IMPLEMENTED);
-
- if (RT_SUCCESS(rc))
- {
- /* Make sure that the pair (if any) knows that we're not valid anymore. */
- if (pStream->pPair)
- pStream->pPair->pPair = NULL;
-
- /* Reset status. */
- pStream->fStatus = PDMAUDIOSTRMSTS_FLAG_NONE;
-
- /* Clear name. */
- pStream->szName[0] = '\0';
+ int rc2 = RTCritSectEnter(&pThis->CritSect);
+ AssertRC(rc2);
- /* Destroy mixing buffer. */
- AudioMixBufDestroy(&pStream->MixBuf);
- }
+ if (pGstStrmOut)
+ drvAudioDestroyGstOut(pThis, pGstStrmOut);
- LogFlowFunc(("Returning %Rrc\n", rc));
- return rc;
+ rc2 = RTCritSectLeave(&pThis->CritSect);
+ AssertRC(rc2);
}
/********************************************************************/
@@ -2183,25 +2423,41 @@ static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const c
*/
static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
{
+ LogFlowFuncEnter();
+ PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+
PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
- LogFlowFuncEnter();
+ if (!pThis->pHostDrvAudio)
+ return;
+
+ /* Tear down all host output streams. */
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
+ while ((pHstStrmOut = drvAudioFindAnyHstOut(pThis, pHstStrmOut)))
+ {
+ drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
+ pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
+ }
- /* Just destroy the host stream on the backend side.
- * The rest will either be destructed by the device emulation or
- * in drvAudioDestruct(). */
- PPDMAUDIOSTREAM pStream;
- RTListForEach(&pThis->lstHstStreams, pStream, PDMAUDIOSTREAM, Node)
- drvAudioStreamDestroyInBackendInternal(pThis, pStream);
+ /* Tear down all host input streams. */
+ PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
+ while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
+ {
+ drvAudioControlHstIn(pThis, pHstStrmIn, PDMAUDIOSTREAMCMD_DISABLE);
+ pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio, pHstStrmIn);
+ }
- /*
- * Last call for the driver below us.
- * Let it know that we reached end of life.
- */
if (pThis->pHostDrvAudio->pfnShutdown)
pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
- pThis->pHostDrvAudio = NULL;
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+ PPDMAUDIOCALLBACK pCB, pCBNext;
+ RTListForEachSafe(&pThis->lstCBIn, pCB, pCBNext, PDMAUDIOCALLBACK, Node)
+ drvAudioCallbackDestroy(pCB);
+
+ RTListForEachSafe(&pThis->lstCBOut, pCB, pCBNext, PDMAUDIOCALLBACK, Node)
+ drvAudioCallbackDestroy(pCB);
+#endif
LogFlowFuncLeave();
}
@@ -2218,39 +2474,31 @@ static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHan
PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
- RTListInit(&pThis->lstHstStreams);
- RTListInit(&pThis->lstGstStreams);
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- RTListInit(&pThis->lstCBIn);
- RTListInit(&pThis->lstCBOut);
-#endif
-
/*
* Init the static parts.
*/
- pThis->pDrvIns = pDrvIns;
+ pThis->pDrvIns = pDrvIns;
/* IBase. */
- pDrvIns->IBase.pfnQueryInterface = drvAudioQueryInterface;
+ pDrvIns->IBase.pfnQueryInterface = drvAudioQueryInterface;
/* IAudioConnector. */
- pThis->IAudioConnector.pfnGetConfig = drvAudioGetConfig;
- pThis->IAudioConnector.pfnGetStatus = drvAudioGetStatus;
- pThis->IAudioConnector.pfnStreamCreate = drvAudioStreamCreate;
- pThis->IAudioConnector.pfnStreamDestroy = drvAudioStreamDestroy;
- pThis->IAudioConnector.pfnStreamRetain = drvAudioStreamRetain;
- pThis->IAudioConnector.pfnStreamRelease = drvAudioStreamRelease;
- pThis->IAudioConnector.pfnStreamControl = drvAudioStreamControl;
- pThis->IAudioConnector.pfnStreamRead = drvAudioStreamRead;
- pThis->IAudioConnector.pfnStreamWrite = drvAudioStreamWrite;
- pThis->IAudioConnector.pfnStreamIterate = drvAudioStreamIterate;
- pThis->IAudioConnector.pfnStreamGetReadable = drvAudioStreamGetReadable;
- pThis->IAudioConnector.pfnStreamGetWritable = drvAudioStreamGetWritable;
- pThis->IAudioConnector.pfnStreamGetStatus = drvAudioStreamGetStatus;
- pThis->IAudioConnector.pfnStreamSetVolume = drvAudioStreamSetVolume;
- pThis->IAudioConnector.pfnStreamPlay = drvAudioStreamPlay;
- pThis->IAudioConnector.pfnStreamCapture = drvAudioStreamCapture;
+ pThis->IAudioConnector.pfnQueryStatus = drvAudioQueryStatus;
+ pThis->IAudioConnector.pfnRead = drvAudioRead;
+ pThis->IAudioConnector.pfnWrite = drvAudioWrite;
+ pThis->IAudioConnector.pfnGetConfiguration = drvAudioGetConfiguration;
+ pThis->IAudioConnector.pfnIsActiveIn = drvAudioIsActiveIn;
+ pThis->IAudioConnector.pfnIsActiveOut = drvAudioIsActiveOut;
+ pThis->IAudioConnector.pfnIsValidIn = drvAudioIsValidIn;
+ pThis->IAudioConnector.pfnIsValidOut = drvAudioIsValidOut;
+ pThis->IAudioConnector.pfnEnableOut = drvAudioEnableOut;
+ pThis->IAudioConnector.pfnEnableIn = drvAudioEnableIn;
+ pThis->IAudioConnector.pfnDestroyIn = drvAudioDestroyIn;
+ pThis->IAudioConnector.pfnDestroyOut = drvAudioDestroyOut;
+ pThis->IAudioConnector.pfnCreateIn = drvAudioCreateIn;
+ pThis->IAudioConnector.pfnCreateOut = drvAudioCreateOut;
+ pThis->IAudioConnector.pfnPlayOut = drvAudioPlayOut;
#ifdef VBOX_WITH_AUDIO_CALLBACKS
- pThis->IAudioConnector.pfnRegisterCallbacks = drvAudioRegisterCallbacks;
- pThis->IAudioConnector.pfnCallback = drvAudioCallback;
+ pThis->IAudioConnector.pfnRegisterCallbacks = drvAudioRegisterCallbacks;
+ pThis->IAudioConnector.pfnCallback = drvAudioCallback;
#endif
/*
@@ -2273,26 +2521,15 @@ static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHan
N_("Host audio backend missing or invalid"));
}
- rc = drvAudioInit(pDrvIns, pCfgHandle);
+#ifdef DEBUG_andy
+ CFGMR3Dump(pCfgHandle);
+#endif
+
+ rc = drvAudioInit(pCfgHandle, pDrvIns);
if (RT_SUCCESS(rc))
{
pThis->fTerminate = false;
pThis->pDrvIns = pDrvIns;
-
-#ifdef VBOX_WITH_STATISTICS
- PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->Stats.TotalStreamsActive, "TotalStreamsActive",
- STAMUNIT_COUNT, "Active input streams.");
- PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->Stats.TotalStreamsCreated, "TotalStreamsCreated",
- STAMUNIT_COUNT, "Total created input streams.");
- PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->Stats.TotalSamplesPlayed, "TotalSamplesPlayed",
- STAMUNIT_COUNT, "Total samples played.");
- PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->Stats.TotalSamplesCaptured, "TotalSamplesCaptured",
- STAMUNIT_COUNT, "Total samples captured.");
- PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->Stats.TotalBytesRead, "TotalBytesRead",
- STAMUNIT_BYTES, "Total bytes read.");
- PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->Stats.TotalBytesWritten, "TotalBytesWritten",
- STAMUNIT_BYTES, "Total bytes written.");
-#endif
}
LogFlowFuncLeaveRC(rc);
@@ -2306,75 +2543,16 @@ static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHan
*/
static DECLCALLBACK(void) drvAudioDestruct(PPDMDRVINS pDrvIns)
{
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
- PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
-
LogFlowFuncEnter();
- int rc2 = RTCritSectEnter(&pThis->CritSect);
- AssertRC(rc2);
-
- /*
- * Note: No calls here to the driver below us anymore,
- * as PDM already has destroyed it.
- * If you need to call something from the host driver,
- * do this in drvAudioPowerOff() instead.
- */
-
- /* Thus, NULL the pointer to the host audio driver first,
- * so that routines like drvAudioStreamDestroyInternal() don't call the driver(s) below us anymore. */
- pThis->pHostDrvAudio = NULL;
-
- PPDMAUDIOSTREAM pStream, pStreamNext;
- RTListForEachSafe(&pThis->lstHstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node)
- {
- rc2 = drvAudioStreamUninitInternal(pThis, pStream);
- if (RT_SUCCESS(rc2))
- {
- RTListNodeRemove(&pStream->Node);
-
- RTMemFree(pStream);
- pStream = NULL;
- }
- }
-
- /* Sanity. */
- Assert(RTListIsEmpty(&pThis->lstHstStreams));
+ PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
+ PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
- RTListForEachSafe(&pThis->lstGstStreams, pStream, pStreamNext, PDMAUDIOSTREAM, Node)
+ if (RTCritSectIsInitialized(&pThis->CritSect))
{
- rc2 = drvAudioStreamUninitInternal(pThis, pStream);
- if (RT_SUCCESS(rc2))
- {
- RTListNodeRemove(&pStream->Node);
-
- RTMemFree(pStream);
- pStream = NULL;
- }
+ int rc2 = RTCritSectDelete(&pThis->CritSect);
+ AssertRC(rc2);
}
-
- /* Sanity. */
- Assert(RTListIsEmpty(&pThis->lstGstStreams));
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- /*
- * Destroy callbacks, if any.
- */
- PPDMAUDIOCALLBACK pCB, pCBNext;
- RTListForEachSafe(&pThis->lstCBIn, pCB, pCBNext, PDMAUDIOCALLBACK, Node)
- drvAudioCallbackDestroy(pCB);
-
- RTListForEachSafe(&pThis->lstCBOut, pCB, pCBNext, PDMAUDIOCALLBACK, Node)
- drvAudioCallbackDestroy(pCB);
-#endif
-
- rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- rc2 = RTCritSectDelete(&pThis->CritSect);
- AssertRC(rc2);
-
- LogFlowFuncLeave();
}
/**
@@ -2417,7 +2595,7 @@ const PDMDRVREG g_DrvAUDIO =
/* fClass */
PDM_DRVREG_CLASS_AUDIO,
/* cMaxInstances */
- UINT32_MAX,
+ 2,
/* cbInstance */
sizeof(DRVAUDIO),
/* pfnConstruct */
@@ -2447,4 +2625,3 @@ const PDMDRVREG g_DrvAUDIO =
/* u32EndVersion */
PDM_DRVREG_VERSION
};
-
diff --git a/src/VBox/Devices/Audio/DrvAudio.h b/src/VBox/Devices/Audio/DrvAudio.h
index 552d5d9..e48c62a 100644
--- a/src/VBox/Devices/Audio/DrvAudio.h
+++ b/src/VBox/Devices/Audio/DrvAudio.h
@@ -47,8 +47,6 @@
#include <iprt/circbuf.h>
#include <iprt/critsect.h>
-#include <iprt/file.h>
-#include <iprt/path.h>
#include <VBox/vmm/pdmdev.h>
#include <VBox/vmm/pdm.h>
@@ -72,22 +70,6 @@ typedef struct audio_option
int overriden;
} audio_option;
-#ifdef VBOX_WITH_STATISTICS
-/**
- * Structure for keeping stream statistics for the
- * statistic manager (STAM).
- */
-typedef struct DRVAUDIOSTATS
-{
- STAMCOUNTER TotalStreamsActive;
- STAMCOUNTER TotalStreamsCreated;
- STAMCOUNTER TotalSamplesPlayed;
- STAMCOUNTER TotalSamplesCaptured;
- STAMCOUNTER TotalBytesRead;
- STAMCOUNTER TotalBytesWritten;
-} DRVAUDIOSTATS, *PDRVAUDIOSTATS;
-#endif
-
/**
* Audio driver instance data.
*
@@ -107,16 +89,16 @@ typedef struct DRVAUDIO
PPDMDRVINS pDrvIns;
/** Pointer to audio driver below us. */
PPDMIHOSTAUDIO pHostDrvAudio;
- /** List of host input/output audio streams. */
- RTLISTANCHOR lstHstStreams;
- /** List of guest input/output audio streams. */
- RTLISTANCHOR lstGstStreams;
+ /** List of host input streams. */
+ RTLISTANCHOR lstHstStrmIn;
+ /** List of host output streams. */
+ RTLISTANCHOR lstHstStrmOut;
/** Max. number of free input streams.
* UINT32_MAX for unlimited streams. */
- uint32_t cStreamsFreeIn;
+ uint32_t cFreeInputStreams;
/** Max. number of free output streams.
* UINT32_MAX for unlimited streams. */
- uint32_t cStreamsFreeOut;
+ uint32_t cFreeOutputStreams;
/** Audio configuration settings retrieved from the backend. */
PDMAUDIOBACKENDCFG BackendCfg;
#ifdef VBOX_WITH_AUDIO_CALLBACKS
@@ -124,41 +106,51 @@ typedef struct DRVAUDIO
RTLISTANCHOR lstCBIn;
RTLISTANCHOR lstCBOut;
#endif
-#ifdef VBOX_WITH_STATISTICS
- /** Statistics for the statistics manager (STAM). */
- DRVAUDIOSTATS Stats;
-#endif
} DRVAUDIO, *PDRVAUDIO;
/** Makes a PDRVAUDIO out of a PPDMIAUDIOCONNECTOR. */
#define PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface) \
( (PDRVAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVAUDIO, IAudioConnector)) )
-
-bool DrvAudioHlpAudFmtIsSigned(PDMAUDIOFMT enmFmt);
-uint8_t DrvAudioHlpAudFmtToBits(PDMAUDIOFMT enmFmt);
-const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt);
-void DrvAudioHlpClearBuf(PPDMAUDIOPCMPROPS pPCMInfo, void *pvBuf, size_t cbBuf, uint32_t cSamples);
-uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels);
-uint32_t DrvAudioHlpCalcBitrate(PPDMAUDIOSTREAMCFG pCfg);
-bool DrvAudioHlpPCMPropsAreEqual(PPDMAUDIOPCMPROPS pPCMProps1, PPDMAUDIOPCMPROPS pPCMProps2);
-bool DrvAudioHlpPCMPropsAreEqual(PPDMAUDIOPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg);
-int DrvAudioHlpPCMPropsToStreamCfg(PPDMAUDIOPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg);
-const char *DrvAudioHlpRecSrcToStr(PDMAUDIORECSOURCE enmRecSource);
-void DrvAudioHlpStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg);
-bool DrvAudioHlpStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg);
-int DrvAudioHlpStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOPCMPROPS pProps);
-PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt);
-
-int DrvAudioHlpSanitizeFileName(char *pszPath, size_t cbPath);
-int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType);
-
-int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMAUDIOPCMPROPS pProps, PDMAUDIOFILEFLAGS fFlags);
-int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile);
-size_t DrvAudioHlpWAVFileGetDataSize(PPDMAUDIOFILE pFile);
-int DrvAudioHlpWAVFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags);
-
-#define AUDIO_MAKE_FOURCC(c0, c1, c2, c3) RT_H2LE_U32_C(RT_MAKE_U32_FROM_U8(c0, c1, c2, c3))
+const char *drvAudioHlpFormatToString(PDMAUDIOFMT enmFormat);
+const char *drvAudioRecSourceToString(PDMAUDIORECSOURCE enmRecSource);
+PDMAUDIOFMT drvAudioHlpStringToFormat(const char *pszFormat);
+
+bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS info, PPDMAUDIOSTREAMCFG pCfg);
+void drvAudioStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg);
+
+/* AUDIO IN function declarations. */
+void drvAudioHlpPcmSwFreeResourcesIn(PPDMAUDIOGSTSTRMIN pGstStrmIn);
+void drvAudioGstInFreeRes(PPDMAUDIOGSTSTRMIN pGstStrmIn);
+void drvAudioGstInRemove(PPDMAUDIOGSTSTRMIN pGstStrmIn);
+uint32_t drvAudioHstInFindMinCaptured(PPDMAUDIOHSTSTRMIN pHstStrmIn);
+void drvAudioHstInFreeRes(PPDMAUDIOHSTSTRMIN pHstStrmIn);
+uint32_t drvAudioHstInGetFree(PPDMAUDIOHSTSTRMIN pHstStrmIn);
+uint32_t drvAudioHstInGetLive(PPDMAUDIOHSTSTRMIN pHstStrmIn);
+void drvAudioGstInRemove(PPDMAUDIOGSTSTRMIN pGstStrmIn);
+int drvAudioGstInInit(PPDMAUDIOGSTSTRMIN pGstStrmIn, PPDMAUDIOHSTSTRMIN pHstStrmIn, const char *pszName, PPDMAUDIOSTREAMCFG pCfg);
+
+PPDMAUDIOHSTSTRMIN drvAudioFindNextHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+PPDMAUDIOHSTSTRMIN drvAudioFindNextEnabledHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+PPDMAUDIOHSTSTRMIN drvAudioFindNextEqHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg);
+
+/* AUDIO OUT function declarations. */
+int drvAudioGstOutAlloc(PPDMAUDIOGSTSTRMOUT pGstStrmOut);
+void drvAudioGstOutFreeRes(PPDMAUDIOGSTSTRMOUT pGstStrmOut);
+void drvAudioHstOutFreeRes(PPDMAUDIOHSTSTRMOUT pHstStrmOut);
+int drvAudioDestroyGstOut(PDRVAUDIO pDrvAudio, PPDMAUDIOGSTSTRMOUT pGstStrmOut);
+void drvAudioDestroyHstOut(PDRVAUDIO pDrvAudio, PDMAUDIOHSTSTRMOUT pHstStrmOut);
+int drvAudioGstOutInit(PPDMAUDIOGSTSTRMOUT pGstStrmOut, PPDMAUDIOHSTSTRMOUT pHstStrmOut, const char *pszName, PPDMAUDIOSTREAMCFG pCfg);
+
+PPDMAUDIOHSTSTRMOUT drvAudioFindAnyHstOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
+PPDMAUDIOHSTSTRMOUT drvAudioHstFindAnyEnabledOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
+PPDMAUDIOHSTSTRMOUT drvAudioFindSpecificOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg);
+int drvAudioAllocHstOut(PDRVAUDIO pDrvAudio, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut);
+int drvAudioHlpPcmHwAddOut(PDRVAUDIO pDrvAudio, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut);
+int drvAudioHlpPcmCreateVoicePairOut(PDRVAUDIO pDrvAudio, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut);
+
+/* Common functions between DrvAudio and backends (host audio drivers). */
+void DrvAudioClearBuf(PPDMPCMPROPS pPCMInfo, void *pvBuf, size_t cbBuf, uint32_t cSamples);
+int DrvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps);
#endif /* DRV_AUDIO_H */
-
diff --git a/src/VBox/Devices/Audio/DrvAudioCommon.cpp b/src/VBox/Devices/Audio/DrvAudioCommon.cpp
index 577ffc3..12c1e2c 100644
--- a/src/VBox/Devices/Audio/DrvAudioCommon.cpp
+++ b/src/VBox/Devices/Audio/DrvAudioCommon.cpp
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -41,13 +41,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include <iprt/alloc.h>
+#define LOG_GROUP LOG_GROUP_DRV_AUDIO
+#include <VBox/log.h>
#include <iprt/asm-math.h>
#include <iprt/assert.h>
-#include <iprt/dir.h>
-#include <iprt/file.h>
-#include <iprt/string.h>
#include <iprt/uuid.h>
+#include <iprt/string.h>
+#include <iprt/alloc.h>
#include <VBox/vmm/pdmdev.h>
#include <VBox/vmm/pdm.h>
@@ -60,327 +60,236 @@
#include "DrvAudio.h"
#include "AudioMixBuffer.h"
-#pragma pack(1)
-/**
- * Structure for building up a .WAV file header.
- */
-typedef struct AUDIOWAVFILEHDR
-{
- uint32_t u32RIFF;
- uint32_t u32Size;
- uint32_t u32WAVE;
-
- uint32_t u32Fmt;
- uint32_t u32Size1;
- uint16_t u16AudioFormat;
- uint16_t u16NumChannels;
- uint32_t u32SampleRate;
- uint32_t u32ByteRate;
- uint16_t u16BlockAlign;
- uint16_t u16BitsPerSample;
-
- uint32_t u32ID2;
- uint32_t u32Size2;
-} AUDIOWAVFILEHDR, *PAUDIOWAVFILEHDR;
-#pragma pack()
-
-/**
- * Structure for keeeping the internal .WAV file data
- */
-typedef struct AUDIOWAVFILEDATA
-{
- /** The file header/footer. */
- AUDIOWAVFILEHDR Hdr;
-} AUDIOWAVFILEDATA, *PAUDIOWAVFILEDATA;
-
-/**
- * Retrieves the matching PDMAUDIOFMT for given bits + signing flag.
- *
- * @return IPRT status code.
- * @return PDMAUDIOFMT Resulting audio format or PDMAUDIOFMT_INVALID if invalid.
- * @param cBits Bits to retrieve audio format for.
- * @param fSigned Signed flag for bits to retrieve audio format for.
- */
-PDMAUDIOFMT DrvAudioAudFmtBitsToAudFmt(uint8_t cBits, bool fSigned)
-{
- if (fSigned)
- {
- switch (cBits)
- {
- case 8: return PDMAUDIOFMT_S8;
- case 16: return PDMAUDIOFMT_S16;
- case 32: return PDMAUDIOFMT_S32;
- default: break;
- }
- }
- else
- {
- switch (cBits)
- {
- case 8: return PDMAUDIOFMT_U8;
- case 16: return PDMAUDIOFMT_U16;
- case 32: return PDMAUDIOFMT_U32;
- default: break;
- }
- }
-
- AssertMsgFailed(("Bogus audio bits %RU8\n", cBits));
- return PDMAUDIOFMT_INVALID;
-}
-
-/**
- * Clears a sample buffer by the given amount of audio samples.
- *
- * @return IPRT status code.
- * @param pPCMProps PCM properties to use for the buffer to clear.
- * @param pvBuf Buffer to clear.
- * @param cbBuf Size (in bytes) of the buffer.
- * @param cSamples Number of audio samples to clear in the buffer.
- */
-void DrvAudioHlpClearBuf(PPDMAUDIOPCMPROPS pPCMProps, void *pvBuf, size_t cbBuf, uint32_t cSamples)
-{
- AssertPtrReturnVoid(pPCMProps);
- AssertPtrReturnVoid(pvBuf);
-
- if (!cbBuf || !cSamples)
- return;
-
- Log2Func(("pPCMInfo=%p, pvBuf=%p, cSamples=%RU32, fSigned=%RTbool, cBits=%RU8, cShift=%RU8\n",
- pPCMProps, pvBuf, cSamples, pPCMProps->fSigned, pPCMProps->cBits, pPCMProps->cShift));
+bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg);
- if (pPCMProps->fSigned)
- {
- memset(pvBuf, 0, cSamples << pPCMProps->cShift);
- }
- else
- {
- switch (pPCMProps->cBits)
- {
- case 8:
- {
- memset(pvBuf, 0x80, cSamples << pPCMProps->cShift);
- break;
- }
-
- case 16:
- {
- uint16_t *p = (uint16_t *)pvBuf;
- int shift = pPCMProps->cChannels - 1;
- short s = INT16_MAX;
-
- if (pPCMProps->fSwapEndian)
- s = RT_BSWAP_U16(s);
-
- for (unsigned i = 0; i < cSamples << shift; i++)
- p[i] = s;
-
- break;
- }
-
- case 32:
- {
- uint32_t *p = (uint32_t *)pvBuf;
- int shift = pPCMProps->cChannels - 1;
- int32_t s = INT32_MAX;
-
- if (pPCMProps->fSwapEndian)
- s = RT_BSWAP_U32(s);
-
- for (unsigned i = 0; i < cSamples << shift; i++)
- p[i] = s;
-
- break;
- }
-
- default:
- {
- AssertMsgFailed(("Invalid bits: %RU8\n", pPCMProps->cBits));
- break;
- }
- }
- }
-}
-
-/**
- * Converts a recording source enumeration to a string.
- *
- * @returns Stringified recording source, or "Unknown", if not found.
- * @param enmRecSrc Recording source to convert.
- */
-const char *DrvAudioHlpRecSrcToStr(PDMAUDIORECSOURCE enmRecSrc)
+const char *drvAudioRecSourceToString(PDMAUDIORECSOURCE enmRecSource)
{
- switch (enmRecSrc)
+ switch (enmRecSource)
{
- case PDMAUDIORECSOURCE_UNKNOWN: return "Unknown";
case PDMAUDIORECSOURCE_MIC: return "Microphone In";
case PDMAUDIORECSOURCE_CD: return "CD";
case PDMAUDIORECSOURCE_VIDEO: return "Video";
case PDMAUDIORECSOURCE_AUX: return "AUX";
- case PDMAUDIORECSOURCE_LINE: return "Line In";
+ case PDMAUDIORECSOURCE_LINE_IN: return "Line In";
case PDMAUDIORECSOURCE_PHONE: return "Phone";
default:
break;
}
- AssertMsgFailed(("Invalid recording source %ld\n", enmRecSrc));
+ AssertMsgFailed(("Bogus recording source %ld\n", enmRecSource));
return "Unknown";
}
-/**
- * Returns wether the given audio format has signed bits or not.
- *
- * @return IPRT status code.
- * @return bool @true for signed bits, @false for unsigned.
- * @param enmFmt Audio format to retrieve value for.
- */
-bool DrvAudioHlpAudFmtIsSigned(PDMAUDIOFMT enmFmt)
+const char *drvAudioHlpFormatToString(PDMAUDIOFMT enmFormat)
{
- switch (enmFmt)
+ switch (enmFormat)
{
- case PDMAUDIOFMT_S8:
- case PDMAUDIOFMT_S16:
- case PDMAUDIOFMT_S32:
- return true;
+ case AUD_FMT_U8:
+ return "U8";
+
+ case AUD_FMT_U16:
+ return "U16";
- case PDMAUDIOFMT_U8:
- case PDMAUDIOFMT_U16:
- case PDMAUDIOFMT_U32:
- return false;
+ case AUD_FMT_U32:
+ return "U32";
+
+ case AUD_FMT_S8:
+ return "S8";
+
+ case AUD_FMT_S16:
+ return "S16";
+
+ case AUD_FMT_S32:
+ return "S32";
default:
break;
}
- AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
- return false;
+ AssertMsgFailed(("Bogus audio format %ld\n", enmFormat));
+ return "Invalid";
}
-/**
- * Returns the bits of a given audio format.
- *
- * @return IPRT status code.
- * @return uint8_t Bits of audio format.
- * @param enmFmt Audio format to retrieve value for.
- */
-uint8_t DrvAudioHlpAudFmtToBits(PDMAUDIOFMT enmFmt)
+PDMAUDIOFMT drvAudioHlpStringToFormat(const char *pszFormat)
+{
+ if (!RTStrICmp(pszFormat, "u8"))
+ return AUD_FMT_U8;
+ else if (!RTStrICmp(pszFormat, "u16"))
+ return AUD_FMT_U16;
+ else if (!RTStrICmp(pszFormat, "u32"))
+ return AUD_FMT_U32;
+ else if (!RTStrICmp(pszFormat, "s8"))
+ return AUD_FMT_S8;
+ else if (!RTStrICmp(pszFormat, "s16"))
+ return AUD_FMT_S16;
+ else if (!RTStrICmp(pszFormat, "s32"))
+ return AUD_FMT_S32;
+
+ AssertMsgFailed(("Bogus audio format \"%s\"\n", pszFormat));
+ return AUD_FMT_INVALID;
+}
+
+/*********************************** In Stream Functions **********************************************/
+
+void drvAudioGstInFreeRes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
{
- switch (enmFmt)
+ AssertPtrReturnVoid(pGstStrmIn);
+
+ if (pGstStrmIn->State.pszName)
{
- case PDMAUDIOFMT_S8:
- case PDMAUDIOFMT_U8:
- return 8;
+ RTStrFree(pGstStrmIn->State.pszName);
+ pGstStrmIn->State.pszName = NULL;
+ }
- case PDMAUDIOFMT_U16:
- case PDMAUDIOFMT_S16:
- return 16;
+ AudioMixBufDestroy(&pGstStrmIn->MixBuf);
+}
- case PDMAUDIOFMT_U32:
- case PDMAUDIOFMT_S32:
- return 32;
+void drvAudioHstInFreeRes(PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+ AssertPtrReturnVoid(pHstStrmIn);
+ AudioMixBufDestroy(&pHstStrmIn->MixBuf);
+}
- default:
- break;
+void drvAudioGstOutFreeRes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
+{
+ if (!pGstStrmOut)
+ return;
+
+ if (pGstStrmOut->State.pszName)
+ {
+ RTStrFree(pGstStrmOut->State.pszName);
+ pGstStrmOut->State.pszName = NULL;
}
- AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
- return 0;
+ AudioMixBufDestroy(&pGstStrmOut->MixBuf);
}
+#if 0
+
/**
- * Converts an audio format to a string.
+ * Finds the minimum number of not yet captured samples of all
+ * attached guest input streams for a certain host input stream.
*
- * @returns Stringified audio format, or "Unknown", if not found.
- * @param enmFmt Audio format to convert.
+ * @return uint32_t Minimum number of not yet captured samples.
+ * UINT32_MAX if none found.
+ * @param pHstStrmIn Host input stream to check for.
*/
-const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt)
+inline uint32_t drvAudioHstInFindMinCaptured(PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
- switch (enmFmt)
+ AssertPtrReturn(pHstStrmIn, 0);
+ uint32_t cMinSamples = UINT32_MAX;
+
+ PPDMAUDIOGSTSTRMIN pGstStrmIn;
+ RTListForEach(&pHstStrmIn->lstGstStrmIn, pGstStrmIn, PDMAUDIOGSTSTRMIN, Node)
{
- case PDMAUDIOFMT_U8:
- return "U8";
+ if (pGstStrmIn->State.fActive)
+ cMinSamples = RT_MIN(cMinSamples, audioMixBufMixed(&pGstStrmIn->MixBuf));
+ }
- case PDMAUDIOFMT_U16:
- return "U16";
+#ifdef DEBUG_andy
+ LogFlowFunc(("cMinSamples=%RU32\n", cMinSamples));
+#endif
+ return cMinSamples;
+}
- case PDMAUDIOFMT_U32:
- return "U32";
+uint32_t drvAudioHstInGetFree(PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+ AssertPtrReturn(pHstStrmIn, 0);
- case PDMAUDIOFMT_S8:
- return "S8";
+ return audioMixBufSize(&pHstStrmIn->MixBuf) - drvAudioHstInGetLive(pHstStrmIn);
+}
- case PDMAUDIOFMT_S16:
- return "S16";
+uint32_t drvAudioHstInGetLive(PPDMAUDIOHSTSTRMIN pHstStrmIn)
+{
+ AssertPtrReturn(pHstStrmIn, 0);
- case PDMAUDIOFMT_S32:
- return "S32";
+ uint32_t cMinSamplesCaptured = drvAudioHstInFindMinCaptured(pHstStrmIn);
+ uint32_t cSamplesCaptured = audioMixBufMixed(&pHstStrmIn->MixBuf);
- default:
- break;
- }
+ Assert(cSamplesCaptured >= cMinSamplesCaptured);
+ uint32_t cSamplesLive = cSamplesCaptured - cMinSamplesCaptured;
+ Assert(cSamplesLive <= audioMixBufSize(&pHstStrmIn->MixBuf));
- AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
- return "Unknown";
+#ifdef DEBUG_andy
+ LogFlowFunc(("cSamplesLive=%RU32\n", cSamplesLive));
+#endif
+ return cSamplesLive;
}
+#endif
+void drvAudioHstOutFreeRes(PPDMAUDIOHSTSTRMOUT pHstStrmOut)
+{
+ AssertPtrReturnVoid(pHstStrmOut);
+ AudioMixBufDestroy(&pHstStrmOut->MixBuf);
+}
+
+#if 0
/**
- * Converts a given string to an audio format.
+ * Returns the number of live sample data (in bytes) of a certain
+ * guest input stream.
*
- * @returns Audio format for the given string, or PDMAUDIOFMT_INVALID if not found.
- * @param pszFmt String to convert to an audio format.
+ * @return uint32_t Live sample data (in bytes), 0 if none.
+ * @param pGstStrmIn Guest input stream to check for.
*/
-PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt)
+uint32_t drvAudioGstInGetLiveBytes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
{
- AssertPtrReturn(pszFmt, PDMAUDIOFMT_INVALID);
-
- if (!RTStrICmp(pszFmt, "u8"))
- return PDMAUDIOFMT_U8;
- else if (!RTStrICmp(pszFmt, "u16"))
- return PDMAUDIOFMT_U16;
- else if (!RTStrICmp(pszFmt, "u32"))
- return PDMAUDIOFMT_U32;
- else if (!RTStrICmp(pszFmt, "s8"))
- return PDMAUDIOFMT_S8;
- else if (!RTStrICmp(pszFmt, "s16"))
- return PDMAUDIOFMT_S16;
- else if (!RTStrICmp(pszFmt, "s32"))
- return PDMAUDIOFMT_S32;
-
- AssertMsgFailed(("Invalid audio format \"%s\"\n", pszFmt));
- return PDMAUDIOFMT_INVALID;
+ AssertPtrReturn(pGstStrmIn, 0);
+ AssertPtrReturn(pGstStrmIn->pHstStrmIn, 0);
+
+ Assert(pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured >= pGstStrmIn->cTotalHostSamplesRead);
+ uint32_t cSamplesLive = pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured - pGstStrmIn->cTotalHostSamplesRead;
+ if (!cSamplesLive)
+ return 0;
+ Assert(cSamplesLive <= pGstStrmIn->pHstStrmIn->cSamples);
+
+ /** @todo Document / refactor this! */
+ return (((int64_t) cSamplesLive << 32) / pGstStrmIn->State.uFreqRatio) << pGstStrmIn->Props.cShift;
}
+
/**
- * Checks whether the given PCM properties are equal with the given
- * stream configuration.
+ * Returns the total number of unused sample data (in bytes) of a certain
+ * guest output stream.
*
- * @returns @true if equal, @false if not.
- * @param pProps PCM properties to compare.
- * @param pCfg Stream configuration to compare.
+ * @return uint32_t Number of unused sample data (in bytes), 0 if all used up.
+ * @param pGstStrmOut Guest output stream to check for.
*/
-bool DrvAudioHlpPCMPropsAreEqual(PPDMAUDIOPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
+uint32_t drvAudioGstOutGetFreeBytes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
{
- AssertPtrReturn(pProps, false);
- AssertPtrReturn(pCfg, false);
+ AssertPtrReturn(pGstStrmOut, 0);
+
+ Assert(pGstStrmOut->cTotalSamplesWritten <= pGstStrmOut->pHstStrmOut->cSamples);
+ uint32_t cSamplesFree = pGstStrmOut->pHstStrmOut->cSamples
+ - pGstStrmOut->cTotalSamplesWritten;
+ if (!cSamplesFree)
+ return 0;
+
+ /** @todo Document / refactor this! */
+ return (((int64_t) cSamplesFree << 32) / pGstStrmOut->State.uFreqRatio) << pGstStrmOut->Props.cShift;
+}
+#endif
+bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
+{
int cBits = 8;
bool fSigned = false;
switch (pCfg->enmFormat)
{
- case PDMAUDIOFMT_S8:
+ case AUD_FMT_S8:
fSigned = true;
- case PDMAUDIOFMT_U8:
+ case AUD_FMT_U8:
break;
- case PDMAUDIOFMT_S16:
+ case AUD_FMT_S16:
fSigned = true;
- case PDMAUDIOFMT_U16:
+ case AUD_FMT_U16:
cBits = 16;
break;
- case PDMAUDIOFMT_S32:
+ case AUD_FMT_S32:
fSigned = true;
- case PDMAUDIOFMT_U32:
+ case AUD_FMT_U32:
cBits = 32;
break;
@@ -394,90 +303,9 @@ bool DrvAudioHlpPCMPropsAreEqual(PPDMAUDIOPCMPROPS pProps, PPDMAUDIOSTREAMCFG pC
&& pProps->fSigned == fSigned
&& pProps->cBits == cBits
&& pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANNESS);
- return fEqual;
-}
-
-/**
- * Checks whether two given PCM properties are equal.
- *
- * @returns @true if equal, @false if not.
- * @param pProps1 First properties to compare.
- * @param pProps2 Second properties to compare.
- */
-bool DrvAudioHlpPCMPropsAreEqual(PPDMAUDIOPCMPROPS pProps1, PPDMAUDIOPCMPROPS pProps2)
-{
- AssertPtrReturn(pProps1, false);
- AssertPtrReturn(pProps2, false);
- if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */
- return true;
-
- return pProps1->uHz == pProps2->uHz
- && pProps1->cChannels == pProps2->cChannels
- && pProps1->fSigned == pProps2->fSigned
- && pProps1->cBits == pProps2->cBits
- && pProps1->fSwapEndian == pProps2->fSwapEndian;
-}
-
-/**
- * Converts PCM properties to a audio stream configuration.
- *
- * @return IPRT status code.
- * @param pPCMProps Pointer to PCM properties to convert.
- * @param pCfg Pointer to audio stream configuration to store result into.
- */
-int DrvAudioHlpPCMPropsToStreamCfg(PPDMAUDIOPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- pCfg->uHz = pPCMProps->uHz;
- pCfg->cChannels = pPCMProps->cChannels;
- pCfg->enmFormat = DrvAudioAudFmtBitsToAudFmt(pPCMProps->cBits, pPCMProps->fSigned);
-
- /** @todo We assume little endian is the default for now. */
- pCfg->enmEndianness = pPCMProps->fSwapEndian == false ? PDMAUDIOENDIANNESS_LITTLE : PDMAUDIOENDIANNESS_BIG;
- return VINF_SUCCESS;
-}
-
-/**
- * Checks whether a given stream configuration is valid or not.
- *
- * Returns @true if configuration is valid, @false if not.
- * @param pCfg Stream configuration to check.
- */
-bool DrvAudioHlpStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
-{
- bool fValid = ( pCfg->cChannels == 1
- || pCfg->cChannels == 2); /* Either stereo (2) or mono (1), per stream. */
-
- fValid |= ( pCfg->enmEndianness == PDMAUDIOENDIANNESS_LITTLE
- || pCfg->enmEndianness == PDMAUDIOENDIANNESS_BIG);
-
- fValid |= ( pCfg->enmDir == PDMAUDIODIR_IN
- || pCfg->enmDir == PDMAUDIODIR_OUT);
-
- if (fValid)
- {
- switch (pCfg->enmFormat)
- {
- case PDMAUDIOFMT_S8:
- case PDMAUDIOFMT_U8:
- case PDMAUDIOFMT_S16:
- case PDMAUDIOFMT_U16:
- case PDMAUDIOFMT_S32:
- case PDMAUDIOFMT_U32:
- break;
- default:
- fValid = false;
- break;
- }
- }
-
- fValid |= pCfg->uHz > 0;
- /** @todo Check for defined frequencies supported. */
-
- return fValid;
+ LogFlowFunc(("fEqual=%RTbool\n", fEqual));
+ return fEqual;
}
/**
@@ -487,7 +315,7 @@ bool DrvAudioHlpStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
* @param pCfg Audio stream configuration to convert.
* @param pProps PCM properties to save result to.
*/
-int DrvAudioHlpStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOPCMPROPS pProps)
+int DrvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps)
{
AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
AssertPtrReturn(pProps, VERR_INVALID_POINTER);
@@ -499,21 +327,21 @@ int DrvAudioHlpStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOPCMPROPS pProp
switch (pCfg->enmFormat)
{
- case PDMAUDIOFMT_S8:
+ case AUD_FMT_S8:
fSigned = true;
- case PDMAUDIOFMT_U8:
+ case AUD_FMT_U8:
break;
- case PDMAUDIOFMT_S16:
+ case AUD_FMT_S16:
fSigned = true;
- case PDMAUDIOFMT_U16:
+ case AUD_FMT_U16:
cBits = 16;
cShift = 1;
break;
- case PDMAUDIOFMT_S32:
+ case AUD_FMT_S32:
fSigned = true;
- case PDMAUDIOFMT_U32:
+ case AUD_FMT_U32:
cBits = 32;
cShift = 2;
break;
@@ -529,44 +357,39 @@ int DrvAudioHlpStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOPCMPROPS pProp
pProps->uHz = pCfg->uHz;
pProps->cBits = cBits;
pProps->fSigned = fSigned;
- pProps->cShift = (pCfg->cChannels == 2) + cShift;
pProps->cChannels = pCfg->cChannels;
+ pProps->cShift = (pCfg->cChannels == 2) + cShift;
pProps->uAlign = (1 << pProps->cShift) - 1;
+ pProps->cbPerSec = pProps->uHz << pProps->cShift;
pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
}
return rc;
}
-/**
- * Prints an audio stream configuration to the debug log.
- *
- * @param pCfg Stream configuration to log.
- */
-void DrvAudioHlpStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
+void drvAudioStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
{
- AssertPtrReturnVoid(pCfg);
-
- LogFlowFunc(("uHz=%RU32, cChannels=%RU8, enmFormat=", pCfg->uHz, pCfg->cChannels));
+ LogFlowFunc(("uHz=%RU32, cChannels=%RU8, enmFormat=",
+ pCfg->uHz, pCfg->cChannels));
switch (pCfg->enmFormat)
{
- case PDMAUDIOFMT_S8:
+ case AUD_FMT_S8:
LogFlow(("S8"));
break;
- case PDMAUDIOFMT_U8:
+ case AUD_FMT_U8:
LogFlow(("U8"));
break;
- case PDMAUDIOFMT_S16:
+ case AUD_FMT_S16:
LogFlow(("S16"));
break;
- case PDMAUDIOFMT_U16:
+ case AUD_FMT_U16:
LogFlow(("U16"));
break;
- case PDMAUDIOFMT_S32:
+ case AUD_FMT_S32:
LogFlow(("S32"));
break;
- case PDMAUDIOFMT_U32:
+ case AUD_FMT_U32:
LogFlow(("U32"));
break;
default:
@@ -588,320 +411,3 @@ void DrvAudioHlpStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
break;
}
}
-
-/**
- * Calculates the audio bit rate of the given bits per sample, the Hz and the number
- * of audio channels.
- *
- * Divide the result by 8 to get the byte rate.
- *
- * @returns The calculated bit rate.
- * @param cBits Number of bits per sample.
- * @param uHz Hz (Hertz) rate.
- * @param cChannels Number of audio channels.
- */
-uint32_t DrvAudioHlpCalcBitrate(uint8_t cBits, uint32_t uHz, uint8_t cChannels)
-{
- return (cBits * uHz * cChannels);
-}
-
-/**
- * Calculates the audio bit rate out of a given audio stream configuration.
- *
- * Divide the result by 8 to get the byte rate.
- *
- * @returns The calculated bit rate.
- * @param pCfg Audio stream configuration to calculate bit rate for.
- *
- * @remark
- */
-uint32_t DrvAudioHlpCalcBitrate(PPDMAUDIOSTREAMCFG pCfg)
-{
- return DrvAudioHlpCalcBitrate(DrvAudioHlpAudFmtToBits(pCfg->enmFormat), pCfg->uHz, pCfg->cChannels);
-}
-
-/**
- * Sanitizes the file name component so that unsupported characters
- * will be replaced by an underscore ("_").
- *
- * @return IPRT status code.
- * @param pszPath Path to sanitize.
- * @param cbPath Size (in bytes) of path to sanitize.
- */
-int DrvAudioHlpSanitizeFileName(char *pszPath, size_t cbPath)
-{
- RT_NOREF(cbPath);
- int rc = VINF_SUCCESS;
-#ifdef RT_OS_WINDOWS
- /* Filter out characters not allowed on Windows platforms, put in by
- RTTimeSpecToString(). */
- /** @todo Use something like RTPathSanitize() if available later some time. */
- static RTUNICP const s_uszValidRangePairs[] =
- {
- ' ', ' ',
- '(', ')',
- '-', '.',
- '0', '9',
- 'A', 'Z',
- 'a', 'z',
- '_', '_',
- 0xa0, 0xd7af,
- '\0'
- };
- ssize_t cReplaced = RTStrPurgeComplementSet(pszPath, s_uszValidRangePairs, '_' /* Replacement */);
- if (cReplaced < 0)
- rc = VERR_INVALID_UTF8_ENCODING;
-#else
- RT_NOREF(pszPath);
-#endif
- return rc;
-}
-
-/**
- * Constructs an unique file name, based on the given path and the audio file type.
- *
- * @returns IPRT status code.
- * @param pszFile Where to store the constructed file name.
- * @param cchFile Size (in characters) of the file name buffer.
- * @param pszPath Base path to use.
- * @param pszName A name for better identifying the file. Optional.
- * @param enmType Audio file type to construct file name for.
- */
-int DrvAudioHlpGetFileName(char *pszFile, size_t cchFile, const char *pszPath, const char *pszName, PDMAUDIOFILETYPE enmType)
-{
- AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
- AssertReturn(cchFile, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
- /* pszName is optional. */
-
- int rc;
-
- do
- {
- char szFilePath[RTPATH_MAX];
- RTStrPrintf(szFilePath, sizeof(szFilePath), "%s", pszPath);
-
- /* Create it when necessary. */
- if (!RTDirExists(szFilePath))
- {
- rc = RTDirCreateFullPath(szFilePath, RTFS_UNIX_IRWXU);
- if (RT_FAILURE(rc))
- break;
- }
-
- /* The actually drop directory consist of the current time stamp and a
- * unique number when necessary. */
- char pszTime[64];
- RTTIMESPEC time;
- if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
- {
- rc = VERR_BUFFER_OVERFLOW;
- break;
- }
-
- rc = DrvAudioHlpSanitizeFileName(pszTime, sizeof(pszTime));
- if (RT_FAILURE(rc))
- break;
-
- rc = RTPathAppend(szFilePath, sizeof(szFilePath), pszTime);
- if (RT_FAILURE(rc))
- break;
-
- if (pszName) /* Optional name given? */
- {
- rc = RTStrCat(szFilePath, sizeof(szFilePath), "-");
- if (RT_FAILURE(rc))
- break;
-
- rc = RTStrCat(szFilePath, sizeof(szFilePath), pszName);
- if (RT_FAILURE(rc))
- break;
- }
-
- switch (enmType)
- {
- case PDMAUDIOFILETYPE_WAV:
- rc = RTStrCat(szFilePath, sizeof(szFilePath), ".wav");
- break;
-
- default:
- AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
- }
-
- if (RT_FAILURE(rc))
- break;
-
- RTStrPrintf(pszFile, cchFile, "%s", szFilePath);
-
- } while (0);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * Opens or creates a wave (.WAV) file.
- *
- * @returns IPRT status code.
- * @param pFile Pointer to audio file handle to use.
- * @param pszFile File path of file to open or create.
- * @param fOpen Open flags.
- * @param pProps PCM properties to use.
- * @param fFlags Audio file flags.
- */
-int DrvAudioHlpWAVFileOpen(PPDMAUDIOFILE pFile, const char *pszFile, uint32_t fOpen, PPDMAUDIOPCMPROPS pProps,
- PDMAUDIOFILEFLAGS fFlags)
-{
- AssertPtrReturn(pFile, VERR_INVALID_POINTER);
- AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
- /** @todo Validate fOpen flags. */
- AssertPtrReturn(pProps, VERR_INVALID_POINTER);
- RT_NOREF(fFlags); /** @todo Validate fFlags flags. */
-
- Assert(pProps->cChannels);
- Assert(pProps->uHz);
- Assert(pProps->cBits);
-
- pFile->pvData = (PAUDIOWAVFILEDATA)RTMemAllocZ(sizeof(AUDIOWAVFILEDATA));
- if (!pFile->pvData)
- return VERR_NO_MEMORY;
- pFile->cbData = sizeof(PAUDIOWAVFILEDATA);
-
- PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
- AssertPtr(pData);
-
- /* Header. */
- pData->Hdr.u32RIFF = AUDIO_MAKE_FOURCC('R','I','F','F');
- pData->Hdr.u32Size = 36;
- pData->Hdr.u32WAVE = AUDIO_MAKE_FOURCC('W','A','V','E');
-
- pData->Hdr.u32Fmt = AUDIO_MAKE_FOURCC('f','m','t',' ');
- pData->Hdr.u32Size1 = 16; /* Means PCM. */
- pData->Hdr.u16AudioFormat = 1; /* PCM, linear quantization. */
- pData->Hdr.u16NumChannels = pProps->cChannels;
- pData->Hdr.u32SampleRate = pProps->uHz;
- pData->Hdr.u32ByteRate = DrvAudioHlpCalcBitrate(pProps->cBits, pProps->uHz, pProps->cChannels) / 8;
- pData->Hdr.u16BlockAlign = pProps->cChannels * pProps->cBits / 8;
- pData->Hdr.u16BitsPerSample = pProps->cBits;
-
- /* Data chunk. */
- pData->Hdr.u32ID2 = AUDIO_MAKE_FOURCC('d','a','t','a');
- pData->Hdr.u32Size2 = 0;
-
- int rc = RTFileOpen(&pFile->hFile, pszFile, fOpen);
- if (RT_SUCCESS(rc))
- {
- rc = RTFileWrite(pFile->hFile, &pData->Hdr, sizeof(pData->Hdr), NULL);
- if (RT_FAILURE(rc))
- {
- RTFileClose(pFile->hFile);
- pFile->hFile = NIL_RTFILE;
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- pFile->enmType = PDMAUDIOFILETYPE_WAV;
-
- RTStrPrintf(pFile->szName, RT_ELEMENTS(pFile->szName), "%s", pszFile);
- }
- else
- {
- RTMemFree(pFile->pvData);
- pFile->pvData = NULL;
- pFile->cbData = 0;
- }
-
- return rc;
-}
-
-/**
- * Closes a wave (.WAV) audio file.
- *
- * @returns IPRT status code.
- * @param pFile Audio file handle to close.
- */
-int DrvAudioHlpWAVFileClose(PPDMAUDIOFILE pFile)
-{
- AssertPtrReturn(pFile, VERR_INVALID_POINTER);
-
- Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
-
- if (pFile->hFile != NIL_RTFILE)
- {
- PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
- AssertPtr(pData);
-
- /* Update the header with the current data size. */
- RTFileWriteAt(pFile->hFile, 0, &pData->Hdr, sizeof(pData->Hdr), NULL);
-
- RTFileClose(pFile->hFile);
- pFile->hFile = NIL_RTFILE;
- }
-
- if (pFile->pvData)
- {
- RTMemFree(pFile->pvData);
- pFile->pvData = NULL;
- }
-
- pFile->cbData = 0;
- pFile->enmType = PDMAUDIOFILETYPE_UNKNOWN;
-
- return VINF_SUCCESS;
-}
-
-/**
- * Returns the raw PCM audio data size of a wave file.
- * This does *not* include file headers and other data which does
- * not belong to the actual PCM audio data.
- *
- * @returns Size (in bytes) of the raw PCM audio data.
- * @param pFile Audio file handle to retrieve the audio data size for.
- */
-size_t DrvAudioHlpWAVFileGetDataSize(PPDMAUDIOFILE pFile)
-{
- AssertPtrReturn(pFile, 0);
-
- Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
-
- PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
- AssertPtr(pData);
-
- return pData->Hdr.u32Size2;
-}
-
-/**
- * Write PCM data to a wave (.WAV) file.
- *
- * @returns IPRT status code.
- * @param pFile Audio file handle to write PCM data to.
- * @param pvBuf Audio data to write.
- * @param cbBuf Size (in bytes) of audio data to write.
- * @param fFlags Additional write flags. Not being used at the moment and must be 0.
- */
-int DrvAudioHlpWAVFileWrite(PPDMAUDIOFILE pFile, const void *pvBuf, size_t cbBuf, uint32_t fFlags)
-{
- AssertPtrReturn(pFile, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
-
- AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /** @todo fFlags are currently not implemented. */
-
- Assert(pFile->enmType == PDMAUDIOFILETYPE_WAV);
-
- if (!cbBuf)
- return VINF_SUCCESS;
-
- PAUDIOWAVFILEDATA pData = (PAUDIOWAVFILEDATA)pFile->pvData;
- AssertPtr(pData);
-
- int rc = RTFileWrite(pFile->hFile, pvBuf, cbBuf, NULL);
- if (RT_SUCCESS(rc))
- {
- pData->Hdr.u32Size += (uint32_t)cbBuf;
- pData->Hdr.u32Size2 += (uint32_t)cbBuf;
- }
-
- return rc;
-}
-
diff --git a/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp b/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp
index 039f3ea..23b4c3a 100644
--- a/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvHostALSAAudio.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -56,32 +56,15 @@ RT_C_DECLS_BEGIN
RT_C_DECLS_END
#include <alsa/asoundlib.h>
-#include <alsa/control.h> /* For device enumeration. */
#include "DrvAudio.h"
#include "AudioMixBuffer.h"
#include "VBoxDD.h"
-
-/*********************************************************************************************************************************
-* Defines *
-*********************************************************************************************************************************/
-
-/** Makes DRVHOSTALSAAUDIO out of PDMIHOSTAUDIO. */
-#define PDMIHOSTAUDIO_2_DRVHOSTALSAAUDIO(pInterface) \
- ( (PDRVHOSTALSAAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTALSAAUDIO, IHostAudio)) )
-
-
-/*********************************************************************************************************************************
-* Structures *
-*********************************************************************************************************************************/
-
typedef struct ALSAAUDIOSTREAMIN
{
- /** Associated host input stream.
- * Note: Always must come first! */
- PDMAUDIOSTREAM Stream;
+ PDMAUDIOHSTSTRMIN pStreamIn;
snd_pcm_t *phPCM;
void *pvBuf;
size_t cbBuf;
@@ -89,14 +72,10 @@ typedef struct ALSAAUDIOSTREAMIN
typedef struct ALSAAUDIOSTREAMOUT
{
- /** Associated host output stream.
- * Note: Always must come first! */
- PDMAUDIOSTREAM Stream;
+ PDMAUDIOHSTSTRMOUT pStreamOut;
snd_pcm_t *phPCM;
void *pvBuf;
size_t cbBuf;
- /** Minimum samples required for ALSA to play data. */
- uint32_t cSamplesMin;
} ALSAAUDIOSTREAMOUT, *PALSAAUDIOSTREAMOUT;
/* latency = period_size * periods / (rate * bytes_per_frame) */
@@ -121,7 +100,7 @@ typedef struct ALSAAUDIOCFG
} ALSAAUDIOCFG, *PALSAAUDIOCFG;
-static int alsaStreamRecover(snd_pcm_t *phPCM);
+static int drvHostALSAAudioRecover(snd_pcm_t *phPCM);
static ALSAAUDIOCFG s_ALSAConf =
{
@@ -174,41 +153,55 @@ typedef struct DRVHOSTALSAAUDIO
typedef struct ALSAAUDIOSTREAMCFG
{
- unsigned int freq;
- /** PCM sound format. */
- snd_pcm_format_t fmt;
- /** PCM data access type. */
- snd_pcm_access_t access;
- /** Whether resampling should be performed by alsalib or not. */
- int resample;
- int nchannels;
- unsigned long buffer_size;
- unsigned long period_size;
- snd_pcm_uframes_t samples;
+ unsigned int freq;
+ snd_pcm_format_t fmt;
+ int nchannels;
+ unsigned long buffer_size;
+ unsigned long period_size;
+ snd_pcm_uframes_t samples;
} ALSAAUDIOSTREAMCFG, *PALSAAUDIOSTREAMCFG;
+static int drvHostALSAAudioClose(snd_pcm_t **pphPCM)
+{
+ if (!pphPCM || !*pphPCM)
+ return VINF_SUCCESS;
+
+ int rc;
+ int rc2 = snd_pcm_close(*pphPCM);
+ if (rc2)
+ {
+ LogRel(("ALSA: Closing PCM descriptor failed: %s\n", snd_strerror(rc2)));
+ rc = VERR_GENERAL_FAILURE; /** @todo */
+ }
+ else
+ {
+ *pphPCM = NULL;
+ rc = VINF_SUCCESS;
+ }
+ return rc;
+}
-static snd_pcm_format_t alsaAudioFmtToALSA(PDMAUDIOFMT fmt)
+static snd_pcm_format_t drvHostALSAAudioFmtToALSA(PDMAUDIOFMT fmt)
{
switch (fmt)
{
- case PDMAUDIOFMT_S8:
+ case AUD_FMT_S8:
return SND_PCM_FORMAT_S8;
- case PDMAUDIOFMT_U8:
+ case AUD_FMT_U8:
return SND_PCM_FORMAT_U8;
- case PDMAUDIOFMT_S16:
+ case AUD_FMT_S16:
return SND_PCM_FORMAT_S16_LE;
- case PDMAUDIOFMT_U16:
+ case AUD_FMT_U16:
return SND_PCM_FORMAT_U16_LE;
- case PDMAUDIOFMT_S32:
+ case AUD_FMT_S32:
return SND_PCM_FORMAT_S32_LE;
- case PDMAUDIOFMT_U32:
+ case AUD_FMT_U32:
return SND_PCM_FORMAT_U32_LE;
default:
@@ -219,9 +212,8 @@ static snd_pcm_format_t alsaAudioFmtToALSA(PDMAUDIOFMT fmt)
return SND_PCM_FORMAT_U8;
}
-
-static int alsaALSAToAudioFmt(snd_pcm_format_t fmt,
- PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
+static int drvHostALSAAudioALSAToFmt(snd_pcm_format_t fmt,
+ PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
{
AssertPtrReturn(pFmt, VERR_INVALID_POINTER);
/* pEndianness is optional. */
@@ -229,61 +221,61 @@ static int alsaALSAToAudioFmt(snd_pcm_format_t fmt,
switch (fmt)
{
case SND_PCM_FORMAT_S8:
- *pFmt = PDMAUDIOFMT_S8;
+ *pFmt = AUD_FMT_S8;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
case SND_PCM_FORMAT_U8:
- *pFmt = PDMAUDIOFMT_U8;
+ *pFmt = AUD_FMT_U8;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
case SND_PCM_FORMAT_S16_LE:
- *pFmt = PDMAUDIOFMT_S16;
+ *pFmt = AUD_FMT_S16;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
case SND_PCM_FORMAT_U16_LE:
- *pFmt = PDMAUDIOFMT_U16;
+ *pFmt = AUD_FMT_U16;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
case SND_PCM_FORMAT_S16_BE:
- *pFmt = PDMAUDIOFMT_S16;
+ *pFmt = AUD_FMT_S16;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_BIG;
break;
case SND_PCM_FORMAT_U16_BE:
- *pFmt = PDMAUDIOFMT_U16;
+ *pFmt = AUD_FMT_U16;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_BIG;
break;
case SND_PCM_FORMAT_S32_LE:
- *pFmt = PDMAUDIOFMT_S32;
+ *pFmt = AUD_FMT_S32;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
case SND_PCM_FORMAT_U32_LE:
- *pFmt = PDMAUDIOFMT_U32;
+ *pFmt = AUD_FMT_U32;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
case SND_PCM_FORMAT_S32_BE:
- *pFmt = PDMAUDIOFMT_S32;
+ *pFmt = AUD_FMT_S32;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_BIG;
break;
case SND_PCM_FORMAT_U32_BE:
- *pFmt = PDMAUDIOFMT_U32;
+ *pFmt = AUD_FMT_U32;
if (pEndianness)
*pEndianness = PDMAUDIOENDIANNESS_BIG;
break;
@@ -296,8 +288,7 @@ static int alsaALSAToAudioFmt(snd_pcm_format_t fmt,
return VINF_SUCCESS;
}
-
-static int alsaGetSampleShift(snd_pcm_format_t fmt, unsigned *puShift)
+static int drvHostALSAAudioALSAGetShift(snd_pcm_format_t fmt, unsigned *puShift)
{
AssertPtrReturn(puShift, VERR_INVALID_POINTER);
@@ -330,8 +321,8 @@ static int alsaGetSampleShift(snd_pcm_format_t fmt, unsigned *puShift)
return VINF_SUCCESS;
}
-
-static int alsaStreamSetThreshold(snd_pcm_t *phPCM, snd_pcm_uframes_t threshold)
+static int drvHostALSAAudioSetThreshold(snd_pcm_t *phPCM,
+ snd_pcm_uframes_t threshold)
{
snd_pcm_sw_params_t *pSWParms = NULL;
snd_pcm_sw_params_alloca(&pSWParms);
@@ -359,15 +350,6 @@ static int alsaStreamSetThreshold(snd_pcm_t *phPCM, snd_pcm_uframes_t threshold)
break;
}
- err = snd_pcm_sw_params_set_avail_min(phPCM, pSWParms, 512);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set available minimum to %ld: %s\n",
- threshold, snd_strerror(err)));
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
err = snd_pcm_sw_params(phPCM, pSWParms);
if (err < 0)
{
@@ -385,224 +367,10 @@ static int alsaStreamSetThreshold(snd_pcm_t *phPCM, snd_pcm_uframes_t threshold)
return rc;
}
-
-static int alsaStreamClose(snd_pcm_t **pphPCM)
-{
- if (!pphPCM || !*pphPCM)
- return VINF_SUCCESS;
-
- int rc;
- int rc2 = snd_pcm_close(*pphPCM);
- if (rc2)
- {
- LogRel(("ALSA: Closing PCM descriptor failed: %s\n", snd_strerror(rc2)));
- rc = VERR_GENERAL_FAILURE; /** @todo */
- }
- else
- {
- *pphPCM = NULL;
- rc = VINF_SUCCESS;
- }
-
- return rc;
-}
-
-
-#if 0 /* After Beta. */
-static int alsaSetHWParams(snd_pcm_t *phPCM, PALSAAUDIOSTREAMCFG pCfg)
-{
- int rc;
- snd_pcm_hw_params_t *pParams = NULL;
-
- do
- {
- snd_pcm_hw_params_alloca(&pParams);
- if (!pParams)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
- unsigned int rrate;
- snd_pcm_uframes_t size;
- int dir;
-
- /* choose all parameters */
- int err = snd_pcm_hw_params_any(phPCM, pParams);
- if (err < 0)
- {
- LogRel(("ALSA: Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* set hardware resampling */
- err = snd_pcm_hw_params_set_rate_resample(phPCM, pParams, pCfg->resample);
- if (err < 0)
- {
- LogRel(("ALSA: Resampling setup failed for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* set the interleaved read/write format */
- err = snd_pcm_hw_params_set_access(phPCM, pParams, pCfg->access);
- if (err < 0)
- {
- LogRel(("ALSA: Access type not available for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* set the sample format */
- err = snd_pcm_hw_params_set_format(phPCM, pParams, pCfg->fmt);
- if (err < 0)
- {
- LogRel(("ALSA: Sample format not available for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* set the count of channels */
- err = snd_pcm_hw_params_set_channels(phPCM, pParams, pCfg->nchannels);
- if (err < 0)
- {
- LogRel(("ALSA: Channels count (%d) not available for playbacks: %s\n", pCfg->nchannels, snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* set the stream rate */
- rrate = pCfg->freq;
- err = snd_pcm_hw_params_set_rate_near(phPCM, pParams, &rrate, 0);
- if (err < 0)
- {
- LogRel(("ALSA: Rate %uHz not available for playback: %s\n", pCfg->freq, snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- if (rrate != pCfg->freq)
- {
- LogRel(("ALSA: Rate doesn't match (requested %iHz, get %uHz)\n", pCfg->freq, err));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* set the buffer time */
- err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pParams, &pCfg->buffer_time, &dir);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- err = snd_pcm_hw_params_get_buffer_size(pParams, &size);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to get buffer size for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- buffer_size = size;
- /* set the period time */
- err = snd_pcm_hw_params_set_period_time_near(phPCM, pParams, &period_time, &dir);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- err = snd_pcm_hw_params_get_period_size(pParams, &size, &dir);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to get period size for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- period_size = size;
- /* write the parameters to device */
- err = snd_pcm_hw_params(phPCM, pParams);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to set hw params for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- rc = VINF_SUCCESS;
-
- } while (0);
-
- if (pParams)
- {
- snd_pcm_hw_params_free(pParams);
- pParams = NULL;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-
-static int alsaSetSWParams(snd_pcm_t *phPCM, PALSAAUDIOCFG pCfg)
-{
- int rc;
- snd_pcm_sw_params_t *pParams = NULL;
-
- do
- {
- snd_pcm_sw_params_alloca(&pParams);
- if (!pParams)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
- /* get the current swparams */
- int err = snd_pcm_sw_params_current(phPCM, pParams);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to determine current swparams for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* start the transfer when the buffer is almost full: */
- /* (buffer_size / avail_min) * avail_min */
- err = snd_pcm_sw_params_set_start_threshold(phPCM, pParams, (buffer_size / period_size) * period_size);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to set start threshold mode for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* allow the transfer when at least period_size samples can be processed */
- /* or disable this mechanism when period event is enabled (aka interrupt like style processing) */
- err = snd_pcm_sw_params_set_avail_min(phPCM, pParams, period_size);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to set avail min for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- /* write the parameters to the playback device */
- err = snd_pcm_sw_params(phPCM, pParams);
- if (err < 0)
- {
- LogRel(("ALSA: Unable to set sw params for playback: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- rc = VINF_SUCCESS;
-
- } while (0);
-
- if (pParams)
- {
- snd_pcm_sw_params_free(pParams);
- pParams = NULL;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-#endif
-
-
-static int alsaStreamOpen(bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREAMCFG pCfgObt, snd_pcm_t **pphPCM)
+static int drvHostALSAAudioOpen(bool fIn,
+ PALSAAUDIOSTREAMCFG pCfgReq,
+ PALSAAUDIOSTREAMCFG pCfgObt,
+ snd_pcm_t **pphPCM)
{
snd_pcm_t *phPCM = NULL;
int rc;
@@ -830,8 +598,6 @@ static int alsaStreamOpen(bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREA
break;
}
- LogFunc(("Buffer sample size is: %RU32\n", obt_buffer_size));
-
snd_pcm_uframes_t obt_period_size;
int dir = 0;
err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir);
@@ -857,7 +623,7 @@ static int alsaStreamOpen(bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREA
&& s_ALSAConf.threshold)
{
unsigned uShift;
- rc = alsaGetSampleShift(pCfgReq->fmt, &uShift);
+ rc = drvHostALSAAudioALSAGetShift(pCfgReq->fmt, &uShift);
if (RT_SUCCESS(rc))
{
int bytes_per_sec = uFreq
@@ -867,7 +633,7 @@ static int alsaStreamOpen(bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREA
snd_pcm_uframes_t threshold
= (s_ALSAConf.threshold * bytes_per_sec) / 1000;
- rc = alsaStreamSetThreshold(phPCM, threshold);
+ rc = drvHostALSAAudioSetThreshold(phPCM, threshold);
}
}
else
@@ -885,24 +651,22 @@ static int alsaStreamOpen(bool fIn, PALSAAUDIOSTREAMCFG pCfgReq, PALSAAUDIOSTREA
*pphPCM = phPCM;
}
else
- alsaStreamClose(&phPCM);
+ drvHostALSAAudioClose(&phPCM);
LogFlowFuncLeaveRC(rc);
return rc;
}
-
#ifdef DEBUG
-static void alsaDbgErrorHandler(const char *file, int line, const char *function,
- int err, const char *fmt, ...)
+static void drvHostALSAAudioErrorHandler(const char *file, int line, const char *function,
+ int err, const char *fmt, ...)
{
- /** @todo Implement me! */
RT_NOREF(file, line, function, err, fmt);
+ /** @todo Implement me! */
}
#endif
-
-static int alsaStreamGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail)
+static int drvHostALSAAudioGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail)
{
AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
AssertPtrReturn(pFramesAvail, VERR_INVALID_POINTER);
@@ -915,7 +679,7 @@ static int alsaStreamGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail)
{
if (framesAvail == -EPIPE)
{
- rc = alsaStreamRecover(phPCM);
+ rc = drvHostALSAAudioRecover(phPCM);
if (RT_SUCCESS(rc))
framesAvail = snd_pcm_avail_update(phPCM);
}
@@ -931,8 +695,7 @@ static int alsaStreamGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail)
return rc;
}
-
-static int alsaStreamRecover(snd_pcm_t *phPCM)
+static int drvHostALSAAudioRecover(snd_pcm_t *phPCM)
{
AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
@@ -946,8 +709,7 @@ static int alsaStreamRecover(snd_pcm_t *phPCM)
return VINF_SUCCESS;
}
-
-static int alsaStreamResume(snd_pcm_t *phPCM)
+static int drvHostALSAAudioResume(snd_pcm_t *phPCM)
{
AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
@@ -961,7 +723,6 @@ static int alsaStreamResume(snd_pcm_t *phPCM)
return VINF_SUCCESS;
}
-
static int drvHostALSAAudioStreamCtl(snd_pcm_t *phPCM, bool fPause)
{
int err;
@@ -987,10 +748,6 @@ static int drvHostALSAAudioStreamCtl(snd_pcm_t *phPCM, bool fPause)
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
- */
static DECLCALLBACK(int) drvHostALSAAudioInit(PPDMIHOSTAUDIO pInterface)
{
NOREF(pInterface);
@@ -1003,28 +760,23 @@ static DECLCALLBACK(int) drvHostALSAAudioInit(PPDMIHOSTAUDIO pInterface)
else
{
#ifdef DEBUG
- snd_lib_error_set_handler(alsaDbgErrorHandler);
+ snd_lib_error_set_handler(drvHostALSAAudioErrorHandler);
#endif
}
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
- */
-static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static DECLCALLBACK(int) drvHostALSAAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ uint32_t *pcSamplesCaptured)
{
- RT_NOREF(pvBuf, cbBuf);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbRead is optional. */
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- PALSAAUDIOSTREAMIN pThisStream = (PALSAAUDIOSTREAMIN)pStream;
+ PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
snd_pcm_sframes_t cAvail;
- int rc = alsaStreamGetAvail(pThisStream->phPCM, &cAvail);
+ int rc = drvHostALSAAudioGetAvail(pThisStrmIn->phPCM, &cAvail);
if (RT_FAILURE(rc))
{
LogFunc(("Error getting number of captured frames, rc=%Rrc\n", rc));
@@ -1033,16 +785,16 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
if (!cAvail) /* No data yet? */
{
- snd_pcm_state_t state = snd_pcm_state(pThisStream->phPCM);
+ snd_pcm_state_t state = snd_pcm_state(pThisStrmIn->phPCM);
switch (state)
{
case SND_PCM_STATE_PREPARED:
- cAvail = AudioMixBufFree(&pStream->MixBuf);
+ cAvail = AudioMixBufFree(&pHstStrmIn->MixBuf);
break;
case SND_PCM_STATE_SUSPENDED:
{
- rc = alsaStreamResume(pThisStream->phPCM);
+ rc = drvHostALSAAudioResume(pThisStrmIn->phPCM);
if (RT_FAILURE(rc))
break;
@@ -1057,8 +809,8 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
if (!cAvail)
{
- if (pcbRead)
- *pcbRead = 0;
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = 0;
return VINF_SUCCESS;
}
}
@@ -1068,8 +820,8 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
* the mixer buffer.
*/
Assert(cAvail);
- size_t cbMixFree = AudioMixBufFreeBytes(&pStream->MixBuf);
- size_t cbToRead = RT_MIN((size_t)AUDIOMIXBUF_S2B(&pStream->MixBuf, cAvail), cbMixFree);
+ size_t cbMixFree = AudioMixBufFreeBytes(&pHstStrmIn->MixBuf);
+ size_t cbToRead = RT_MIN((size_t)AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cAvail), cbMixFree);
LogFlowFunc(("cbToRead=%zu, cAvail=%RI32\n", cbToRead, cAvail));
@@ -1080,10 +832,10 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
while ( cbToRead
&& RT_SUCCESS(rc))
{
- cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pStream->MixBuf, cbToRead),
- AUDIOMIXBUF_B2S(&pStream->MixBuf, pThisStream->cbBuf));
+ cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbToRead),
+ AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, pThisStrmIn->cbBuf));
AssertBreakStmt(cToRead, rc = VERR_NO_DATA);
- cRead = snd_pcm_readi(pThisStream->phPCM, pThisStream->pvBuf, cToRead);
+ cRead = snd_pcm_readi(pThisStrmIn->phPCM, pThisStrmIn->pvBuf, cToRead);
if (cRead <= 0)
{
switch (cRead)
@@ -1108,7 +860,7 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
case -EPIPE:
{
- rc = alsaStreamRecover(pThisStream->phPCM);
+ rc = drvHostALSAAudioRecover(pThisStrmIn->phPCM);
if (RT_FAILURE(rc))
break;
@@ -1127,8 +879,8 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
else
{
uint32_t cWritten;
- rc = AudioMixBufWriteCirc(&pStream->MixBuf,
- pThisStream->pvBuf, AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead),
+ rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
+ pThisStrmIn->pvBuf, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cRead),
&cWritten);
if (RT_FAILURE(rc))
break;
@@ -1140,7 +892,7 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
*/
AssertLogRelMsgBreakStmt(cWritten > 0, ("Mixer buffer shouldn't be full at this point!\n"),
rc = VERR_INTERNAL_ERROR);
- uint32_t cbWritten = AUDIOMIXBUF_S2B(&pStream->MixBuf, cWritten);
+ uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
Assert(cbToRead >= cbWritten);
cbToRead -= cbWritten;
@@ -1152,11 +904,11 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
{
uint32_t cProcessed = 0;
if (cWrittenTotal)
- rc = AudioMixBufMixToParent(&pStream->MixBuf, cWrittenTotal,
+ rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
&cProcessed);
- if (pcbRead)
- *pcbRead = cWrittenTotal;
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = cWrittenTotal;
LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
cWrittenTotal, cProcessed, rc));
@@ -1166,17 +918,13 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamCapture(PPDMIHOSTAUDIO pInterface
return rc;
}
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
- */
-static DECLCALLBACK(int) drvHostALSAAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+static DECLCALLBACK(int) drvHostALSAAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ uint32_t *pcSamplesPlayed)
{
- RT_NOREF(pvBuf, cbBuf);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbWritten is optional. */
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- PALSAAUDIOSTREAMOUT pThisStream = (PALSAAUDIOSTREAMOUT)pStream;
+ PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
int rc = VINF_SUCCESS;
uint32_t cbReadTotal = 0;
@@ -1184,50 +932,50 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamPlay(PPDMIHOSTAUDIO pInterface, P
do
{
snd_pcm_sframes_t cAvail;
- rc = alsaStreamGetAvail(pThisStream->phPCM, &cAvail);
+ rc = drvHostALSAAudioGetAvail(pThisStrmOut->phPCM, &cAvail);
if (RT_FAILURE(rc))
{
LogFunc(("Error getting number of playback frames, rc=%Rrc\n", rc));
break;
}
- size_t cbToRead = RT_MIN(AUDIOMIXBUF_S2B(&pStream->MixBuf,
+ size_t cbToRead = RT_MIN(AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
(uint32_t)cAvail), /* cAvail is always >= 0 */
- AUDIOMIXBUF_S2B(&pStream->MixBuf,
- AudioMixBufLive(&pStream->MixBuf)));
+ AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
+ AudioMixBufAvail(&pHstStrmOut->MixBuf)));
LogFlowFunc(("cbToRead=%zu, cbAvail=%zu\n",
- cbToRead, AUDIOMIXBUF_S2B(&pStream->MixBuf, cAvail)));
+ cbToRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cAvail)));
uint32_t cRead, cbRead;
snd_pcm_sframes_t cWritten;
while (cbToRead)
{
- rc = AudioMixBufReadCirc(&pStream->MixBuf, pThisStream->pvBuf, cbToRead, &cRead);
+ rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvBuf, cbToRead, &cRead);
if (RT_FAILURE(rc))
break;
- cbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead);
+ cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
AssertBreak(cbRead);
/* Don't try infinitely on recoverable errors. */
unsigned iTry;
for (iTry = 0; iTry < ALSA_RECOVERY_TRIES_MAX; iTry++)
{
- cWritten = snd_pcm_writei(pThisStream->phPCM, pThisStream->pvBuf, cRead);
+ cWritten = snd_pcm_writei(pThisStrmOut->phPCM, pThisStrmOut->pvBuf, cRead);
if (cWritten <= 0)
{
switch (cWritten)
{
case 0:
{
- LogFunc(("Failed to write %RU32 samples\n", cRead));
+ LogFunc(("Failed to write %RI32 frames\n", cRead));
rc = VERR_ACCESS_DENIED;
break;
}
case -EPIPE:
{
- rc = alsaStreamRecover(pThisStream->phPCM);
+ rc = drvHostALSAAudioRecover(pThisStrmOut->phPCM);
if (RT_FAILURE(rc))
break;
@@ -1238,7 +986,7 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamPlay(PPDMIHOSTAUDIO pInterface, P
case -ESTRPIPE:
{
/* Stream was suspended and waiting for a recovery. */
- rc = alsaStreamResume(pThisStream->phPCM);
+ rc = drvHostALSAAudioResume(pThisStrmOut->phPCM);
if (RT_FAILURE(rc))
{
LogRel(("ALSA: Failed to resume output stream\n"));
@@ -1276,12 +1024,12 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamPlay(PPDMIHOSTAUDIO pInterface, P
if (RT_SUCCESS(rc))
{
- uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pStream->MixBuf, cbReadTotal);
+ uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
if (cReadTotal)
- AudioMixBufFinish(&pStream->MixBuf, cReadTotal);
+ AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
- if (pcbWritten)
- *pcbWritten = cReadTotal;
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = cReadTotal;
LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
cReadTotal, cbReadTotal, rc));
@@ -1291,49 +1039,52 @@ static DECLCALLBACK(int) drvHostALSAAudioStreamPlay(PPDMIHOSTAUDIO pInterface, P
return rc;
}
-
-static int alsaDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostALSAAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
NOREF(pInterface);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- PALSAAUDIOSTREAMIN pThisStream = (PALSAAUDIOSTREAMIN)pStream;
+ PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
- alsaStreamClose(&pThisStream->phPCM);
+ drvHostALSAAudioClose(&pThisStrmIn->phPCM);
- if (pThisStream->pvBuf)
+ if (pThisStrmIn->pvBuf)
{
- RTMemFree(pThisStream->pvBuf);
- pThisStream->pvBuf = NULL;
+ RTMemFree(pThisStrmIn->pvBuf);
+ pThisStrmIn->pvBuf = NULL;
}
return VINF_SUCCESS;
}
-
-static int alsaDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostALSAAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
NOREF(pInterface);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- PALSAAUDIOSTREAMOUT pThisStream = (PALSAAUDIOSTREAMOUT)pStream;
+ PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
- alsaStreamClose(&pThisStream->phPCM);
+ drvHostALSAAudioClose(&pThisStrmOut->phPCM);
- if (pThisStream->pvBuf)
+ if (pThisStrmOut->pvBuf)
{
- RTMemFree(pThisStream->pvBuf);
- pThisStream->pvBuf = NULL;
+ RTMemFree(pThisStrmOut->pvBuf);
+ pThisStrmOut->pvBuf = NULL;
}
return VINF_SUCCESS;
}
-
-static int alsaCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostALSAAudioInitOut(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ uint32_t *pcSamples)
{
- PALSAAUDIOSTREAMOUT pThisStream = (PALSAAUDIOSTREAMOUT)pStream;
+ RT_NOREF(pInterface, pCfgAcq);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+ PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
snd_pcm_t *phPCM = NULL;
int rc;
@@ -1341,128 +1092,144 @@ static int alsaCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgR
do
{
ALSAAUDIOSTREAMCFG req;
- req.fmt = alsaAudioFmtToALSA(pCfgReq->enmFormat);
+ req.fmt = drvHostALSAAudioFmtToALSA(pCfgReq->enmFormat);
req.freq = pCfgReq->uHz;
req.nchannels = pCfgReq->cChannels;
req.period_size = s_ALSAConf.period_size_out;
req.buffer_size = s_ALSAConf.buffer_size_out;
ALSAAUDIOSTREAMCFG obt;
- rc = alsaStreamOpen(false /* fIn */, &req, &obt, &phPCM);
+ rc = drvHostALSAAudioOpen(false /* false */, &req, &obt, &phPCM);
if (RT_FAILURE(rc))
break;
PDMAUDIOFMT enmFormat;
PDMAUDIOENDIANNESS enmEnd;
- rc = alsaALSAToAudioFmt(obt.fmt, &enmFormat, &enmEnd);
+ rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
if (RT_FAILURE(rc))
break;
- pCfgAcq->uHz = obt.freq;
- pCfgAcq->cChannels = obt.nchannels;
- pCfgAcq->enmFormat = enmFormat;
- pCfgAcq->enmEndianness = enmEnd;
- pCfgAcq->cSampleBufferSize = obt.samples * 4;
+ PDMAUDIOSTREAMCFG streamCfg;
+ streamCfg.uHz = obt.freq;
+ streamCfg.cChannels = obt.nchannels;
+ streamCfg.enmFormat = enmFormat;
+ streamCfg.enmEndianness = enmEnd;
- PDMAUDIOPCMPROPS Props;
- rc = DrvAudioHlpStreamCfgToProps(pCfgAcq, &Props);
+ rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
if (RT_FAILURE(rc))
break;
AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
- size_t cbBuf = obt.samples * (1 << Props.cShift); /** @todo Get rid of using Props! */
+ size_t cbBuf = obt.samples * (1 << pHstStrmOut->Props.cShift);
AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
- pThisStream->pvBuf = RTMemAlloc(cbBuf);
- if (!pThisStream->pvBuf)
+ pThisStrmOut->pvBuf = RTMemAlloc(cbBuf);
+ if (!pThisStrmOut->pvBuf)
{
LogRel(("ALSA: Not enough memory for output DAC buffer (%RU32 samples, each %d bytes)\n",
- obt.samples, 1 << Props.cShift));
+ obt.samples, 1 << pHstStrmOut->Props.cShift));
rc = VERR_NO_MEMORY;
break;
}
- pThisStream->cbBuf = cbBuf;
- pThisStream->phPCM = phPCM;
+ pThisStrmOut->cbBuf = cbBuf;
+ pThisStrmOut->phPCM = phPCM;
+
+ if (pcSamples)
+ *pcSamples = obt.samples;
}
while (0);
if (RT_FAILURE(rc))
- alsaStreamClose(&phPCM);
+ drvHostALSAAudioClose(&phPCM);
LogFlowFuncLeaveRC(rc);
return rc;
}
-
-static int alsaCreateStreamIn(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostALSAAudioInitIn(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
{
+ RT_NOREF(pInterface, pCfgAcq, enmRecSource);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+
int rc;
- PALSAAUDIOSTREAMIN pThisStream = (PALSAAUDIOSTREAMIN)pStream;
+ PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
snd_pcm_t *phPCM = NULL;
do
{
ALSAAUDIOSTREAMCFG req;
- req.fmt = alsaAudioFmtToALSA(pCfgReq->enmFormat);
+ req.fmt = drvHostALSAAudioFmtToALSA(pCfgReq->enmFormat);
req.freq = pCfgReq->uHz;
req.nchannels = pCfgReq->cChannels;
req.period_size = s_ALSAConf.period_size_in;
req.buffer_size = s_ALSAConf.buffer_size_in;
ALSAAUDIOSTREAMCFG obt;
- rc = alsaStreamOpen(true /* fIn */, &req, &obt, &phPCM);
+ rc = drvHostALSAAudioOpen(true /* fIn */, &req, &obt, &phPCM);
if (RT_FAILURE(rc))
break;
PDMAUDIOFMT enmFormat;
PDMAUDIOENDIANNESS enmEnd;
- rc = alsaALSAToAudioFmt(obt.fmt, &enmFormat, &enmEnd);
+ rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
if (RT_FAILURE(rc))
break;
- pCfgAcq->uHz = obt.freq;
- pCfgAcq->cChannels = obt.nchannels;
- pCfgAcq->enmFormat = enmFormat;
- pCfgAcq->enmEndianness = enmEnd;
- pCfgAcq->cSampleBufferSize = obt.samples;
+ PDMAUDIOSTREAMCFG streamCfg;
+ streamCfg.uHz = obt.freq;
+ streamCfg.cChannels = obt.nchannels;
+ streamCfg.enmFormat = enmFormat;
+ streamCfg.enmEndianness = enmEnd;
- PDMAUDIOPCMPROPS Props;
- rc = DrvAudioHlpStreamCfgToProps(pCfgAcq, &Props);
+ rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
if (RT_FAILURE(rc))
break;
AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
- size_t cbBuf = obt.samples * (1 << Props.cShift); /** @todo Get rid of using Props! */
+ size_t cbBuf = obt.samples * (1 << pHstStrmIn->Props.cShift);
AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
- pThisStream->pvBuf = RTMemAlloc(cbBuf);
- if (!pThisStream->pvBuf)
+ pThisStrmIn->pvBuf = RTMemAlloc(cbBuf);
+ if (!pThisStrmIn->pvBuf)
{
LogRel(("ALSA: Not enough memory for input ADC buffer (%RU32 samples, each %d bytes)\n",
- obt.samples, 1 << Props.cShift));
+ obt.samples, 1 << pHstStrmIn->Props.cShift));
rc = VERR_NO_MEMORY;
break;
}
- pThisStream->cbBuf = cbBuf;
- pThisStream->phPCM = phPCM;
+ pThisStrmIn->cbBuf = cbBuf;
+ pThisStrmIn->phPCM = phPCM;
+
+ if (pcSamples)
+ *pcSamples = obt.samples;
}
while (0);
if (RT_FAILURE(rc))
- alsaStreamClose(&phPCM);
+ drvHostALSAAudioClose(&phPCM);
LogFlowFuncLeaveRC(rc);
return rc;
}
+static DECLCALLBACK(bool) drvHostALSAAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+ NOREF(pInterface);
+ NOREF(enmDir);
+ return true; /* Always all enabled. */
+}
-static int alsaControlStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
- PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostALSAAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
NOREF(pInterface);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- PALSAAUDIOSTREAMIN pThisStream = (PALSAAUDIOSTREAMIN)pStream;
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
@@ -1471,12 +1238,12 @@ static int alsaControlStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStrea
{
case PDMAUDIOSTREAMCMD_ENABLE:
case PDMAUDIOSTREAMCMD_RESUME:
- rc = drvHostALSAAudioStreamCtl(pThisStream->phPCM, false /* fStop */);
+ rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, false /* fStop */);
break;
case PDMAUDIOSTREAMCMD_DISABLE:
case PDMAUDIOSTREAMCMD_PAUSE:
- rc = drvHostALSAAudioStreamCtl(pThisStream->phPCM, true /* fStop */);
+ rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, true /* fStop */);
break;
default:
@@ -1488,13 +1255,12 @@ static int alsaControlStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStrea
return rc;
}
-
-static int alsaControlStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
- PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostALSAAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
NOREF(pInterface);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- PALSAAUDIOSTREAMOUT pThisStream = (PALSAAUDIOSTREAMOUT)pStream;
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
@@ -1503,12 +1269,12 @@ static int alsaControlStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStre
{
case PDMAUDIOSTREAMCMD_ENABLE:
case PDMAUDIOSTREAMCMD_RESUME:
- rc = drvHostALSAAudioStreamCtl(pThisStream->phPCM, false /* fStop */);
+ rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, false /* fStop */);
break;
case PDMAUDIOSTREAMCMD_DISABLE:
case PDMAUDIOSTREAMCMD_PAUSE:
- rc = drvHostALSAAudioStreamCtl(pThisStream->phPCM, true /* fStop */);
+ rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, true /* fStop */);
break;
default:
@@ -1520,244 +1286,40 @@ static int alsaControlStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStre
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
- */
-static DECLCALLBACK(int) drvHostALSAAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
+static DECLCALLBACK(int) drvHostALSAAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
{
NOREF(pInterface);
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- pBackendCfg->cbStreamIn = sizeof(ALSAAUDIOSTREAMIN);
- pBackendCfg->cbStreamOut = sizeof(ALSAAUDIOSTREAMOUT);
+ pCfg->cbStreamIn = sizeof(ALSAAUDIOSTREAMIN);
+ pCfg->cbStreamOut = sizeof(ALSAAUDIOSTREAMOUT);
- pBackendCfg->cSources = 0;
- pBackendCfg->cSinks = 0;
-
- /* Enumerate sound devices. */
- char **pszHints;
- int err = snd_device_name_hint(-1 /* All cards */, "pcm", (void***)&pszHints);
- if (err == 0)
- {
- char** pszHintCur = pszHints;
- while (*pszHintCur != NULL)
- {
- char *pszDev = snd_device_name_get_hint(*pszHintCur, "NAME");
- bool fSkip = !pszDev
- || !RTStrICmp("null", pszDev);
- if (fSkip)
- {
- if (pszDev)
- free(pszDev);
- pszHintCur++;
- continue;
- }
-
- char *pszIOID = snd_device_name_get_hint(*pszHintCur, "IOID");
- if (pszIOID)
- {
- if (!RTStrICmp("input", pszIOID))
- pBackendCfg->cSources++;
- else if (!RTStrICmp("output", pszIOID))
- pBackendCfg->cSinks++;
- }
- else /* NULL means bidirectional, input + output. */
- {
- pBackendCfg->cSources++;
- pBackendCfg->cSinks++;
- }
-
- LogRel2(("ALSA: Found %s device: %s\n", pszIOID ? RTStrToLower(pszIOID) : "bidirectional", pszDev));
-
- /* Special case for ALSAAudio. */
- if ( pszDev
- && RTStrIStr("pulse", pszDev) != NULL)
- LogRel2(("ALSA: ALSAAudio plugin in use\n"));
-
- if (pszIOID)
- free(pszIOID);
-
- if (pszDev)
- free(pszDev);
-
- pszHintCur++;
- }
-
- LogRel2(("ALSA: Found %RU8 host playback devices\n", pBackendCfg->cSinks));
- LogRel2(("ALSA: Found %RU8 host capturing devices\n", pBackendCfg->cSources));
-
- snd_device_name_free_hint((void **)pszHints);
- pszHints = NULL;
- }
- else
- LogRel2(("ALSA: Error enumerating PCM devices: %Rrc (%d)\n", RTErrConvertFromErrno(err), err));
-
- /* ALSA allows exactly one input and one output used at a time for the selected device(s). */
- pBackendCfg->cMaxStreamsIn = 1;
- pBackendCfg->cMaxStreamsOut = 1;
+ /* ALSA only allows one input and one output used at a time for
+ * the selected device. */
+ pCfg->cMaxHstStrmsIn = 1;
+ pCfg->cMaxHstStrmsOut = 1;
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
- */
static DECLCALLBACK(void) drvHostALSAAudioShutdown(PPDMIHOSTAUDIO pInterface)
{
NOREF(pInterface);
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostALSAAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- RT_NOREF(enmDir);
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
-
- return PDMAUDIOBACKENDSTS_RUNNING;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvHostALSAAudioStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
-
- int rc;
- if (pCfgReq->enmDir == PDMAUDIODIR_IN)
- rc = alsaCreateStreamIn(pStream, pCfgReq, pCfgAcq);
- else
- rc = alsaCreateStreamOut(pStream, pCfgReq, pCfgAcq);
-
- LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvHostALSAAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = alsaDestroyStreamIn(pInterface, pStream);
- else
- rc = alsaDestroyStreamOut(pInterface, pStream);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
- */
-static DECLCALLBACK(int) drvHostALSAAudioStreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = alsaControlStreamIn(pInterface, pStream, enmStreamCmd);
- else
- rc = alsaControlStreamOut(pInterface, pStream, enmStreamCmd);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostALSAAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- NOREF(pInterface);
- NOREF(pStream);
-
- PDMAUDIOSTRMSTS strmSts = PDMAUDIOSTRMSTS_FLAG_INITIALIZED
- | PDMAUDIOSTRMSTS_FLAG_ENABLED;
-
- snd_pcm_t *phPCM = NULL;
- snd_pcm_sframes_t cSamplesMin;
-
- /** @todo Get rid of this once we have a unified ALSA stream. */
- if (pStream->enmDir == PDMAUDIODIR_IN)
- {
- PALSAAUDIOSTREAMIN pStreamIn = (PALSAAUDIOSTREAMIN)pStream;
- phPCM = pStreamIn->phPCM;
- cSamplesMin = 0;
- }
- else if (pStream->enmDir == PDMAUDIODIR_OUT)
- {
- PALSAAUDIOSTREAMOUT pStreamOut = (PALSAAUDIOSTREAMOUT)pStream;
- phPCM = pStreamOut->phPCM;
- cSamplesMin = pStreamOut->cSamplesMin;
- }
- else
- AssertFailed();
-
- if (phPCM)
- {
- snd_pcm_sframes_t cSamplesAvail;
- int rc2 = alsaStreamGetAvail(phPCM, &cSamplesAvail);
- if (RT_SUCCESS(rc2))
- {
- Log3Func(("cAvail=%ld \n", cSamplesAvail));
- if (cSamplesAvail >= cSamplesMin)
- strmSts |= pStream->enmDir == PDMAUDIODIR_IN
- ? PDMAUDIOSTRMSTS_FLAG_DATA_READABLE
- : PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
- }
- }
-
- return strmSts;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
- */
-static DECLCALLBACK(int) drvHostALSAAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
-
- /* Nothing to do here for ALSA. */
- return VINF_SUCCESS;
-}
-
-
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
static DECLCALLBACK(void *) drvHostALSAAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
return NULL;
}
-
/**
* Construct a DirectSound Audio driver instance.
*
@@ -1766,7 +1328,6 @@ static DECLCALLBACK(void *) drvHostALSAAudioQueryInterface(PPDMIBASE pInterface,
static DECLCALLBACK(int) drvHostAlsaAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
RT_NOREF(pCfg, fFlags);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
LogRel(("Audio: Initializing ALSA driver\n"));
@@ -1782,7 +1343,6 @@ static DECLCALLBACK(int) drvHostAlsaAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE
return VINF_SUCCESS;
}
-
/**
* Char driver registration record.
*/
@@ -1834,7 +1394,7 @@ const PDMDRVREG g_DrvHostALSAAudio =
PDM_DRVREG_VERSION
};
-#if 0 /* unused */
+#if 0 // unused
static struct audio_option alsa_options[] =
{
{"DACSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_out,
@@ -1858,6 +1418,8 @@ static struct audio_option alsa_options[] =
"DAC device name (for instance dmix)", NULL, 0},
{"ADCDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_in,
- "ADC device name", NULL, 0}
+ "ADC device name", NULL, 0},
+
+ NULL
};
#endif
diff --git a/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp b/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp
index 7385349..11daedf 100644
--- a/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvHostCoreAudio.cpp
@@ -1,6 +1,6 @@
/* $Id: DrvHostCoreAudio.cpp $ */
/** @file
- * VBox audio devices - Mac OS X CoreAudio audio driver.
+ * VBox audio devices: Mac OS X CoreAudio audio driver.
*/
/*
@@ -14,14 +14,8 @@
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
#include <VBox/log.h>
-#include <VBox/vmm/pdmaudioifs.h>
#include "DrvAudio.h"
#include "AudioMixBuffer.h"
@@ -37,11 +31,14 @@
#include <CoreAudio/CoreAudio.h>
#include <CoreServices/CoreServices.h>
-#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioConverter.h>
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
-# include <AudioToolbox/AudioToolbox.h>
-#endif
+#include <AudioToolbox/AudioToolbox.h>
+
+/* Audio Queue buffer configuration. */
+#define AQ_BUF_COUNT 32 /* Number of buffers. */
+#define AQ_BUF_SIZE 512 /* Size of each buffer in bytes. */
+#define AQ_BUF_TOTAL (AQ_BUF_COUNT * AQ_BUF_SIZE)
+#define AQ_BUF_SAMPLES (AQ_BUF_TOTAL / 4) /* Hardcoded 4 bytes per sample! */
#if 0
# include <iprt/file.h>
@@ -53,7 +50,19 @@
# endif
#endif
-/** @todo
+/* Enables utilizing the Core Audio converter unit for converting
+ * input / output from/to our requested formats. That might be more
+ * performant than using our own routines later down the road. */
+/** @todo Needs more investigation and testing first before enabling. */
+//# define VBOX_WITH_AUDIO_CA_CONVERTER
+
+#ifdef DEBUG_andy
+# undef DEBUG_DUMP_PCM_DATA_PATH
+# define DEBUG_DUMP_PCM_DATA_PATH "/Users/anloeffl/Documents/"
+# undef VBOX_WITH_AUDIO_CA_CONVERTER
+#endif
+
+/* TODO:
* - Maybe make sure the threads are immediately stopped if playing/recording stops.
*/
@@ -63,9 +72,19 @@
* http://developer.apple.com/mac/library/technotes/tn2002/tn2091.html
* http://developer.apple.com/mac/library/qa/qa2007/qa1533.html
* http://developer.apple.com/mac/library/qa/qa2001/qa1317.html
- * http://developer.apple.com/mac/library/documentation/AudioUnit/Reference/AUComponentServicesReference/Reference/reference.html
*/
+/**
+ * Host Coreaudio driver instance data.
+ * @implements PDMIAUDIOCONNECTOR
+ */
+typedef struct DRVHOSTCOREAUDIO
+{
+ /** Pointer to the driver instance structure. */
+ PPDMDRVINS pDrvIns;
+ /** Pointer to host audio interface. */
+ PDMIHOSTAUDIO IHostAudio;
+} DRVHOSTCOREAUDIO, *PDRVHOSTCOREAUDIO;
/*******************************************************************************
*
@@ -73,16 +92,14 @@
*
******************************************************************************/
-/* Move these down below the internal function prototypes... */
-
-static void coreAudioPrintASBD(const char *pszDesc, const AudioStreamBasicDescription *pASBD)
+static void drvHostCoreAudioPrintASBD(const char *pszDesc, const AudioStreamBasicDescription *pASBD)
{
char pszSampleRate[32];
LogRel2(("CoreAudio: %s description:\n", pszDesc));
- LogRel2(("CoreAudio: Format ID: %RU32 (%c%c%c%c)\n", pASBD->mFormatID,
+ LogRel2(("CoreAudio:\tFormat ID: %RU32 (%c%c%c%c)\n", pASBD->mFormatID,
RT_BYTE4(pASBD->mFormatID), RT_BYTE3(pASBD->mFormatID),
RT_BYTE2(pASBD->mFormatID), RT_BYTE1(pASBD->mFormatID)));
- LogRel2(("CoreAudio: Flags: %RU32", pASBD->mFormatFlags));
+ LogRel2(("CoreAudio:\tFlags: %RU32", pASBD->mFormatFlags));
if (pASBD->mFormatFlags & kAudioFormatFlagIsFloat)
LogRel2((" Float"));
if (pASBD->mFormatFlags & kAudioFormatFlagIsBigEndian)
@@ -101,18 +118,18 @@ static void coreAudioPrintASBD(const char *pszDesc, const AudioStreamBasicDescri
LogRel2((" AllClear"));
LogRel2(("\n"));
snprintf(pszSampleRate, 32, "%.2f", (float)pASBD->mSampleRate); /** @todo r=andy Use RTStrPrint*. */
- LogRel2(("CoreAudio: SampleRate : %s\n", pszSampleRate));
- LogRel2(("CoreAudio: ChannelsPerFrame: %RU32\n", pASBD->mChannelsPerFrame));
- LogRel2(("CoreAudio: FramesPerPacket : %RU32\n", pASBD->mFramesPerPacket));
- LogRel2(("CoreAudio: BitsPerChannel : %RU32\n", pASBD->mBitsPerChannel));
- LogRel2(("CoreAudio: BytesPerFrame : %RU32\n", pASBD->mBytesPerFrame));
- LogRel2(("CoreAudio: BytesPerPacket : %RU32\n", pASBD->mBytesPerPacket));
+ LogRel2(("CoreAudio:\tSampleRate : %s\n", pszSampleRate));
+ LogRel2(("CoreAudio:\tChannelsPerFrame: %RU32\n", pASBD->mChannelsPerFrame));
+ LogRel2(("CoreAudio:\tFramesPerPacket : %RU32\n", pASBD->mFramesPerPacket));
+ LogRel2(("CoreAudio:\tBitsPerChannel : %RU32\n", pASBD->mBitsPerChannel));
+ LogRel2(("CoreAudio:\tBytesPerFrame : %RU32\n", pASBD->mBytesPerFrame));
+ LogRel2(("CoreAudio:\tBytesPerPacket : %RU32\n", pASBD->mBytesPerPacket));
}
-static void coreAudioPCMPropsToASBD(PDMAUDIOPCMPROPS *pPCMProps, AudioStreamBasicDescription *pASBD)
+static int drvHostCoreAudioPCMPropsToASBD(PPDMPCMPROPS pPCMProps, AudioStreamBasicDescription *pASBD)
{
- AssertPtrReturnVoid(pPCMProps);
- AssertPtrReturnVoid(pASBD);
+ AssertPtrReturn(pPCMProps, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
RT_BZERO(pASBD, sizeof(AudioStreamBasicDescription));
@@ -126,22 +143,24 @@ static void coreAudioPCMPropsToASBD(PDMAUDIOPCMPROPS *pPCMProps, AudioStreamBasi
pASBD->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
pASBD->mBytesPerFrame = pASBD->mChannelsPerFrame * (pASBD->mBitsPerChannel / 8);
pASBD->mBytesPerPacket = pASBD->mFramesPerPacket * pASBD->mBytesPerFrame;
+
+ return VINF_SUCCESS;
}
-static int coreAudioStreamCfgToASBD(PPDMAUDIOSTREAMCFG pCfg, AudioStreamBasicDescription *pASBD)
+static int drvHostCoreAudioStreamCfgToASBD(PPDMAUDIOSTREAMCFG pCfg, AudioStreamBasicDescription *pASBD)
{
AssertPtrReturn(pCfg, VERR_INVALID_PARAMETER);
AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
- PDMAUDIOPCMPROPS Props;
- int rc = DrvAudioHlpStreamCfgToProps(pCfg, &Props);
+ PDMPCMPROPS Props;
+ int rc = DrvAudioStreamCfgToProps(pCfg, &Props);
if (RT_SUCCESS(rc))
- coreAudioPCMPropsToASBD(&Props, pASBD);
+ rc = drvHostCoreAudioPCMPropsToASBD(&Props, pASBD);
return rc;
}
-static int coreAudioASBDToStreamCfg(AudioStreamBasicDescription *pASBD, PPDMAUDIOSTREAMCFG pCfg)
+static int drvHostCoreAudioASBDToStreamCfg(AudioStreamBasicDescription *pASBD, PPDMAUDIOSTREAMCFG pCfg)
{
AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
AssertPtrReturn(pCfg, VERR_INVALID_PARAMETER);
@@ -156,20 +175,20 @@ static int coreAudioASBDToStreamCfg(AudioStreamBasicDescription *pASBD, PPDMAUDI
{
switch (pASBD->mBitsPerChannel)
{
- case 8: pCfg->enmFormat = PDMAUDIOFMT_S8; break;
- case 16: pCfg->enmFormat = PDMAUDIOFMT_S16; break;
- case 32: pCfg->enmFormat = PDMAUDIOFMT_S32; break;
- default: rc = VERR_NOT_SUPPORTED; break;
+ case 8: pCfg->enmFormat = AUD_FMT_S8; break;
+ case 16: pCfg->enmFormat = AUD_FMT_S16; break;
+ case 32: pCfg->enmFormat = AUD_FMT_S32; break;
+ default: rc = VERR_NOT_SUPPORTED; break;
}
}
else
{
switch (pASBD->mBitsPerChannel)
{
- case 8: pCfg->enmFormat = PDMAUDIOFMT_U8; break;
- case 16: pCfg->enmFormat = PDMAUDIOFMT_U16; break;
- case 32: pCfg->enmFormat = PDMAUDIOFMT_U32; break;
- default: rc = VERR_NOT_SUPPORTED; break;
+ case 8: pCfg->enmFormat = AUD_FMT_U8; break;
+ case 16: pCfg->enmFormat = AUD_FMT_U16; break;
+ case 32: pCfg->enmFormat = AUD_FMT_U32; break;
+ default: rc = VERR_NOT_SUPPORTED; break;
}
}
@@ -177,110 +196,8 @@ static int coreAudioASBDToStreamCfg(AudioStreamBasicDescription *pASBD, PPDMAUDI
return rc;
}
-#ifndef VBOX_WITH_AUDIO_CA_QUEUES
-static OSStatus coreAudioSetFrameBufferSize(AudioDeviceID deviceID, bool fInput, UInt32 cReqSize, UInt32 *pcActSize)
-{
- AudioObjectPropertyScope propScope = fInput
- ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
- AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyBufferFrameSize, propScope,
- kAudioObjectPropertyElementMaster };
-
- /* First try to set the new frame buffer size. */
- OSStatus err = AudioObjectSetPropertyData(deviceID, &propAdr, 0, NULL, sizeof(cReqSize), &cReqSize);
-
- /* Check if it really was set. */
- UInt32 cSize = sizeof(*pcActSize);
- err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &cSize, pcActSize);
- if (RT_UNLIKELY(err != noErr))
- return err;
-
- /* If both sizes are the same, we are done. */
- if (cReqSize == *pcActSize)
- return noErr;
-
- /* If not we have to check the limits of the device. First get the size of
- the buffer size range property. */
- propAdr.mSelector = kAudioDevicePropertyBufferSizeRange;
- err = AudioObjectGetPropertyDataSize(deviceID, &propAdr, 0, NULL, &cSize);
- if (RT_UNLIKELY(err != noErr))
- return err;
-
- Assert(cSize);
- AudioValueRange *pRange = (AudioValueRange *)RTMemAllocZ(cSize);
- if (pRange)
- {
- err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &cSize, pRange);
- if (err == noErr)
- {
- Float64 cMin = -1;
- Float64 cMax = -1;
- for (size_t a = 0; a < cSize / sizeof(AudioValueRange); a++)
- {
- /* Search for the absolute minimum. */
- if ( pRange[a].mMinimum < cMin
- || cMin == -1)
- cMin = pRange[a].mMinimum;
-
- /* Search for the best maximum which isn't bigger than cReqSize. */
- if (pRange[a].mMaximum < cReqSize)
- {
- if (pRange[a].mMaximum > cMax)
- cMax = pRange[a].mMaximum;
- }
- }
- if (cMax == -1)
- cMax = cMin;
- cReqSize = cMax;
-
- /* First try to set the new frame buffer size. */
- propAdr.mSelector = kAudioDevicePropertyBufferFrameSize;
- err = AudioObjectSetPropertyData(deviceID, &propAdr, 0, NULL, sizeof(cReqSize), &cReqSize);
- if (err == noErr)
- {
- /* Check if it really was set. */
- cSize = sizeof(*pcActSize);
- err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &cSize, pcActSize);
- }
- }
-
- RTMemFree(pRange);
- }
- else
- err = notEnoughMemoryErr;
-
- return err;
-}
-
-DECL_FORCE_INLINE(bool) coreAudioIsRunning(AudioDeviceID deviceID)
-{
- AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsRunning, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- UInt32 uFlag = 0;
- UInt32 uSize = sizeof(uFlag);
- OSStatus err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &uSize, &uFlag);
- if (err != kAudioHardwareNoError)
- LogRel(("CoreAudio: Could not determine whether the device is running (%RI32)\n", err));
-
- return (uFlag >= 1);
-}
-
-static int coreAudioCFStringToCString(const CFStringRef pCFString, char **ppszString)
-{
- CFIndex cLen = CFStringGetLength(pCFString) + 1;
- char *pszResult = (char *)RTMemAllocZ(cLen * sizeof(char));
- if (!CFStringGetCString(pCFString, pszResult, cLen, kCFStringEncodingUTF8))
- {
- RTMemFree(pszResult);
- return VERR_NOT_FOUND;
- }
-
- *ppszString = pszResult;
- return VINF_SUCCESS;
-}
-#endif /* VBOX_WITH_AUDIO_CA_QUEUES */
-
-#if 0 /* unused */
-static AudioDeviceID coreAudioDeviceUIDtoID(const char* pszUID)
+#if 0 // unused
+static AudioDeviceID drvHostCoreAudioDeviceUIDtoID(const char* pszUID)
{
/* Create a CFString out of our CString. */
CFStringRef strUID = CFStringCreateWithCString(NULL, pszUID, kCFStringEncodingMacRoman);
@@ -310,63 +227,34 @@ static AudioDeviceID coreAudioDeviceUIDtoID(const char* pszUID)
/* Return the unknown device on error. */
return kAudioDeviceUnknown;
}
-#endif /* unused */
-
+#endif
-/*********************************************************************************************************************************
-* Defined Constants And Macros *
-*********************************************************************************************************************************/
-/** @name Initialization status indicator used for the recreation of the AudioUnits.
- * @{ */
-#define CA_STATUS_UNINIT UINT32_C(0) /**< The device is uninitialized */
-#define CA_STATUS_IN_INIT UINT32_C(1) /**< The device is currently initializing */
-#define CA_STATUS_INIT UINT32_C(2) /**< The device is initialized */
-#define CA_STATUS_IN_UNINIT UINT32_C(3) /**< The device is currently uninitializing */
-#define CA_STATUS_REINIT UINT32_C(4) /**< The device has to be reinitialized */
-/** @} */
+/*******************************************************************************
+ *
+ * Global structures section
+ *
+ ******************************************************************************/
+/* Initialization status indicator used for device (re)initialization. */
+#define CA_STATUS_UNINIT UINT32_C(0) /* The device is uninitialized */
+#define CA_STATUS_IN_INIT UINT32_C(1) /* The device is currently initializing */
+#define CA_STATUS_INIT UINT32_C(2) /* The device is initialized */
+#define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
+#define CA_STATUS_REINIT UINT32_C(4) /* The device has to be reinitialized */
-/*********************************************************************************************************************************
-* Global Variables *
-*********************************************************************************************************************************/
#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
/* Error code which indicates "End of data" */
-static const OSStatus g_caConverterEOFDErr = 0x656F6664; /* 'eofd' */
+static const OSStatus caConverterEOFDErr = 0x656F6664; /* 'eofd' */
#endif
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
/* Prototypes needed for COREAUDIOSTREAMCBCTX. */
struct COREAUDIOSTREAMIN;
typedef struct COREAUDIOSTREAMIN *PCOREAUDIOSTREAMIN;
struct COREAUDIOSTREAMOUT;
typedef struct COREAUDIOSTREAMOUT *PCOREAUDIOSTREAMOUT;
-/**
- * Host Coreaudio driver instance data.
- * @implements PDMIAUDIOCONNECTOR
- */
-typedef struct DRVHOSTCOREAUDIO
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
-} DRVHOSTCOREAUDIO, *PDRVHOSTCOREAUDIO;
-
-/** Converts a pointer to DRVHOSTCOREAUDIO::IHostAudio to a PDRVHOSTCOREAUDIO. */
-#define PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface) RT_FROM_MEMBER(pInterface, DRVHOSTCOREAUDIO, IHostAudio)
-
-/**
- * Simple structure for maintaining a stream's callback context.
- ** @todo Remove this as soon as we have unified input/output streams in this backend.
- */
typedef struct COREAUDIOSTREAM
{
- /** Pointer to driver instance. */
- PDRVHOSTCOREAUDIO pThis;
/** The stream's direction. */
PDMAUDIODIR enmDir;
union
@@ -375,8 +263,8 @@ typedef struct COREAUDIOSTREAM
PCOREAUDIOSTREAMIN pIn;
/** Pointer to self, if it's an output stream. */
PCOREAUDIOSTREAMOUT pOut;
+ /** @todo Add attributes here as soon as COREAUDIOSTREAMIN / COREAUDIOSTREAMOUT are unified. */
};
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
/** The stream's thread handle for maintaining the audio queue. */
RTTHREAD hThread;
/** Flag indicating to start a stream's data processing. */
@@ -392,17 +280,27 @@ typedef struct COREAUDIOSTREAM
/** The actual audio queue being used. */
AudioQueueRef audioQueue;
/** The audio buffers which are used with the above audio queue. */
- AudioQueueBufferRef audioBuffer[3];
+ AudioQueueBufferRef audioBuffer[AQ_BUF_COUNT];
/** The acquired (final) audio format for this stream. */
AudioStreamBasicDescription asbdStream;
/** The device' UUID. */
CFStringRef UUID;
/** An internal ring buffer for transferring data from/to the rendering callbacks. */
PRTCIRCBUF pCircBuf;
-#endif
} COREAUDIOSTREAM, *PCOREAUDIOSTREAM;
/**
+ * Simple structure for maintaining a stream's callback context.
+ */
+typedef struct COREAUDIOSTREAMCBCTX
+{
+ /** Pointer to driver instance. */
+ PDRVHOSTCOREAUDIO pThis;
+ /** Pointer to the stream being handled. Can be NULL if not used. */
+ PCOREAUDIOSTREAM pStream;
+} COREAUDIOSTREAMCBCTX, *PCOREAUDIOSTREAMCBCTX;
+
+/**
* Structure for keeping a conversion callback context.
* This is needed when using an audio converter during input/output processing.
*/
@@ -411,17 +309,19 @@ typedef struct COREAUDIOCONVCBCTX
/** Pointer to stream context this converter callback context
* is bound to. */
/** @todo Remove this as soon as we have unified input/output streams in this backend. */
- COREAUDIOSTREAM Stream;
+ PCOREAUDIOSTREAMCBCTX pStreamCtx;
/** Source stream description. */
- AudioStreamBasicDescription asbdSrc;
+ AudioStreamBasicDescription asbdSrc;
/** Destination stream description. */
- AudioStreamBasicDescription asbdDst;
- /** Native buffer list used for rendering the source audio data into. */
- AudioBufferList bufLstSrc;
+ AudioStreamBasicDescription asbdDst;
+ /** Pointer to native buffer list used for rendering the source audio data into. */
+ AudioBufferList *pBufLstSrc;
/** Total packet conversion count. */
- UInt32 uPacketCnt;
+ UInt32 uPacketCnt;
/** Current packet conversion index. */
- UInt32 uPacketIdx;
+ UInt32 uPacketIdx;
+ /** Error count, for limiting the logging. */
+ UInt32 cErrors;
} COREAUDIOCONVCBCTX, *PCOREAUDIOCONVCBCTX;
/** @todo Unify COREAUDIOSTREAMOUT / COREAUDIOSTREAMIN. */
@@ -429,18 +329,9 @@ typedef struct COREAUDIOSTREAMOUT
{
/** Host output stream.
* Note: Always must come first in this structure! */
- PDMAUDIOSTREAM Stream;
- /** Common stream data.
- * @todo Remove this as soon as we have unified input/output streams in this backend. */
- COREAUDIOSTREAM Common;
- /** Stream description which is default on the device. */
- AudioStreamBasicDescription deviceFormat;
- /** Stream description which is selected for using with VBox. */
- AudioStreamBasicDescription streamFormat;
+ PDMAUDIOHSTSTRMOUT streamOut;
/** The audio device ID of the currently used device. */
AudioDeviceID deviceID;
- /** The AudioUnit being used. */
- AudioUnit audioUnit;
/** A ring buffer for transferring data to the playback thread. */
PRTCIRCBUF pCircBuf;
/** Initialization status tracker. Used when some of the device parameters
@@ -450,32 +341,29 @@ typedef struct COREAUDIOSTREAMOUT
bool fDefDevChgListReg;
/** Flag whether the "device state changed" listener was registered. */
bool fDevStateChgListReg;
+ /** Unified attribtues. */
+ /** @todo Remove this as soon as we have unified input/output streams in this backend. */
+ COREAUDIOSTREAM Stream;
+ /** Callback context for this stream for handing this stream in an CoreAudio callback.
+ ** @todo Remove this as soon as we have unified input/output streams in this backend. */
+ COREAUDIOSTREAMCBCTX cbCtx;
} COREAUDIOSTREAMOUT, *PCOREAUDIOSTREAMOUT;
typedef struct COREAUDIOSTREAMIN
{
/** Host input stream.
* Note: Always must come first in this structure! */
- PDMAUDIOSTREAM Stream;
- /** Common stream data.
- * @todo Remove this as soon as we have unified input/output streams in this backend. */
- COREAUDIOSTREAM Common;
- /** Stream description which is default on the device. */
- AudioStreamBasicDescription deviceFormat;
- /** Stream description which is selected for using with VBox. */
- AudioStreamBasicDescription streamFormat;
+ PDMAUDIOHSTSTRMIN streamIn;
/** The audio device ID of the currently used device. */
AudioDeviceID deviceID;
- /** The AudioUnit used. */
- AudioUnit audioUnit;
- /** A ring buffer for transferring data to the playback thread. */
+ /** A ring buffer for transferring data from the recording thread. */
PRTCIRCBUF pCircBuf;
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
/** The audio converter if necessary. NULL if no converter is being used. */
- AudioConverterRef pConverter;
+ AudioConverterRef ConverterRef;
/** Callback context for the audio converter. */
COREAUDIOCONVCBCTX convCbCtx;
- /** The ratio between the device & the stream sample rate. */
- Float64 sampleRatio;
+#endif
/** Initialization status tracker. Used when some of the device parameters
* or the device itself is changed during the runtime. */
volatile uint32_t status;
@@ -483,75 +371,28 @@ typedef struct COREAUDIOSTREAMIN
bool fDefDevChgListReg;
/** Flag whether the "device state changed" listener was registered. */
bool fDevStateChgListReg;
+ /** Unified attribtues. */
+ /** @todo Remove this as soon as we have unified input/output streams in this backend. */
+ COREAUDIOSTREAM Stream;
+ /** Callback context for this stream for handing this stream in an CoreAudio callback.
+ ** @todo Remove this as soon as we have unified input/output streams in this backend. */
+ COREAUDIOSTREAMCBCTX cbCtx;
} COREAUDIOSTREAMIN, *PCOREAUDIOSTREAMIN;
+static int drvHostCoreAudioReinitInput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+static int drvHostCoreAudioReinitOutput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
-/*********************************************************************************************************************************
-* Internal Functions *
-*********************************************************************************************************************************/
-static OSStatus coreAudioPlaybackAudioDevicePropertyChanged(AudioObjectID propertyID, UInt32 cAddresses, const AudioObjectPropertyAddress properties[], void *pvUser);
-#ifndef VBOX_WITH_AUDIO_CA_QUEUES
-static int coreAudioStreamInitIn(PCOREAUDIOSTREAMIN pStreamIn, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq);
-static int coreAudioStreamInitOut(PCOREAUDIOSTREAMOUT pStreamOut, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq);
-static OSStatus coreAudioPlaybackCb(void *pvUser, AudioUnitRenderActionFlags *pActionFlags, const AudioTimeStamp *pAudioTS, UInt32 uBusID, UInt32 cFrames, AudioBufferList* pBufData);
-#endif
+static int drvHostCoreAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd);
+static int drvHostCoreAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd);
+static int drvHostCoreAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn);
+static int drvHostCoreAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
-static int coreAudioControlStreamIn(PCOREAUDIOSTREAMIN pCAStreamIn, PDMAUDIOSTREAMCMD enmStreamCmd);
-static int coreAudioControlStreamOut(PCOREAUDIOSTREAMOUT pCAStreamOut, PDMAUDIOSTREAMCMD enmStreamCmd);
+static OSStatus drvHostCoreAudioDevPropChgCb(AudioObjectID propertyID, UInt32 nAddresses, const AudioObjectPropertyAddress properties[], void *pvUser);
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
static void coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer, const AudioTimeStamp *pAudioTS, UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc);
static void coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer);
-#endif
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
-/**
- * Initializes a conversion callback context.
- *
- * @return IPRT status code.
- * @param pConvCbCtx Conversion callback context to initialize.
- * @param pASBDSrc Input (source) stream description to use.
- * @param pASBDDst Output (destination) stream description to use.
- */
-static int coreAudioInitConvCbCtx(PCOREAUDIOCONVCBCTX pConvCbCtx,
- AudioStreamBasicDescription *pASBDSrc, AudioStreamBasicDescription *pASBDDst)
-{
- AssertPtrReturn(pConvCbCtx, VERR_INVALID_POINTER);
- AssertPtrReturn(pASBDSrc, VERR_INVALID_POINTER);
- AssertPtrReturn(pASBDDst, VERR_INVALID_POINTER);
-
- memcpy(&pConvCbCtx->asbdSrc, pASBDSrc, sizeof(AudioStreamBasicDescription));
- memcpy(&pConvCbCtx->asbdDst, pASBDDst, sizeof(AudioStreamBasicDescription));
-
- /* Create the AudioBufferList structure with one buffer. */
- pConvCbCtx->bufLstSrc.mNumberBuffers = 1;
-
- /* Initialize the conversion buffer. */
- pConvCbCtx->bufLstSrc.mBuffers[0].mNumberChannels = pConvCbCtx->asbdSrc.mChannelsPerFrame;
- pConvCbCtx->bufLstSrc.mBuffers[0].mDataByteSize = 0;
- pConvCbCtx->bufLstSrc.mBuffers[0].mData = NULL;
-
- return VINF_SUCCESS;
-}
-
-/**
- * Uninitializes a conversion callback context.
- *
- * @return IPRT status code.
- * @param pConvCbCtx Conversion callback context to uninitialize.
- */
-static void coreAudioUninitConvCbCtx(PCOREAUDIOCONVCBCTX pConvCbCtx)
-{
- AssertPtrReturnVoid(pConvCbCtx);
-
- RT_ZERO(pConvCbCtx->asbdSrc);
- RT_ZERO(pConvCbCtx->asbdDst);
-
- pConvCbCtx->bufLstSrc.mNumberBuffers = 0;
-}
-#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
-
/**
* Does a (Re-)enumeration of the host's playback + recording devices.
*
@@ -560,7 +401,7 @@ static void coreAudioUninitConvCbCtx(PCOREAUDIOCONVCBCTX pConvCbCtx)
* @param pCfg Where to store the enumeration results.
* @param fEnum Enumeration flags.
*/
-static int coreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, bool fIn, uint32_t fEnum)
+static int drvHostCoreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, bool fIn, uint32_t fEnum)
{
RT_NOREF(fEnum);
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
@@ -605,17 +446,16 @@ static int coreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCF
if (!pBufList)
continue;
- bool fIsValid = false;
+ bool fIsValid = false;
+ uint16_t cChannels = 0;
err = AudioObjectGetPropertyData(curDevID, &propAddrCfg, 0, NULL, &uSize, pBufList);
if (err == noErr)
{
for (UInt32 a = 0; a < pBufList->mNumberBuffers; a++)
- {
- fIsValid = pBufList->mBuffers[a].mNumberChannels > 0;
- if (fIsValid)
- break;
- }
+ cChannels += pBufList->mBuffers[a].mNumberChannels;
+
+ fIsValid = cChannels > 0;
}
if (pBufList)
@@ -645,7 +485,8 @@ static int coreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCF
if ( pszName
&& CFStringGetCString(pcfstrName, pszName, uMax, kCFStringEncodingUTF8))
{
- LogRel2(("CoreAudio: Found %s device '%s'\n", fIn ? "recording" : "playback", pszName));
+ LogRel2(("CoreAudio: Found %s device '%s' (%RU16 channels max)\n",
+ fIn ? "recording" : "playback", pszName, cChannels));
cDevs++;
}
@@ -669,9 +510,9 @@ static int coreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCF
if (pCfg)
{
if (fIn)
- pCfg->cSources = cDevs;
+ pCfg->cMaxHstStrmsIn = cDevs;
else
- pCfg->cSinks = cDevs;
+ pCfg->cMaxHstStrmsOut = cDevs;
}
LogFlowFuncLeaveRC(rc);
@@ -695,14 +536,12 @@ int coreAudioUpdateStatusInternalEx(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG
PDMAUDIOBACKENDCFG Cfg;
RT_ZERO(Cfg);
- Cfg.cbStreamOut = sizeof(COREAUDIOSTREAMOUT);
- Cfg.cbStreamIn = sizeof(COREAUDIOSTREAMIN);
- Cfg.cMaxStreamsIn = UINT32_MAX;
- Cfg.cMaxStreamsOut = UINT32_MAX;
+ Cfg.cbStreamOut = sizeof(COREAUDIOSTREAMOUT);
+ Cfg.cbStreamIn = sizeof(COREAUDIOSTREAMIN);
- int rc = coreAudioDevicesEnumerate(pThis, &Cfg, false /* fIn */, 0 /* fEnum */);
+ int rc = drvHostCoreAudioDevicesEnumerate(pThis, &Cfg, false /* fIn */, 0 /* fEnum */);
AssertRC(rc);
- rc = coreAudioDevicesEnumerate(pThis, &Cfg, true /* fIn */, 0 /* fEnum */);
+ rc = drvHostCoreAudioDevicesEnumerate(pThis, &Cfg, true /* fIn */, 0 /* fEnum */);
AssertRC(rc);
if (pCfg)
@@ -712,20 +551,17 @@ int coreAudioUpdateStatusInternalEx(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG
return rc;
}
-
-/**
- * Implements the OS X callback AudioObjectPropertyListenerProc.
- */
-static OSStatus drvHostCoreAudioDeviceStateChanged(AudioObjectID propertyID,
- UInt32 cAddresses,
- const AudioObjectPropertyAddress paProperties[],
- void *pvUser)
+static DECLCALLBACK(OSStatus) drvHostCoreAudioDeviceStateChangedCb(AudioObjectID propertyID,
+ UInt32 nAddresses,
+ const AudioObjectPropertyAddress properties[],
+ void *pvUser)
{
- RT_NOREF(propertyID, cAddresses, paProperties)
- LogFlowFunc(("propertyID=%u cAddresses=%u pvUser=%p\n", propertyID, cAddresses, pvUser));
+ RT_NOREF(propertyID, nAddresses, properties);
+ LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
- PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
- AssertPtr(pCAStream);
+ PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
+ AssertPtr(pCbCtx);
+ AssertPtr(pCbCtx->pStream);
UInt32 uAlive = 1;
UInt32 uSize = sizeof(UInt32);
@@ -733,8 +569,8 @@ static OSStatus drvHostCoreAudioDeviceStateChanged(AudioObjectID propertyID,
AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
- AudioDeviceID deviceID = pCAStream->enmDir == PDMAUDIODIR_IN
- ? pCAStream->pIn->deviceID : pCAStream->pOut->deviceID;
+ AudioDeviceID deviceID = pCbCtx->pStream->enmDir == PDMAUDIODIR_IN
+ ? pCbCtx->pStream->pIn->deviceID : pCbCtx->pStream->pOut->deviceID;
OSStatus err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &uSize, &uAlive);
@@ -747,11 +583,11 @@ static OSStatus drvHostCoreAudioDeviceStateChanged(AudioObjectID propertyID,
if (fIsDead)
{
- switch (pCAStream->enmDir)
+ switch (pCbCtx->pStream->enmDir)
{
case PDMAUDIODIR_IN:
{
- PCOREAUDIOSTREAMIN pStreamIn = pCAStream->pIn;
+ PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
/* We move the reinitialization to the next output event.
* This make sure this thread isn't blocked and the
@@ -764,7 +600,7 @@ static OSStatus drvHostCoreAudioDeviceStateChanged(AudioObjectID propertyID,
case PDMAUDIODIR_OUT:
{
- PCOREAUDIOSTREAMOUT pStreamOut = pCAStream->pOut;
+ PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
/* We move the reinitialization to the next output event.
* This make sure this thread isn't blocked and the
@@ -781,32 +617,30 @@ static OSStatus drvHostCoreAudioDeviceStateChanged(AudioObjectID propertyID,
}
}
- int rc2 = coreAudioDevicesEnumerate(pCAStream->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
+ int rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
AssertRC(rc2);
- rc2 = coreAudioDevicesEnumerate(pCAStream->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
+ rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
AssertRC(rc2);
return noErr;
}
-
-/**
- * Implements the OS X callback AudioObjectPropertyListenerProc for getting
- * notified when the default recording/playback device has been changed.
- */
-static OSStatus coreAudioDefaultDeviceChanged(AudioObjectID propertyID,
- UInt32 cAddresses,
- const AudioObjectPropertyAddress properties[],
- void *pvUser)
+/* Callback for getting notified when the default recording/playback device has been changed. */
+static DECLCALLBACK(OSStatus) drvHostCoreAudioDefaultDeviceChangedCb(AudioObjectID propertyID,
+ UInt32 nAddresses,
+ const AudioObjectPropertyAddress properties[],
+ void *pvUser)
{
RT_NOREF(propertyID);
- LogFlowFunc(("propertyID=%u cAddresses=%u pvUser=%p\n", propertyID, cAddresses, pvUser));
+ OSStatus err = noErr;
- PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
- AssertPtr(pCAStream);
+ LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
- OSStatus err = noErr;
- for (UInt32 idxAddress = 0; idxAddress < cAddresses; idxAddress++)
+ PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
+ AssertPtr(pCbCtx);
+ AssertPtr(pCbCtx->pStream);
+
+ for (UInt32 idxAddress = 0; idxAddress < nAddresses; idxAddress++)
{
const AudioObjectPropertyAddress *pProperty = &properties[idxAddress];
@@ -814,7 +648,7 @@ static OSStatus coreAudioDefaultDeviceChanged(AudioObjectID propertyID,
{
case kAudioHardwarePropertyDefaultInputDevice:
{
- PCOREAUDIOSTREAMIN pStreamIn = pCAStream->pIn;
+ PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
AssertPtr(pStreamIn);
/* This listener is called on every change of the hardware
@@ -840,7 +674,7 @@ static OSStatus coreAudioDefaultDeviceChanged(AudioObjectID propertyID,
case kAudioHardwarePropertyDefaultOutputDevice:
{
- PCOREAUDIOSTREAMOUT pStreamOut = pCAStream->pOut;
+ PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
AssertPtr(pStreamOut);
/* This listener is called on every change of the hardware
@@ -872,9 +706,9 @@ static OSStatus coreAudioDefaultDeviceChanged(AudioObjectID propertyID,
}
}
- int rc2 = coreAudioDevicesEnumerate(pCAStream->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
+ int rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
AssertRC(rc2);
- rc2 = coreAudioDevicesEnumerate(pCAStream->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
+ rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
AssertRC(rc2);
/** @todo Implement callback notification here to let the audio connector / device emulation
@@ -883,7 +717,6 @@ static OSStatus coreAudioDefaultDeviceChanged(AudioObjectID propertyID,
return noErr;
}
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
/**
* Thread for a Core Audio stream's audio queue handling.
* This thread is required per audio queue to pump data to/from the Core Audio stream and
@@ -914,17 +747,28 @@ static DECLCALLBACK(int) coreAudioQueueThread(RTTHREAD hThreadSelf, void *pvUser
CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
if (err != noErr)
+ {
+ LogRel(("CoreAudio: Failed to create audio queue (%RI32)\n", err));
return VERR_GENERAL_FAILURE; /** @todo Fudge! */
+ }
+ ///@todo: The following code may cause subsequent AudioQueueStart to fail
+ // with !dev error (560227702). If we skip it entirely, we end up using the
+ // default device, which is what we're doing anyway.
+#if 0
/*
* Assign device to queue.
*/
UInt32 uSize = sizeof(pCAStream->UUID);
err = AudioQueueSetProperty(pCAStream->audioQueue, kAudioQueueProperty_CurrentDevice, &pCAStream->UUID, uSize);
if (err != noErr)
+ {
+ LogRel(("CoreAudio: Failed to set queue device UUID (%d)\n", err));
return VERR_GENERAL_FAILURE; /** @todo Fudge! */
+ }
+#endif
- const size_t cbBufSize = _4K; /** @todo Make this configurable! */
+ const size_t cbBufSize = AQ_BUF_SIZE; /** @todo Make this configurable! */
/*
* Allocate audio buffers.
@@ -971,6 +815,7 @@ static DECLCALLBACK(int) coreAudioQueueThread(RTTHREAD hThreadSelf, void *pvUser
}
AudioQueueDispose(pCAStream->audioQueue, 1);
+ pCAStream->audioQueue = NULL;
LogFunc(("Ended pCAStream=%p\n", pCAStream));
return VINF_SUCCESS;
@@ -1191,7 +1036,6 @@ static int coreAudioStreamInvalidateQueue(PCOREAUDIOSTREAM pCAStream)
static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, bool fIn, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
{
RT_NOREF(pCfgAcq);
-
LogFunc(("pCAStream=%p, pCfgReq=%p, pCfgAcq=%p\n", pCAStream, pCfgReq, pCfgAcq));
AudioDeviceID deviceID = kAudioDeviceUnknown;
@@ -1223,7 +1067,7 @@ static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, bool fIn, PPDMAU
}
/* Create the recording device's out format based on our required audio settings. */
- int rc = coreAudioStreamCfgToASBD(pCfgReq, &pCAStream->asbdStream);
+ int rc = drvHostCoreAudioStreamCfgToASBD(pCfgReq, &pCAStream->asbdStream);
if (RT_FAILURE(rc))
{
LogRel(("CoreAudio: Failed to convert requested %s format to native format (%Rrc)\n",
@@ -1245,9 +1089,9 @@ static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, bool fIn, PPDMAU
pCAStream->pOut->deviceID = deviceID;
}
- coreAudioPrintASBD( fIn
- ? "Capturing queue format"
- : "Playback queue format", &pCAStream->asbdStream);
+ drvHostCoreAudioPrintASBD( fIn
+ ? "Capturing queue format"
+ : "Playback queue format", &pCAStream->asbdStream);
rc = RTCircBufCreate(&pCAStream->pCircBuf, 8096 << 1 /*pHstStrmIn->Props.cShift*/); /** @todo FIX THIS !!! */
if (RT_FAILURE(rc))
@@ -1256,6 +1100,7 @@ static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, bool fIn, PPDMAU
/*
* Start the thread.
*/
+ pCAStream->fShutdown = false;
rc = RTThreadCreate(&pCAStream->hThread, coreAudioQueueThread,
pCAStream /* pvUser */, 0 /* Default stack size */,
RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "CAQUEUE");
@@ -1304,8 +1149,8 @@ static int coreAudioStreamUninitQueue(PCOREAUDIOSTREAM pCAStream)
LogFunc(("Returning\n"));
return VINF_SUCCESS;
}
-#endif /* VBOX_WITH_AUDIO_CA_QUEUES */
+#if 0 // unused
/**
* Unitializes a Core Audio stream.
*
@@ -1316,43 +1161,36 @@ static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream)
{
LogFunc(("pCAStream=%p\n", pCAStream));
- int rc;
-
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = coreAudioStreamUninitQueue(pCAStream);
-#else
- rc = VINF_SUCCESS;
-#endif
-
+ int rc = coreAudioStreamUninitQueue(pCAStream);
return rc;
}
+#endif
-static int coreAudioStreamReinitIn(PCOREAUDIOSTREAM pCAStream)
+static int drvHostCoreAudioReinitInput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
- int rc = coreAudioStreamUninit(pCAStream);
+ int rc = drvHostCoreAudioFiniIn(pInterface, pHstStrmIn);
if (RT_SUCCESS(rc))
{
+ PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
+
PDMAUDIOSTREAMCFG CfgAcq;
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = coreAudioASBDToStreamCfg(&pCAStream->asbdStream, &CfgAcq);
-#else
- rc = coreAudioASBDToStreamCfg(&pCAStream->pIn->streamFormat, &CfgAcq);
-#endif
+ rc = drvHostCoreAudioASBDToStreamCfg(&pStreamIn->cbCtx.pStream->asbdStream, &CfgAcq);
if (RT_SUCCESS(rc))
{
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = coreAudioStreamInitQueue(pCAStream, true /* fInput */, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
-#else
- /* Use the acquired stream configuration from the former initialization to
- * re-initialize the stream. */
- rc = coreAudioStreamInitIn(pCAStream->pIn, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
-#endif
+ int rc2;
+ rc2 = RTCritSectInit(&pStreamIn->cbCtx.pStream->CritSect);
+ AssertRC(rc2);
+
+ rc = coreAudioStreamInitQueue(pStreamIn->cbCtx.pStream, true /* fInput */, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
if (RT_SUCCESS(rc))
- rc = coreAudioControlStreamIn(pCAStream->pIn, PDMAUDIOSTREAMCMD_ENABLE);
+ {
+ ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_INIT);
+ rc = drvHostCoreAudioControlIn(pInterface, pHstStrmIn, PDMAUDIOSTREAMCMD_ENABLE);
+ }
if (RT_FAILURE(rc))
{
- int rc2 = coreAudioStreamUninit(pCAStream);
+ rc2 = drvHostCoreAudioFiniIn(pInterface, pHstStrmIn);
AssertRC(rc2);
}
}
@@ -1364,32 +1202,31 @@ static int coreAudioStreamReinitIn(PCOREAUDIOSTREAM pCAStream)
return rc;
}
-static int coreAudioStreamReinitOut(PCOREAUDIOSTREAM pCAStream)
+static int drvHostCoreAudioReinitOutput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
- int rc = coreAudioStreamUninit(pCAStream);
+ int rc = drvHostCoreAudioFiniOut(pInterface, pHstStrmOut);
if (RT_SUCCESS(rc))
{
+ PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
+
PDMAUDIOSTREAMCFG CfgAcq;
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = coreAudioASBDToStreamCfg(&pCAStream->asbdStream, &CfgAcq);
-#else
- rc = coreAudioASBDToStreamCfg(&pCAStream->pOut->streamFormat, &CfgAcq);
-#endif
+ rc = drvHostCoreAudioASBDToStreamCfg(&pStreamOut->cbCtx.pStream->asbdStream, &CfgAcq);
if (RT_SUCCESS(rc))
{
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = coreAudioStreamInitQueue(pCAStream, false /* fInput */, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
-#else
- /* Use the acquired stream configuration from the former initialization to
- * re-initialize the stream. */
- rc = coreAudioStreamInitOut(pCAStream->pOut, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
-#endif
+ int rc2;
+ rc2 = RTCritSectInit(&pStreamOut->cbCtx.pStream->CritSect);
+ AssertRC(rc2);
+
+ rc = coreAudioStreamInitQueue(pStreamOut->cbCtx.pStream, false /* fInput */, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
if (RT_SUCCESS(rc))
- rc = coreAudioControlStreamOut(pCAStream->pOut, PDMAUDIOSTREAMCMD_ENABLE);
+ {
+ ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_INIT);
+ rc = drvHostCoreAudioControlOut(pInterface, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
+ }
if (RT_FAILURE(rc))
{
- int rc2 = coreAudioStreamUninit(pCAStream);
+ rc2 = drvHostCoreAudioFiniOut(pInterface, pHstStrmOut);
AssertRC(rc2);
}
}
@@ -1401,59 +1238,17 @@ static int coreAudioStreamReinitOut(PCOREAUDIOSTREAM pCAStream)
return rc;
}
-/**
- * Implements the OS X callback AudioObjectPropertyListenerProc for getting
- * notified when some of the properties of an audio device has changed.
- */
-static OSStatus coreAudioRecordingAudioDevicePropertyChanged(AudioObjectID propertyID,
- UInt32 cAddresses,
- const AudioObjectPropertyAddress paProperties[],
- void *pvUser)
-{
- RT_NOREF(cAddresses, paProperties);
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pvUser;
-
- switch (propertyID)
- {
-#ifdef DEBUG
- case kAudioDeviceProcessorOverload:
- {
- LogFunc(("Processor overload detected!\n"));
- break;
- }
-#endif /* DEBUG */
- case kAudioDevicePropertyNominalSampleRate:
- {
- LogRel(("CoreAudio: Recording sample rate changed\n"));
-
- /* We move the reinitialization to the next input event.
- * This make sure this thread isn't blocked and the
- * reinitialization is done when necessary only. */
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
- break;
- }
-
- default:
- break;
- }
-
- return noErr;
-}
-
#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
-/**
- * Implements the OS X callback AudioConverterComplexInputDataProc for
- * converting audio input data from one format to another.
- */
-static OSStatus coreAudioConverterCallback(AudioConverterRef inAudioConverter,
- UInt32 *ioNumberDataPackets,
- AudioBufferList *ioData,
- AudioStreamPacketDescription **ppASPD,
- void *pvUser)
+/* Callback to convert audio input data from one format to another. */
+static DECLCALLBACK(OSStatus) drvHostCoreAudioConverterCb(AudioConverterRef inAudioConverter,
+ UInt32 *ioNumberDataPackets,
+ AudioBufferList *ioData,
+ AudioStreamPacketDescription **ppASPD,
+ void *pvUser)
{
- RT_NOREF(inAudioConverter, ppASPD);
- AssertPtrReturn(ioNumberDataPackets, g_caConverterEOFDErr);
- AssertPtrReturn(ioData, g_caConverterEOFDErr);
+ RT_NOREF(inAudioConverter);
+ AssertPtrReturn(ioNumberDataPackets, caConverterEOFDErr);
+ AssertPtrReturn(ioData, caConverterEOFDErr);
PCOREAUDIOCONVCBCTX pConvCbCtx = (PCOREAUDIOCONVCBCTX)pvUser;
AssertPtr(pConvCbCtx);
@@ -1463,55 +1258,64 @@ static OSStatus coreAudioConverterCallback(AudioConverterRef inAudi
ioData->mBuffers[0].mDataByteSize = 0;
ioData->mBuffers[0].mData = NULL;
- /** @todo Check converter ID? */
+ if (ppASPD)
+ {
+ Log3Func(("Handling packet description not implemented\n"));
+ }
+ else
+ {
+ /** @todo Check converter ID? */
- /** @todo Handled non-interleaved data by going through the full buffer list,
- * not only through the first buffer like we do now. */
+ /** @todo Handled non-interleaved data by going through the full buffer list,
+ * not only through the first buffer like we do now. */
+ Log3Func(("ioNumberDataPackets=%RU32\n", *ioNumberDataPackets));
- Log3Func(("ioNumberDataPackets=%RU32\n", *ioNumberDataPackets));
+ UInt32 cNumberDataPackets = *ioNumberDataPackets;
+ Assert(pConvCbCtx->uPacketIdx + cNumberDataPackets <= pConvCbCtx->uPacketCnt);
- if (pConvCbCtx->uPacketIdx + *ioNumberDataPackets > pConvCbCtx->uPacketCnt)
- {
- Log3Func(("Limiting ioNumberDataPackets to %RU32\n", pConvCbCtx->uPacketCnt - pConvCbCtx->uPacketIdx));
- *ioNumberDataPackets = pConvCbCtx->uPacketCnt - pConvCbCtx->uPacketIdx;
- }
+ if (cNumberDataPackets)
+ {
+ AssertPtr(pConvCbCtx->pBufLstSrc);
+ Assert(pConvCbCtx->pBufLstSrc->mNumberBuffers == 1); /* Only one buffer for the source supported atm. */
- if (*ioNumberDataPackets)
- {
- Assert(pConvCbCtx->bufLstSrc.mNumberBuffers == 1); /* Only one buffer for the source supported atm. */
+ AudioStreamBasicDescription *pSrcASBD = &pConvCbCtx->asbdSrc;
+ AudioBuffer *pSrcBuf = &pConvCbCtx->pBufLstSrc->mBuffers[0];
- size_t cbOff = pConvCbCtx->uPacketIdx * pConvCbCtx->asbdSrc.mBytesPerPacket;
+ size_t cbOff = pConvCbCtx->uPacketIdx * pSrcASBD->mBytesPerPacket;
- size_t cbAvail = RT_MIN(*ioNumberDataPackets * pConvCbCtx->asbdSrc.mBytesPerPacket,
- pConvCbCtx->bufLstSrc.mBuffers[0].mDataByteSize - cbOff);
+ cNumberDataPackets = RT_MIN((pSrcBuf->mDataByteSize - cbOff) / pSrcASBD->mBytesPerPacket,
+ cNumberDataPackets);
- void *pvAvail = (uint8_t *)pConvCbCtx->bufLstSrc.mBuffers[0].mData + cbOff;
+ void *pvAvail = (uint8_t *)pSrcBuf->mData + cbOff;
+ size_t cbAvail = RT_MIN(pSrcBuf->mDataByteSize - cbOff, cNumberDataPackets * pSrcASBD->mBytesPerPacket);
- Log3Func(("cbOff=%zu, cbAvail=%zu\n", cbOff, cbAvail));
+ Log3Func(("cNumberDataPackets=%RU32, cbOff=%zu, cbAvail=%zu\n", cNumberDataPackets, cbOff, cbAvail));
- /* Set input data for the converter to use.
- * Note: For VBR (Variable Bit Rates) or interleaved data handling we need multiple buffers here. */
- ioData->mNumberBuffers = 1;
+ /* Set input data for the converter to use.
+ * Note: For VBR (Variable Bit Rates) or interleaved data handling we need multiple buffers here. */
+ ioData->mNumberBuffers = 1;
- ioData->mBuffers[0].mNumberChannels = pConvCbCtx->bufLstSrc.mBuffers[0].mNumberChannels;
- ioData->mBuffers[0].mDataByteSize = cbAvail;
- ioData->mBuffers[0].mData = pvAvail;
+ ioData->mBuffers[0].mNumberChannels = pSrcBuf->mNumberChannels;
+ ioData->mBuffers[0].mDataByteSize = cbAvail;
+ ioData->mBuffers[0].mData = pvAvail;
#ifdef DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- int rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-converter-cb-input.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- if (RT_SUCCESS(rc))
- {
- RTFileWrite(fh, pvAvail, cbAvail, NULL);
- RTFileClose(fh);
- }
- else
- AssertFailed();
+ RTFILE fh;
+ int rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-converter-cb-input.pcm",
+ RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
+ if (RT_SUCCESS(rc))
+ {
+ RTFileWrite(fh, pvAvail, cbAvail, NULL);
+ RTFileClose(fh);
+ }
+ else
+ AssertFailed();
#endif
+ pConvCbCtx->uPacketIdx += cNumberDataPackets;
+ Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt);
- pConvCbCtx->uPacketIdx += *ioNumberDataPackets;
- Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt);
+ *ioNumberDataPackets = cNumberDataPackets;
+ }
}
Log3Func(("%RU32 / %RU32 -> ioNumberDataPackets=%RU32\n",
@@ -1521,1130 +1325,124 @@ static OSStatus coreAudioConverterCallback(AudioConverterRef inAudi
}
#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
-#ifndef VBOX_WITH_AUDIO_CA_QUEUES
-/**
- * Implements the OS X callback AURenderCallback in order to feed the audio
- * input buffer.
- */
-static OSStatus coreAudioRecordingCb(void *pvUser,
- AudioUnitRenderActionFlags *pActionFlags,
- const AudioTimeStamp *pAudioTS,
- UInt32 uBusID,
- UInt32 cFrames,
- AudioBufferList *pBufData)
-{
- RT_NOREF(pBufData);
-
- /* If nothing is pending return immediately. */
- if (cFrames == 0)
- return noErr;
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pvUser;
-
- if (ASMAtomicReadU32(&pStreamIn->status) != CA_STATUS_INIT)
- return noErr;
-
- PCOREAUDIOCONVCBCTX pConvCbCtx = &pStreamIn->convCbCtx;
-
- OSStatus err = noErr;
- int rc = VINF_SUCCESS;
-
- Assert(pConvCbCtx->bufLstSrc.mNumberBuffers == 1);
- AudioBuffer *pSrcBuf = &pConvCbCtx->bufLstSrc.mBuffers[0];
-
- pConvCbCtx->uPacketCnt = cFrames / pConvCbCtx->asbdSrc.mFramesPerPacket;
- pConvCbCtx->uPacketIdx = 0;
-
- AudioConverterReset(pStreamIn->pConverter);
+/* Callback for getting notified when some of the properties of an audio device have changed. */
+static DECLCALLBACK(OSStatus) drvHostCoreAudioDevPropChgCb(AudioObjectID propertyID,
+ UInt32 cAddresses,
+ const AudioObjectPropertyAddress properties[],
+ void *pvUser)
+{
+ RT_NOREF(cAddresses, properties);
+ PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
+ AssertPtr(pCbCtx);
+ AssertPtr(pCbCtx->pStream);
- Log3Func(("cFrames=%RU32 (%RU32 frames per packet) -> %RU32 packets\n",
- cFrames, pConvCbCtx->asbdSrc.mFramesPerPacket, pConvCbCtx->uPacketCnt));
+ LogFlowFunc(("propertyID=%u, nAddresses=%u, pCbCtx=%p\n", propertyID, cAddresses, pCbCtx));
- do
+ if (pCbCtx->pStream->enmDir == PDMAUDIODIR_IN)
{
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- /* Are we using a converter? */
- if (pStreamIn->pConverter)
+ PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
+ AssertPtr(pStreamIn);
+
+ switch (propertyID)
{
- pSrcBuf->mNumberChannels = pConvCbCtx->asbdSrc.mChannelsPerFrame;
- pSrcBuf->mDataByteSize = pConvCbCtx->asbdSrc.mBytesPerFrame * cFrames;
- pSrcBuf->mData = RTMemAllocZ(pSrcBuf->mDataByteSize);
- if (!pSrcBuf->mData)
+#ifdef DEBUG
+ case kAudioDeviceProcessorOverload:
{
- rc = VERR_NO_MEMORY;
+ LogFunc(("Processor overload detected!\n"));
break;
}
-
- /* First, render the source data as usual. */
- err = AudioUnitRender(pStreamIn->audioUnit, pActionFlags, pAudioTS, uBusID, cFrames, &pConvCbCtx->bufLstSrc);
- if (err != noErr)
+#endif /* DEBUG */
+ case kAudioDevicePropertyNominalSampleRate:
{
- LogRel2(("CoreAudio: Failed rendering converted audio input data (%RI32)\n", err));
- rc = VERR_IO_GEN_FAILURE; /** @todo Improve this. */
+ LogRel2(("CoreAudio: Recording sample rate changed\n"));
+
+ /* We move the reinitialization to the next input event.
+ * This make sure this thread isn't blocked and the
+ * reinitialization is done when necessary only. */
+ ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
break;
}
- Log3Func(("cbSrcBufSize=%RU32\n", pSrcBuf->mDataByteSize));
+ default:
+ break;
+ }
+ }
+ else
+ {
+ PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
+ AssertPtr(pStreamOut);
-#ifdef DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-recording-cb-src.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- if (RT_SUCCESS(rc))
+ switch (propertyID)
+ {
+ case kAudioDevicePropertyNominalSampleRate:
{
- RTFileWrite(fh, pSrcBuf->mData, pSrcBuf->mDataByteSize, NULL);
- RTFileClose(fh);
- }
- else
- AssertFailed();
-#endif
- AudioBufferList dstBufList;
+ LogRel2(("CoreAudio: Playback sample rate changed\n"));
- dstBufList.mNumberBuffers = 1; /* We only use one buffer at once. */
-
- AudioBuffer *pDstBuf = &dstBufList.mBuffers[0];
- pDstBuf->mDataByteSize = pConvCbCtx->asbdDst.mBytesPerFrame * cFrames;
- pDstBuf->mData = RTMemAllocZ(pDstBuf->mDataByteSize);
- if (!pDstBuf->mData)
- {
- rc = VERR_NO_MEMORY;
+ /* We move the reinitialization to the next input event.
+ * This make sure this thread isn't blocked and the
+ * reinitialization is done when necessary only. */
+ ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
break;
}
- UInt32 cPacketsToWriteAndWritten = pConvCbCtx->uPacketCnt;
- Assert(cPacketsToWriteAndWritten);
+ default:
+ break;
+ }
+ }
- Log3Func(("cPacketsToWrite=%RU32\n", cPacketsToWriteAndWritten));
+ return noErr;
+}
- do
- {
- err = AudioConverterFillComplexBuffer(pStreamIn->pConverter,
- coreAudioConverterCallback, pConvCbCtx /* pvData */,
- &cPacketsToWriteAndWritten, &dstBufList, NULL);
-
- Log3Func(("cPacketsWritten=%RU32 (%zu bytes), err=%RI32\n",
- cPacketsToWriteAndWritten, cPacketsToWriteAndWritten * pConvCbCtx->asbdDst.mBytesPerPacket, err));
-
- if (err != noErr)
- {
- LogFlowFunc(("Failed to convert audio data (%RI32:%c%c%c%c)\n", err,
- RT_BYTE4(err), RT_BYTE3(err), RT_BYTE2(err), RT_BYTE1(err)));
- rc = VERR_IO_GEN_FAILURE;
- break;
- }
-
- if (cPacketsToWriteAndWritten == 0)
- break;
-
- size_t cbDst = cPacketsToWriteAndWritten * pConvCbCtx->asbdDst.mBytesPerPacket;
-
-#ifdef DEBUG_DUMP_PCM_DATA
- rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-recording-cb-dst.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- if (RT_SUCCESS(rc))
- {
- RTFileWrite(fh, pDstBuf->mData, cbDst, NULL);
- RTFileClose(fh);
- }
- else
- AssertFailed();
-#endif
- size_t cbFree = RTCircBufFree(pStreamIn->pCircBuf);
- if (cbFree < cbDst)
- {
- LogRel2(("CoreAudio: Recording is lagging behind (%zu bytes available but only %zu bytes free)\n",
- cbDst, cbFree));
- break;
- }
-
- size_t cbDstChunk;
- void *puDst;
- RTCircBufAcquireWriteBlock(pStreamIn->pCircBuf, cbDst, (void **)&puDst, &cbDstChunk);
-
- if (cbDstChunk)
- memcpy(puDst, pDstBuf->mData, cbDstChunk);
-
- RTCircBufReleaseWriteBlock(pStreamIn->pCircBuf, cbDstChunk);
-
- } while (1);
-
- if (pDstBuf->mData)
- {
- RTMemFree(pDstBuf->mData);
- pDstBuf->mData = NULL;
- }
- }
- else /* No converter being used. */
- {
-#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
- AssertBreakStmt(pStreamIn->streamFormat.mChannelsPerFrame >= 1, rc = VERR_INVALID_PARAMETER);
- AssertBreakStmt(pStreamIn->streamFormat.mBytesPerFrame >= 1, rc = VERR_INVALID_PARAMETER);
-
- AssertBreakStmt(pSrcBuf->mNumberChannels, rc = VERR_INVALID_PARAMETER);
-
- pSrcBuf->mNumberChannels = pStreamIn->streamFormat.mChannelsPerFrame;
- pSrcBuf->mDataByteSize = pStreamIn->streamFormat.mBytesPerFrame * cFrames;
- pSrcBuf->mData = RTMemAlloc(pSrcBuf->mDataByteSize);
- if (!pSrcBuf->mData)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
- err = AudioUnitRender(pStreamIn->audioUnit, pActionFlags, pAudioTS, uBusID, cFrames, &pConvCbCtx->bufLstSrc);
- if (err != noErr)
- {
- LogRel2(("CoreAudio: Failed rendering non-coverted audio input data (%RI32)\n", err));
- rc = VERR_IO_GEN_FAILURE; /** @todo Improve this. */
- break;
- }
-
- const uint32_t cbDataSize = pSrcBuf->mDataByteSize;
- const size_t cbBufFree = RTCircBufFree(pStreamIn->pCircBuf);
- size_t cbAvail = RT_MIN(cbDataSize, cbBufFree);
-
- Log3Func(("cbDataSize=%RU32, cbBufFree=%zu, cbAvail=%zu\n", cbDataSize, cbBufFree, cbAvail));
-
- /* Iterate as long as data is available. */
- uint8_t *puDst = NULL;
- uint32_t cbWrittenTotal = 0;
- while (cbAvail)
- {
- /* Try to acquire the necessary space from the ring buffer. */
- size_t cbToWrite = 0;
- RTCircBufAcquireWriteBlock(pStreamIn->pCircBuf, cbAvail, (void **)&puDst, &cbToWrite);
- if (!cbToWrite)
- break;
-
- /* Copy the data from the Core Audio buffer to the ring buffer. */
- memcpy(puDst, (uint8_t *)pSrcBuf->mData + cbWrittenTotal, cbToWrite);
-
- /* Release the ring buffer, so the main thread could start reading this data. */
- RTCircBufReleaseWriteBlock(pStreamIn->pCircBuf, cbToWrite);
-
- cbWrittenTotal += cbToWrite;
-
- Assert(cbAvail >= cbToWrite);
- cbAvail -= cbToWrite;
- }
-
- Log3Func(("cbWrittenTotal=%RU32, cbLeft=%zu\n", cbWrittenTotal, cbAvail));
-
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- }
-#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
-
- } while (0);
-
- if (pSrcBuf->mData)
- {
- RTMemFree(pSrcBuf->mData);
- pSrcBuf->mData = NULL;
- }
-
- return err;
-}
-#endif /* !VBOX_WITH_AUDIO_CA_QUEUES */
-
-#define CA_BREAK_STMT(stmt) if (true) \
- { \
- stmt; \
- break; \
- } else do { } while (0)
-
-#ifndef VBOX_WITH_AUDIO_CA_QUEUES
-/** @todo Eventually split up this function, as this already is huge! */
-static int coreAudioStreamInitIn(PCOREAUDIOSTREAMIN pStreamIn, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- int rc = VINF_SUCCESS;
-
- UInt32 cSamples = 0;
-
- OSStatus err = noErr;
- UInt32 uSize = 0;
-
- AudioDeviceID deviceID = pStreamIn->deviceID;
- if (deviceID == kAudioDeviceUnknown)
- {
- /* Fetch the default audio recording device currently in use. */
- AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultInputDevice,
- kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- uSize = sizeof(deviceID);
- err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize, &deviceID);
- if (err != noErr)
- {
- LogFlowFunc(("CoreAudio: Unable to determine default recording device (%RI32)\n", err));
- return VERR_AUDIO_NO_FREE_INPUT_STREAMS;
- }
- }
-
- if (deviceID == kAudioDeviceUnknown)
- {
- LogFlowFunc(("No default recording device found\n"));
- return VERR_AUDIO_NO_FREE_INPUT_STREAMS;
- }
-
- do
- {
- /* Assign device ID. */
- pStreamIn->deviceID = deviceID;
-
- /*
- * Try to get the name of the recording device and log it. It's not fatal if it fails.
- */
- CFStringRef strTemp;
-
- AudioObjectPropertyAddress propAdr = { kAudioObjectPropertyName, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- uSize = sizeof(CFStringRef);
- err = AudioObjectGetPropertyData(pStreamIn->deviceID, &propAdr, 0, NULL, &uSize, &strTemp);
- if (err == noErr)
- {
- char *pszDevName = NULL;
- err = coreAudioCFStringToCString(strTemp, &pszDevName);
- if (err == noErr)
- {
- CFRelease(strTemp);
-
- /* Get the device' UUID. */
- propAdr.mSelector = kAudioDevicePropertyDeviceUID;
- err = AudioObjectGetPropertyData(pStreamIn->deviceID, &propAdr, 0, NULL, &uSize, &strTemp);
- if (err == noErr)
- {
- char *pszUID = NULL;
-
- err = coreAudioCFStringToCString(strTemp, &pszUID);
- if (err == noErr)
- {
- CFRelease(strTemp);
- LogRel(("CoreAudio: Using recording device: %s (UID: %s)\n", pszDevName, pszUID));
-
- RTMemFree(pszUID);
- }
- }
-
- RTMemFree(pszDevName);
- }
- }
- else
- {
- /* This is not fatal, can happen for some Macs. */
- LogRel2(("CoreAudio: Unable to determine recording device name (%RI32)\n", err));
- }
-
- /* Get the default frames buffer size, so that we can setup our internal buffers. */
- UInt32 cFrames;
- uSize = sizeof(cFrames);
- propAdr.mSelector = kAudioDevicePropertyBufferFrameSize;
- propAdr.mScope = kAudioDevicePropertyScopeInput;
- err = AudioObjectGetPropertyData(pStreamIn->deviceID, &propAdr, 0, NULL, &uSize, &cFrames);
- if (err != noErr)
- {
- /* Can happen if no recording device is available by default. Happens on some Macs,
- * so don't log this by default to not scare people. */
- LogRel2(("CoreAudio: Failed to determine frame buffer size of the audio recording device (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Set the frame buffer size and honor any minimum/maximum restrictions on the device. */
- err = coreAudioSetFrameBufferSize(pStreamIn->deviceID, true /* fInput */, cFrames, &cFrames);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set frame buffer size for the audio recording device (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- LogFlowFunc(("cFrames=%RU32\n", cFrames));
-
- /* Try to find the default HAL output component. */
- AudioComponentDescription cd;
-
- RT_ZERO(cd);
- cd.componentType = kAudioUnitType_Output;
- cd.componentSubType = kAudioUnitSubType_HALOutput;
- cd.componentManufacturer = kAudioUnitManufacturer_Apple;
-
- AudioComponent cp = AudioComponentFindNext(NULL, &cd);
- if (cp == 0)
- {
- LogRel(("CoreAudio: Failed to find HAL output component\n")); /** @todo Return error value? */
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Open the default HAL output component. */
- err = AudioComponentInstanceNew(cp, &pStreamIn->audioUnit);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to open output component (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Switch the I/O mode for input to on. */
- UInt32 uFlag = 1;
- err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,
- 1, &uFlag, sizeof(uFlag));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to disable input I/O mode for input stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Switch the I/O mode for output to off. This is important, as this is a pure input stream. */
- uFlag = 0;
- err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
- 0, &uFlag, sizeof(uFlag));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to disable output I/O mode for input stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Set the default audio recording device as the device for the new AudioUnit. */
- err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global,
- 0, &pStreamIn->deviceID, sizeof(pStreamIn->deviceID));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set current device (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /*
- * CoreAudio will inform us on a second thread for new incoming audio data.
- * Therefore register a callback function which will process the new data.
- */
- AURenderCallbackStruct cb;
- RT_ZERO(cb);
- cb.inputProc = coreAudioRecordingCb;
- cb.inputProcRefCon = pStreamIn;
-
- err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global,
- 0, &cb, sizeof(cb));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to register input callback (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Fetch the current stream format of the device. */
- RT_ZERO(pStreamIn->deviceFormat);
- uSize = sizeof(pStreamIn->deviceFormat);
- err = AudioUnitGetProperty(pStreamIn->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
- 1, &pStreamIn->deviceFormat, &uSize);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to get device format (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Create an AudioStreamBasicDescription based on our required audio settings. */
- RT_ZERO(pStreamIn->streamFormat);
- coreAudioStreamCfgToASBD(pCfgReq, &pStreamIn->streamFormat);
-
- coreAudioPrintASBD("Recording device", &pStreamIn->deviceFormat);
- coreAudioPrintASBD("Recording stream", &pStreamIn->streamFormat);
-
- /* If the frequency of the device is different from the requested one we
- * need a converter. The same count if the number of channels is different. */
- if ( pStreamIn->deviceFormat.mSampleRate != pStreamIn->streamFormat.mSampleRate
- || pStreamIn->deviceFormat.mChannelsPerFrame != pStreamIn->streamFormat.mChannelsPerFrame)
- {
- LogRel2(("CoreAudio: Input converter is active\n"));
-
- err = AudioConverterNew(&pStreamIn->deviceFormat, &pStreamIn->streamFormat, &pStreamIn->pConverter);
- if (RT_UNLIKELY(err != noErr))
- {
- LogRel(("CoreAudio: Failed to create the audio converter (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- if ( pStreamIn->deviceFormat.mChannelsPerFrame == 1 /* Mono */
- && pStreamIn->streamFormat.mChannelsPerFrame == 2 /* Stereo */)
- {
- LogRel2(("CoreAudio: Mono to stereo conversion active\n"));
-
- /*
- * If the channel count is different we have to tell this the converter
- * and supply a channel mapping. For now we only support mapping
- * from mono to stereo. For all other cases the core audio defaults
- * are used, which means dropping additional channels in most
- * cases.
- */
- const SInt32 channelMap[2] = {0, 0}; /* Channel map for mono -> stereo. */
-
- err = AudioConverterSetProperty(pStreamIn->pConverter, kAudioConverterChannelMap, sizeof(channelMap), channelMap);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set channel mapping (mono -> stereo) for the audio input converter (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
- }
-
- /* Set sample rate converter quality to maximum. */
- uFlag = kAudioConverterQuality_Max;
- err = AudioConverterSetProperty(pStreamIn->pConverter, kAudioConverterSampleRateConverterQuality,
- sizeof(uFlag), &uFlag);
- if (err != noErr)
- LogRel2(("CoreAudio: Failed to set input audio converter quality to the maximum (%RI32)\n", err));
-
- uSize = sizeof(UInt32);
- UInt32 maxOutputSize;
- err = AudioConverterGetProperty(pStreamIn->pConverter, kAudioConverterPropertyMaximumOutputPacketSize,
- &uSize, &maxOutputSize);
- if (RT_UNLIKELY(err != noErr))
- {
- LogRel(("CoreAudio: Failed to retrieve converter's maximum output size (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- LogFunc(("Maximum converter packet output size is: %RI32\n", maxOutputSize));
-
- /* Set the input (source) format, that is, the format the device is recording data with. */
- err = AudioUnitSetProperty(pStreamIn->audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input,
- 1,
- &pStreamIn->deviceFormat,
- sizeof(pStreamIn->deviceFormat));
- if (RT_UNLIKELY(err != noErr))
- {
- LogRel(("CoreAudio: Failed to set device input format (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Set the output (target) format, that is, the format we created the input stream with. */
- err = AudioUnitSetProperty(pStreamIn->audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Output,
- 1,
- &pStreamIn->deviceFormat,
- sizeof(pStreamIn->deviceFormat));
- if (RT_UNLIKELY(err != noErr))
- {
- LogRel(("CoreAudio: Failed to set stream output format (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
- }
- else
- {
- /* Set the new output format description for the input stream. */
- err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
- 1, &pStreamIn->streamFormat, sizeof(pStreamIn->streamFormat));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set output format for input stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
- }
-
- /*
- * Also set the frame buffer size off the device on our AudioUnit. This
- * should make sure that the frames count which we receive in the render
- * thread is as we like.
- */
- err = AudioUnitSetProperty(pStreamIn->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
- 1, &cFrames, sizeof(cFrames));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set maximum frame buffer size for input stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Finally initialize the new AudioUnit. */
- err = AudioUnitInitialize(pStreamIn->audioUnit);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to initialize audio unit for input stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- uSize = sizeof(pStreamIn->deviceFormat);
- err = AudioUnitGetProperty(pStreamIn->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
- 1, &pStreamIn->deviceFormat, &uSize);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to get recording device format (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /*
- * There are buggy devices (e.g. my Bluetooth headset) which doesn't honor
- * the frame buffer size set in the previous calls. So finally get the
- * frame buffer size after the AudioUnit was initialized.
- */
- uSize = sizeof(cFrames);
- err = AudioUnitGetProperty(pStreamIn->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
- 0, &cFrames, &uSize);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to get maximum frame buffer size from input audio device (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Destroy any former internal ring buffer. */
- if (pStreamIn->pCircBuf)
- {
- RTCircBufDestroy(pStreamIn->pCircBuf);
- pStreamIn->pCircBuf = NULL;
- }
-
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- coreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
-#endif
- /* Calculate the ratio between the device and the stream sample rate. */
- pStreamIn->sampleRatio = pStreamIn->streamFormat.mSampleRate / pStreamIn->deviceFormat.mSampleRate;
-
- /*
- * Make sure that the ring buffer is big enough to hold the recording
- * data. Compare the maximum frames per slice value with the frames
- * necessary when using the converter where the sample rate could differ.
- * The result is always multiplied by the channels per frame to get the
- * samples count.
- */
- cSamples = RT_MAX(cFrames,
- (cFrames * pStreamIn->deviceFormat.mBytesPerFrame * pStreamIn->sampleRatio)
- / pStreamIn->streamFormat.mBytesPerFrame)
- * pStreamIn->streamFormat.mChannelsPerFrame;
- if (!cSamples)
- {
- LogRel(("CoreAudio: Failed to determine samples buffer count input stream\n"));
- CA_BREAK_STMT(rc = VERR_INVALID_PARAMETER);
- }
-
- PDMAUDIOPCMPROPS PCMProps;
- int rc2 = DrvAudioHlpStreamCfgToProps(pCfgAcq, &PCMProps);
- AssertRC(rc2);
-
- rc = RTCircBufCreate(&pStreamIn->pCircBuf, cSamples << PCMProps.cShift);
- if (RT_FAILURE(rc))
- break;
-
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- /* Init the converter callback context. */
- rc = coreAudioInitConvCbCtx(&pStreamIn->convCbCtx,
- &pStreamIn->deviceFormat /* Source */, &pStreamIn->streamFormat /* Dest */);
-#endif
- if (RT_SUCCESS(rc))
- {
-#ifdef DEBUG
- propAdr.mSelector = kAudioDeviceProcessorOverload;
- propAdr.mScope = kAudioUnitScope_Global;
- err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr,
- coreAudioRecordingAudioDevicePropertyChanged, (void *)pStreamIn);
- if (RT_UNLIKELY(err != noErr))
- LogRel2(("CoreAudio: Failed to add the processor overload listener for input stream (%RI32)\n", err));
-#endif /* DEBUG */
- propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
- propAdr.mScope = kAudioUnitScope_Global;
- err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr,
- coreAudioRecordingAudioDevicePropertyChanged, (void *)pStreamIn);
- /* Not fatal. */
- if (RT_UNLIKELY(err != noErr))
- LogRel2(("CoreAudio: Failed to register sample rate changed listener for input stream (%RI32)\n", err));
- }
-
- } while (0);
-
- if (RT_SUCCESS(rc))
- {
- LogFunc(("cSamples=%RU32\n", cSamples));
-
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = cSamples;
- }
- else
- {
- AudioUnitUninitialize(pStreamIn->audioUnit);
-
- if (pStreamIn->pCircBuf)
- {
- RTCircBufDestroy(pStreamIn->pCircBuf);
- pStreamIn->pCircBuf = NULL;
- }
-
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- coreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
-#endif
- }
-
- LogFunc(("rc=%Rrc\n", rc));
- return rc;
-}
-
-/** @todo Eventually split up this function, as this already is huge! */
-static int coreAudioStreamInitOut(PCOREAUDIOSTREAMOUT pStreamOut, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- int rc = VINF_SUCCESS;
-
- UInt32 cSamples = 0;
-
- OSStatus err = noErr;
- UInt32 uSize = 0;
-
- AudioDeviceID deviceID = pStreamOut->deviceID;
- if (deviceID == kAudioDeviceUnknown)
- {
- /* Fetch the default audio recording device currently in use. */
- AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice,
- kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- uSize = sizeof(deviceID);
- err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize, &deviceID);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Unable to determine default playback device (%RI32)\n", err));
- return VERR_NOT_FOUND;
- }
- }
-
- if (deviceID == kAudioDeviceUnknown)
- {
- LogFlowFunc(("No default playback device found\n"));
- return VERR_NOT_FOUND;
- }
-
- do
- {
- /* Assign device ID. */
- pStreamOut->deviceID = deviceID;
-
- /*
- * Try to get the name of the playback device and log it. It's not fatal if it fails.
- */
- CFStringRef strTemp;
-
- AudioObjectPropertyAddress propAdr = { kAudioObjectPropertyName, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- uSize = sizeof(CFStringRef);
- err = AudioObjectGetPropertyData(pStreamOut->deviceID, &propAdr, 0, NULL, &uSize, &strTemp);
- if (err == noErr)
- {
- char *pszDevName = NULL;
- err = coreAudioCFStringToCString(strTemp, &pszDevName);
- if (err == noErr)
- {
- CFRelease(strTemp);
-
- /* Get the device' UUID. */
- propAdr.mSelector = kAudioDevicePropertyDeviceUID;
- err = AudioObjectGetPropertyData(pStreamOut->deviceID, &propAdr, 0, NULL, &uSize, &strTemp);
- if (err == noErr)
- {
- char *pszUID = NULL;
- err = coreAudioCFStringToCString(strTemp, &pszUID);
- if (err == noErr)
- {
- CFRelease(strTemp);
- LogRel(("CoreAudio: Using playback device: %s (UID: %s)\n", pszDevName, pszUID));
-
- RTMemFree(pszUID);
- }
- }
-
- RTMemFree(pszDevName);
- }
- }
- else
- LogRel(("CoreAudio: Unable to determine playback device name (%RI32)\n", err));
-
- /* Get the default frames buffer size, so that we can setup our internal buffers. */
- UInt32 cFrames;
- uSize = sizeof(cFrames);
- propAdr.mSelector = kAudioDevicePropertyBufferFrameSize;
- propAdr.mScope = kAudioDevicePropertyScopeInput;
- err = AudioObjectGetPropertyData(pStreamOut->deviceID, &propAdr, 0, NULL, &uSize, &cFrames);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to determine frame buffer size of the audio playback device (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Set the frame buffer size and honor any minimum/maximum restrictions on the device. */
- err = coreAudioSetFrameBufferSize(pStreamOut->deviceID, false /* fInput */, cFrames, &cFrames);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set frame buffer size for the audio playback device (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Try to find the default HAL output component. */
- AudioComponentDescription cd;
- RT_ZERO(cd);
-
- cd.componentType = kAudioUnitType_Output;
- cd.componentSubType = kAudioUnitSubType_HALOutput;
- cd.componentManufacturer = kAudioUnitManufacturer_Apple;
-
- AudioComponent cp = AudioComponentFindNext(NULL, &cd);
- if (cp == 0)
- {
- LogRel(("CoreAudio: Failed to find HAL output component\n")); /** @todo Return error value? */
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Open the default HAL output component. */
- err = AudioComponentInstanceNew(cp, &pStreamOut->audioUnit);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to open output component (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Switch the I/O mode for output to on. */
- UInt32 uFlag = 1;
- err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
- 0, &uFlag, sizeof(uFlag));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to disable I/O mode for output stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Set the default audio playback device as the device for the new AudioUnit. */
- err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global,
- 0, &pStreamOut->deviceID, sizeof(pStreamOut->deviceID));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set current device for output stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /*
- * CoreAudio will inform us on a second thread for new incoming audio data.
- * Therefor register a callback function which will process the new data.
- */
- AURenderCallbackStruct cb;
- RT_ZERO(cb);
- cb.inputProc = coreAudioPlaybackCb; /* pvUser */
- cb.inputProcRefCon = pStreamOut;
-
- err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
- 0, &cb, sizeof(cb));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to register output callback (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Fetch the current stream format of the device. */
- uSize = sizeof(pStreamOut->deviceFormat);
- err = AudioUnitGetProperty(pStreamOut->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
- 0, &pStreamOut->deviceFormat, &uSize);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to get device format (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Create an AudioStreamBasicDescription based on our required audio settings. */
- coreAudioStreamCfgToASBD(pCfgReq, &pStreamOut->streamFormat);
-
- coreAudioPrintASBD("Playback device", &pStreamOut->deviceFormat);
- coreAudioPrintASBD("Playback format", &pStreamOut->streamFormat);
-
- /* Set the new output format description for the stream. */
- err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
- 0, &pStreamOut->streamFormat, sizeof(pStreamOut->streamFormat));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set stream format for output stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- uSize = sizeof(pStreamOut->deviceFormat);
- err = AudioUnitGetProperty(pStreamOut->audioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
- 0, &pStreamOut->deviceFormat, &uSize);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to retrieve device format for output stream (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /*
- * Also set the frame buffer size off the device on our AudioUnit. This
- * should make sure that the frames count which we receive in the render
- * thread is as we like.
- */
- err = AudioUnitSetProperty(pStreamOut->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
- 0, &cFrames, sizeof(cFrames));
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set maximum frame buffer size for output AudioUnit (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /* Finally initialize the new AudioUnit. */
- err = AudioUnitInitialize(pStreamOut->audioUnit);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to initialize the output audio device (%RI32)\n", err));
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /*
- * There are buggy devices (e.g. my Bluetooth headset) which doesn't honor
- * the frame buffer size set in the previous calls. So finally get the
- * frame buffer size after the AudioUnit was initialized.
- */
- uSize = sizeof(cFrames);
- err = AudioUnitGetProperty(pStreamOut->audioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global,
- 0, &cFrames, &uSize);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to get maximum frame buffer size from output audio device (%RI32)\n", err));
-
- AudioUnitUninitialize(pStreamOut->audioUnit);
- CA_BREAK_STMT(rc = VERR_AUDIO_BACKEND_INIT_FAILED);
- }
-
- /*
- * Make sure that the ring buffer is big enough to hold the recording
- * data. Compare the maximum frames per slice value with the frames
- * necessary when using the converter where the sample rate could differ.
- * The result is always multiplied by the channels per frame to get the
- * samples count.
- */
- cSamples = cFrames * pStreamOut->streamFormat.mChannelsPerFrame;
- if (!cSamples)
- {
- LogRel(("CoreAudio: Failed to determine samples buffer count output stream\n"));
- CA_BREAK_STMT(rc = VERR_INVALID_PARAMETER);
- }
-
- /* Destroy any former internal ring buffer. */
- if (pStreamOut->pCircBuf)
- {
- RTCircBufDestroy(pStreamOut->pCircBuf);
- pStreamOut->pCircBuf = NULL;
- }
-
- PDMAUDIOPCMPROPS PCMProps;
- int rc2 = DrvAudioHlpStreamCfgToProps(pCfgAcq, &PCMProps);
- AssertRC(rc2);
-
- rc = RTCircBufCreate(&pStreamOut->pCircBuf, cSamples << PCMProps.cShift);
- if (RT_FAILURE(rc))
- break;
-
- /*
- * Register callbacks.
- */
-#ifdef DEBUG
- propAdr.mSelector = kAudioDeviceProcessorOverload;
- propAdr.mScope = kAudioUnitScope_Global;
- err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr,
- coreAudioPlaybackAudioDevicePropertyChanged, (void *)pStreamOut);
- if (err != noErr)
- LogRel(("CoreAudio: Failed to register processor overload listener for output stream (%RI32)\n", err));
-#endif /* DEBUG */
-
- propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
- propAdr.mScope = kAudioUnitScope_Global;
- err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr,
- coreAudioPlaybackAudioDevicePropertyChanged, (void *)pStreamOut);
- /* Not fatal. */
- if (err != noErr)
- LogRel(("CoreAudio: Failed to register sample rate changed listener for output stream (%RI32)\n", err));
-
- } while (0);
-
- if (RT_SUCCESS(rc))
- {
- LogFunc(("cSamples=%RU32\n", cSamples));
-
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = cSamples;
- }
- else
- {
- AudioUnitUninitialize(pStreamOut->audioUnit);
-
- if (pStreamOut->pCircBuf)
- {
- RTCircBufDestroy(pStreamOut->pCircBuf);
- pStreamOut->pCircBuf = NULL;
- }
- }
-
- LogFunc(("cSamples=%RU32, rc=%Rrc\n", cSamples, rc));
- return rc;
-}
-#endif /* VBOX_WITH_AUDIO_CA_QUEUES */
-
-/**
- * Implements the OS X callback AudioObjectPropertyListenerProc for getting
- * notified when some of the properties of an audio device has changed.
- */
-static OSStatus coreAudioPlaybackAudioDevicePropertyChanged(AudioObjectID propertyID,
- UInt32 cAddresses,
- const AudioObjectPropertyAddress paProperties[],
- void *pvUser)
-{
- RT_NOREF(propertyID, cAddresses, paProperties, pvUser)
-
- switch (propertyID)
- {
-#ifdef DEBUG
-#endif /* DEBUG */
- default:
- break;
- }
-
- return noErr;
-}
-
-#ifndef VBOX_WITH_AUDIO_CA_QUEUES
-/**
- * Implements the OS X callback AURenderCallback in order to feed the audio
- * output buffer.
- */
-static OSStatus coreAudioPlaybackCb(void *pvUser,
- AudioUnitRenderActionFlags *pActionFlags,
- const AudioTimeStamp *pAudioTS,
- UInt32 uBusID,
- UInt32 cFrames,
- AudioBufferList *pBufData)
-{
- RT_NOREF(pActionFlags, pAudioTS, uBusID, cFrames);
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pvUser;
-
- if (ASMAtomicReadU32(&pStreamOut->status) != CA_STATUS_INIT)
- {
- pBufData->mBuffers[0].mDataByteSize = 0;
- return noErr;
- }
-
- /* How much space is used in the ring buffer? */
- size_t cbToRead = RT_MIN(RTCircBufUsed(pStreamOut->pCircBuf), pBufData->mBuffers[0].mDataByteSize);
- if (!cbToRead)
- {
- pBufData->mBuffers[0].mDataByteSize = 0;
- return noErr;
- }
-
- uint8_t *pbSrc = NULL;
- size_t cbRead = 0;
-
- size_t cbLeft = cbToRead;
- while (cbLeft)
- {
- /* Try to acquire the necessary block from the ring buffer. */
- RTCircBufAcquireReadBlock(pStreamOut->pCircBuf, cbLeft, (void **)&pbSrc, &cbToRead);
-
- /* Break if nothing is used anymore. */
- if (!cbToRead)
- break;
-
- /* Copy the data from our ring buffer to the core audio buffer. */
- memcpy((uint8_t *)pBufData->mBuffers[0].mData + cbRead, pbSrc, cbToRead);
-
- /* Release the read buffer, so it could be used for new data. */
- RTCircBufReleaseReadBlock(pStreamOut->pCircBuf, cbToRead);
-
- /* Move offset. */
- cbRead += cbToRead;
-
- /* Check if we're lagging behind. */
- if (cbRead > pBufData->mBuffers[0].mDataByteSize)
- {
- LogRel2(("CoreAudio: Host output lagging behind, expect stuttering guest audio output\n"));
- cbRead = pBufData->mBuffers[0].mDataByteSize;
- break;
- }
-
- Assert(cbToRead <= cbLeft);
- cbLeft -= cbToRead;
- }
-
- /* Write the bytes to the core audio buffer which were really written. */
- Assert(pBufData->mBuffers[0].mDataByteSize >= cbRead);
- pBufData->mBuffers[0].mDataByteSize = cbRead;
-
- Log3Func(("Read %zu / %zu bytes\n", cbRead, cbToRead));
-
- return noErr;
-}
-#endif /* VBOX_WITH_AUDIO_CA_QUEUES */
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnInit}
- *
- * @todo Please put me next to the shutdown function, because then it would be
- * clear why I'm empty. While at it, it would be nice if you also
- * reordered my PDMIHOSTAUDIO sibilings according to the interface
- * (doesn't matter if it's reversed (like all other PDM drivers and
- * devices) or not).
- */
static DECLCALLBACK(int) drvHostCoreAudioInit(PPDMIHOSTAUDIO pInterface)
{
- RT_NOREF(pInterface);
+ NOREF(pInterface);
LogFlowFuncEnter();
return VINF_SUCCESS;
}
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamCapture}
- */
-static DECLCALLBACK(int) drvHostCoreAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
- void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static DECLCALLBACK(int) drvHostCoreAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ uint32_t *pcSamplesCaptured)
{
- RT_NOREF(pvBuf, cbBuf); /** @todo r=bird: this looks totally weird at first glance! */
-
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbRead is optional. */
-
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
- PCOREAUDIOSTREAM pCAStream = &pStreamIn->Common;
+ PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
/* Check if the audio device should be reinitialized. If so do it. */
if (ASMAtomicReadU32(&pStreamIn->status) == CA_STATUS_REINIT)
- {
- int rc2 = coreAudioStreamReinitIn(pCAStream);
- if (RT_FAILURE(rc2))
- return VERR_NOT_AVAILABLE;
- }
+ drvHostCoreAudioReinitInput(pInterface, &pStreamIn->streamIn);
if (ASMAtomicReadU32(&pStreamIn->status) != CA_STATUS_INIT)
{
- if (pcbRead)
- *pcbRead = 0;
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = 0;
return VINF_SUCCESS;
}
- int rc = VINF_SUCCESS;
- uint32_t cbWrittenTotal = 0;
-
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = RTCritSectEnter(&pCAStream->CritSect);
- AssertRC(rc);
-#endif
-
PRTCIRCBUF pCircBuf = NULL;
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- pCircBuf = pCAStream->pCircBuf;
-#else
- pCircBuf = pStreamIn->pCircBuf;
-#endif
+ pCircBuf = pStreamIn->cbCtx.pStream->pCircBuf;
AssertPtr(pCircBuf);
+ int rc = VINF_SUCCESS;
+ uint32_t cbWrittenTotal = 0;
+
do
{
- size_t cbMixBuf = AudioMixBufSizeBytes(&pStream->MixBuf);
- size_t cbToWrite = RT_MIN(cbMixBuf, RTCircBufUsed(pCircBuf));
+ size_t cbBuf = AudioMixBufSizeBytes(&pHstStrmIn->MixBuf);
+ size_t cbToWrite = RT_MIN(cbBuf, RTCircBufUsed(pCircBuf));
uint32_t cWritten, cbWritten;
+ uint8_t *puBuf;
+ size_t cbToRead;
- uint8_t *pvChunk;
- size_t cbChunk;
-
- Log3Func(("cbMixBuf=%zu, cbToWrite=%zu/%zu\n", cbMixBuf, cbToWrite, RTCircBufSize(pCircBuf)));
+ Log3Func(("cbBuf=%zu, cbToWrite=%zu/%zu\n", cbBuf, cbToWrite, RTCircBufSize(pCircBuf)));
while (cbToWrite)
{
/* Try to acquire the necessary block from the ring buffer. */
- RTCircBufAcquireReadBlock(pCircBuf, cbToWrite, (void **)&pvChunk, &cbChunk);
- if (cbChunk)
+ RTCircBufAcquireReadBlock(pCircBuf, cbToWrite, (void **)&puBuf, &cbToRead);
+
+ if (cbToRead)
{
#ifdef DEBUG_DUMP_PCM_DATA
RTFILE fh;
@@ -2652,56 +1450,49 @@ static DECLCALLBACK(int) drvHostCoreAudioStreamCapture(PPDMIHOSTAUDIO pInterface
RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
if (RT_SUCCESS(rc))
{
- RTFileWrite(fh, pvChunk, cbChunk, NULL);
+ RTFileWrite(fh, puBuf + cbWrittenTotal, cbToRead, NULL);
RTFileClose(fh);
}
else
AssertFailed();
#endif
- rc = AudioMixBufWriteCirc(&pStream->MixBuf, pvChunk, cbChunk, &cWritten);
- if (rc == VERR_BUFFER_OVERFLOW)
- {
- LogRel2(("Core Audio: Capturing host buffer full\n"));
- rc = VINF_SUCCESS;
- }
+ rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf, puBuf, cbToRead, &cWritten);
}
/* Release the read buffer, so it could be used for new data. */
- RTCircBufReleaseReadBlock(pCircBuf, cbChunk);
+ RTCircBufReleaseReadBlock(pCircBuf, cbToRead);
- if (RT_FAILURE(rc))
+ if ( RT_FAILURE(rc)
+ || !cWritten)
+ {
break;
+ }
- cbWritten = AUDIOMIXBUF_S2B(&pStream->MixBuf, cWritten);
+ cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
Assert(cbToWrite >= cbWritten);
cbToWrite -= cbWritten;
cbWrittenTotal += cbWritten;
}
- Log3Func(("cbToWrite=%zu, cbToRead=%zu, cbWrittenTotal=%RU32, rc=%Rrc\n", cbToWrite, cbChunk, cbWrittenTotal, rc));
+ Log3Func(("cbToWrite=%zu, cbToRead=%zu, cbWrittenTotal=%RU32, rc=%Rrc\n", cbToWrite, cbToRead, cbWrittenTotal, rc));
}
while (0);
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- int rc2 = RTCritSectLeave(&pCAStream->CritSect);
- AssertRC(rc2);
-#endif
-
if (RT_SUCCESS(rc))
{
uint32_t cCaptured = 0;
- uint32_t cWrittenTotal = AUDIOMIXBUF_B2S(&pStream->MixBuf, cbWrittenTotal);
+ uint32_t cWrittenTotal = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbWrittenTotal);
if (cWrittenTotal)
- rc = AudioMixBufMixToParent(&pStream->MixBuf, cWrittenTotal, &cCaptured);
+ rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal, &cCaptured);
Log3Func(("cWrittenTotal=%RU32 (%RU32 bytes), cCaptured=%RU32, rc=%Rrc\n", cWrittenTotal, cbWrittenTotal, cCaptured, rc));
if (cCaptured)
LogFlowFunc(("%RU32 samples captured\n", cCaptured));
- if (pcbRead)
- *pcbRead = cCaptured;
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = cCaptured;
}
if (RT_FAILURE(rc))
@@ -2710,67 +1501,42 @@ static DECLCALLBACK(int) drvHostCoreAudioStreamCapture(PPDMIHOSTAUDIO pInterface
return rc;
}
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamPlay}
- */
-static DECLCALLBACK(int) drvHostCoreAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream,
- const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+static DECLCALLBACK(int) drvHostCoreAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ uint32_t *pcSamplesPlayed)
{
- RT_NOREF(pvBuf, cbBuf); /** @todo r=bird: this looks weird at first glance... */
+ PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbWritten is optional. */
-
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
- PCOREAUDIOSTREAM pCAStream = &pStreamOut->Common;
+ int rc = VINF_SUCCESS;
/* Check if the audio device should be reinitialized. If so do it. */
if (ASMAtomicReadU32(&pStreamOut->status) == CA_STATUS_REINIT)
{
- /* For now re just re-initialize with the current output device. */
- int rc2 = coreAudioStreamReinitOut(pCAStream);
- if (RT_FAILURE(rc2))
- return VERR_NOT_AVAILABLE;
+ rc = drvHostCoreAudioReinitOutput(pInterface, &pStreamOut->streamOut);
+ if (RT_FAILURE(rc))
+ return rc;
}
- if (ASMAtomicReadU32(&pStreamOut->status) != CA_STATUS_INIT)
+ uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+ if (!cLive) /* Not samples to play? Bail out. */
{
- if (pcbWritten)
- *pcbWritten = 0;
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = 0;
return VINF_SUCCESS;
}
- int rc = VINF_SUCCESS;
-
- uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
- if (!cLive) /* Not live samples to play? Bail out. */
- {
- if (pcbWritten)
- *pcbWritten = 0;
- return VINF_SUCCESS;
- }
-
- size_t cbLive = AUDIOMIXBUF_S2B(&pStream->MixBuf, cLive);
-
- uint32_t cbReadTotal = 0;
-
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = RTCritSectEnter(&pCAStream->CritSect);
- AssertRC(rc);
-#endif
+ PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
+ AssertPtr(pCAStream);
PRTCIRCBUF pCircBuf = NULL;
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
pCircBuf = pCAStream->pCircBuf;
-#else
- pCircBuf = pStreamOut->pCircBuf;
-#endif
AssertPtr(pCircBuf);
+ size_t cbLive = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cLive);
+
+ uint32_t cbReadTotal = 0;
+
size_t cbToRead = RT_MIN(cbLive, RTCircBufFree(pCircBuf));
- Log3Func(("cbToRead=%zu\n", cbToRead));
+ Log3Func(("cbLive=%zu, cbToRead=%zu\n", cbLive, cbToRead));
uint8_t *pvChunk;
size_t cbChunk;
@@ -2789,9 +1555,9 @@ static DECLCALLBACK(int) drvHostCoreAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
Assert(cbChunk <= cbToRead);
- rc = AudioMixBufReadCirc(&pStream->MixBuf, pvChunk, cbChunk, &cRead);
+ rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pvChunk, cbChunk, &cRead);
- cbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead);
+ cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
/* Release the ring buffer, so the read thread could start reading this data. */
RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
@@ -2804,7 +1570,6 @@ static DECLCALLBACK(int) drvHostCoreAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
cbReadTotal += cbRead;
}
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
if ( RT_SUCCESS(rc)
&& pCAStream->fRun
&& !pCAStream->fIsRunning)
@@ -2818,30 +1583,30 @@ static DECLCALLBACK(int) drvHostCoreAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
}
}
- int rc2 = RTCritSectLeave(&pCAStream->CritSect);
- AssertRC(rc2);
-#endif
-
if (RT_SUCCESS(rc))
{
- uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pStream->MixBuf, cbReadTotal);
+ uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
if (cReadTotal)
- AudioMixBufFinish(&pStream->MixBuf, cReadTotal);
+ AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
Log3Func(("cReadTotal=%RU32 (%RU32 bytes)\n", cReadTotal, cbReadTotal));
- if (pcbWritten)
- *pcbWritten = cReadTotal;
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = cReadTotal;
}
return rc;
}
-static int coreAudioControlStreamOut(PCOREAUDIOSTREAMOUT pCAStreamOut, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostCoreAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
+ RT_NOREF(pInterface);
+ PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
+
LogFlowFunc(("enmStreamCmd=%RU32\n", enmStreamCmd));
- uint32_t uStatus = ASMAtomicReadU32(&pCAStreamOut->status);
+ uint32_t uStatus = ASMAtomicReadU32(&pStreamOut->status);
if (!( uStatus == CA_STATUS_INIT
|| uStatus == CA_STATUS_REINIT))
{
@@ -2850,57 +1615,26 @@ static int coreAudioControlStreamOut(PCOREAUDIOSTREAMOUT pCAStreamOut, PDMAUDIOS
int rc = VINF_SUCCESS;
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- PCOREAUDIOSTREAM pCAStream = &pCAStreamOut->Common;
-#endif
+ PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
+ AssertPtr(pCAStream);
+ OSStatus err; RT_NOREF(err);
switch (enmStreamCmd)
{
case PDMAUDIOSTREAMCMD_ENABLE:
case PDMAUDIOSTREAMCMD_RESUME:
{
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
LogFunc(("Queue enable\n"));
- if (pCAStream->enmDir == PDMAUDIODIR_IN)
- {
- rc = coreAudioStreamInvalidateQueue(pCAStream);
- if (RT_SUCCESS(rc))
- {
- /* Start the audio queue immediately. */
- AudioQueueStart(pCAStream->audioQueue, NULL);
- }
- }
- if (pCAStream->enmDir == PDMAUDIODIR_OUT)
- {
- /* Touch the run flag to start the audio queue as soon as
- * we have anough data to actually play something. */
- ASMAtomicXchgBool(&pCAStream->fRun, true);
- }
-#else
- /* Only start the device if it is actually stopped */
- if (!coreAudioIsRunning(pCAStreamOut->deviceID))
+ rc = coreAudioStreamInvalidateQueue(pCAStream);
+ if (RT_SUCCESS(rc))
{
- OSStatus err = AudioUnitReset(pCAStreamOut->audioUnit, kAudioUnitScope_Input, 0);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to reset AudioUnit (%RI32)\n", err));
- /* Keep going. */
- }
- RTCircBufReset(pCAStreamOut->pCircBuf);
-
- err = AudioOutputUnitStart(pCAStreamOut->audioUnit);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to start playback (%RI32)\n", err));
- rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
- }
+ /* Start the audio queue immediately. */
+ AudioQueueStart(pCAStream->audioQueue, NULL);
}
-#endif /* VBOX_WITH_AUDIO_CA_QUEUES */
break;
}
case PDMAUDIOSTREAMCMD_DISABLE:
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
{
LogFunc(("Queue disable\n"));
AudioQueueStop(pCAStream->audioQueue, 1 /* Immediately */);
@@ -2908,33 +1642,12 @@ static int coreAudioControlStreamOut(PCOREAUDIOSTREAMOUT pCAStreamOut, PDMAUDIOS
ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
break;
}
-#endif
+
case PDMAUDIOSTREAMCMD_PAUSE:
{
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
LogFunc(("Queue pause\n"));
AudioQueuePause(pCAStream->audioQueue);
ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
-#else
- /* Only stop the device if it is actually running */
- if (coreAudioIsRunning(pCAStreamOut->deviceID))
- {
- OSStatus err = AudioOutputUnitStop(pCAStreamOut->audioUnit);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to stop playback (%RI32)\n", err));
- rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
- break;
- }
-
- err = AudioUnitReset(pCAStreamOut->audioUnit, kAudioUnitScope_Input, 0);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to reset AudioUnit (%RI32)\n", err));
- rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
- }
- }
-#endif /* VBOX_WITH_AUDIO_CA_QUEUES */
break;
}
@@ -2947,11 +1660,15 @@ static int coreAudioControlStreamOut(PCOREAUDIOSTREAMOUT pCAStreamOut, PDMAUDIOS
return rc;
}
-static int coreAudioControlStreamIn(PCOREAUDIOSTREAMIN pCAStreamIn, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostCoreAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
+ RT_NOREF(pInterface);
+ PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
+
LogFlowFunc(("enmStreamCmd=%RU32\n", enmStreamCmd));
- uint32_t uStatus = ASMAtomicReadU32(&pCAStreamIn->status);
+ uint32_t uStatus = ASMAtomicReadU32(&pStreamIn->status);
if (!( uStatus == CA_STATUS_INIT
|| uStatus == CA_STATUS_REINIT))
{
@@ -2960,51 +1677,26 @@ static int coreAudioControlStreamIn(PCOREAUDIOSTREAMIN pCAStreamIn, PDMAUDIOSTRE
int rc = VINF_SUCCESS;
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- PCOREAUDIOSTREAM pCAStream = &pCAStreamIn->Common;
-#endif
+ PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
+ AssertPtr(pCAStream);
+ OSStatus err; RT_NOREF(err);
switch (enmStreamCmd)
{
case PDMAUDIOSTREAMCMD_ENABLE:
case PDMAUDIOSTREAMCMD_RESUME:
{
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
LogFunc(("Queue enable\n"));
- if (pCAStream->enmDir == PDMAUDIODIR_IN)
- {
- rc = coreAudioStreamInvalidateQueue(pCAStream);
- if (RT_SUCCESS(rc))
- {
- /* Start the audio queue immediately. */
- AudioQueueStart(pCAStream->audioQueue, NULL);
- }
- }
- if (pCAStream->enmDir == PDMAUDIODIR_OUT)
- {
- /* Touch the run flag to start the audio queue as soon as
- * we have anough data to actually play something. */
- ASMAtomicXchgBool(&pCAStream->fRun, true);
- }
-#else
- /* Only start the device if it is actually stopped */
- if (!coreAudioIsRunning(pCAStreamIn->deviceID))
+ rc = coreAudioStreamInvalidateQueue(pCAStream);
+ if (RT_SUCCESS(rc))
{
- RTCircBufReset(pCAStreamIn->pCircBuf);
- OSStatus err = AudioOutputUnitStart(pCAStreamIn->audioUnit);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to start recording (%RI32)\n", err));
- rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
- break;
- }
+ /* Start the audio queue immediately. */
+ AudioQueueStart(pCAStream->audioQueue, NULL);
}
-#endif /* VBOX_WITH_AUDIO_CA_QUEUES */
break;
}
case PDMAUDIOSTREAMCMD_DISABLE:
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
{
LogFunc(("Queue disable\n"));
AudioQueueStop(pCAStream->audioQueue, 1 /* Immediately */);
@@ -3012,34 +1704,12 @@ static int coreAudioControlStreamIn(PCOREAUDIOSTREAMIN pCAStreamIn, PDMAUDIOSTRE
ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
break;
}
-#endif
+
case PDMAUDIOSTREAMCMD_PAUSE:
{
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
LogFunc(("Queue pause\n"));
AudioQueuePause(pCAStream->audioQueue);
ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
-#else
- /* Only stop the device if it is actually running */
- if (coreAudioIsRunning(pCAStreamIn->deviceID))
- {
- OSStatus err = AudioOutputUnitStop(pCAStreamIn->audioUnit);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to stop recording (%RI32)\n", err));
- rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
- break;
- }
-
- err = AudioUnitReset(pCAStreamIn->audioUnit, kAudioUnitScope_Input, 0);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to reset AudioUnit (%RI32)\n", err));
- rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
- break;
- }
- }
-#endif /* VBOX_WITH_AUDIO_CA_QUEUES */
break;
}
@@ -3052,10 +1722,9 @@ static int coreAudioControlStreamIn(PCOREAUDIOSTREAMIN pCAStreamIn, PDMAUDIOSTRE
return rc;
}
-static int coreAudioDestroyStreamIn(PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostCoreAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
- PCOREAUDIOSTREAM pCAStream = &pStreamIn->Common;
+ PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN) pHstStrmIn;
LogFlowFuncEnter();
@@ -3068,107 +1737,99 @@ static int coreAudioDestroyStreamIn(PPDMAUDIOSTREAM pStream)
OSStatus err = noErr;
- int rc = coreAudioControlStreamIn(pStreamIn, PDMAUDIOSTREAMCMD_DISABLE);
+ int rc = drvHostCoreAudioControlIn(pInterface, &pStreamIn->streamIn, PDMAUDIOSTREAMCMD_DISABLE);
if (RT_SUCCESS(rc))
{
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_IN_UNINIT);
-
- rc = coreAudioStreamUninit(pCAStream);
- if (RT_SUCCESS(rc))
- {
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_UNINIT);
-
- /*
- * Unregister recording device callbacks.
- */
- AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
+ /*
+ * Unregister recording device callbacks.
+ */
+ AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
#ifdef DEBUG
- err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
- coreAudioRecordingAudioDevicePropertyChanged, &pStreamIn->Common);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the recording processor overload listener (%RI32)\n", err));
- }
+ err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
+ drvHostCoreAudioDevPropChgCb, &pStreamIn->cbCtx /* pvUser */);
+ if ( err != noErr
+ && err != kAudioHardwareBadObjectError)
+ {
+ LogRel(("CoreAudio: Failed to remove the recording processor overload listener (%RI32)\n", err));
+ }
#endif /* DEBUG */
- propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
- err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
- coreAudioRecordingAudioDevicePropertyChanged, &pStreamIn->Common);
+ propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
+ err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
+ drvHostCoreAudioDevPropChgCb, &pStreamIn->cbCtx /* pvUser */);
+ if ( err != noErr
+ && err != kAudioHardwareBadObjectError)
+ {
+ LogRel(("CoreAudio: Failed to remove the recording sample rate changed listener (%RI32)\n", err));
+ }
+
+ if (pStreamIn->fDefDevChgListReg)
+ {
+ propAdr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+ err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
+ drvHostCoreAudioDefaultDeviceChangedCb, pStreamIn);
if ( err != noErr
&& err != kAudioHardwareBadObjectError)
{
- LogRel(("CoreAudio: Failed to remove the recording sample rate changed listener (%RI32)\n", err));
+ LogRel(("CoreAudio: Failed to remove the default recording device changed listener (%RI32)\n", err));
}
- if (pStreamIn->fDefDevChgListReg)
- {
- propAdr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
- err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
- coreAudioDefaultDeviceChanged, &pStreamIn->Common);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the default recording device changed listener (%RI32)\n", err));
- }
+ pStreamIn->fDefDevChgListReg = false;
+ }
- pStreamIn->fDefDevChgListReg = false;
- }
+ if (pStreamIn->fDevStateChgListReg)
+ {
+ Assert(pStreamIn->deviceID != kAudioDeviceUnknown);
- if (pStreamIn->fDevStateChgListReg)
+ AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+ err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr2,
+ drvHostCoreAudioDeviceStateChangedCb, &pStreamIn->cbCtx);
+ if ( err != noErr
+ && err != kAudioHardwareBadObjectError)
{
- Assert(pStreamIn->deviceID != kAudioDeviceUnknown);
-
- AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr2,
- drvHostCoreAudioDeviceStateChanged, &pStreamIn->Common);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the recording device state changed listener (%RI32)\n", err));
- }
-
- pStreamIn->fDevStateChgListReg = false;
+ LogRel(("CoreAudio: Failed to remove the recording device state changed listener (%RI32)\n", err));
}
-#ifndef VBOX_WITH_AUDIO_CA_QUEUES
- if (pStreamIn->pConverter)
- {
- AudioConverterDispose(pStreamIn->pConverter);
- pStreamIn->pConverter = NULL;
- }
+ pStreamIn->fDevStateChgListReg = false;
+ }
- err = AudioUnitUninitialize(pStreamIn->audioUnit);
- if (err == noErr)
- err = AudioComponentInstanceDispose(pStreamIn->audioUnit);
+ if (RT_SUCCESS(rc))
+ {
+ PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
+ rc = coreAudioStreamUninitQueue(pCAStream);
+ if (RT_FAILURE(rc))
{
- LogRel(("CoreAudio: Failed to uninit the recording device (%RI32)\n", err));
+ LogRel(("CoreAudio: Failed to uninit stream queue: %Rrc)\n", rc));
+ return rc;
}
- pStreamIn->deviceID = kAudioDeviceUnknown;
- pStreamIn->audioUnit = NULL;
- pStreamIn->sampleRatio = 1;
-
-# ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- coreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
-# endif
-#else /* VBOX_WITH_AUDIO_CA_QUEUES */
if (RTCritSectIsInitialized(&pCAStream->CritSect))
RTCritSectDelete(&pCAStream->CritSect);
+ }
+
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+ if (pStreamIn->ConverterRef)
+ {
+ AudioConverterDispose(pStreamIn->ConverterRef);
+ pStreamIn->ConverterRef = NULL;
+ }
#endif
- if (pStreamIn->pCircBuf)
- {
- RTCircBufDestroy(pStreamIn->pCircBuf);
- pStreamIn->pCircBuf = NULL;
- }
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_UNINIT);
+ pStreamIn->deviceID = kAudioDeviceUnknown;
+
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+ drvHostCoreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
+#endif
+ if (pStreamIn->pCircBuf)
+ {
+ RTCircBufDestroy(pStreamIn->pCircBuf);
+ pStreamIn->pCircBuf = NULL;
}
+
+ ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_UNINIT);
}
else
{
@@ -3180,10 +1841,9 @@ static int coreAudioDestroyStreamIn(PPDMAUDIOSTREAM pStream)
return rc;
}
-static int coreAudioDestroyStreamOut(PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostCoreAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
- PCOREAUDIOSTREAM pCAStream = &pStreamOut->Common;
+ PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
LogFlowFuncEnter();
@@ -3194,98 +1854,91 @@ static int coreAudioDestroyStreamOut(PPDMAUDIOSTREAM pStream)
return VINF_SUCCESS;
}
- int rc = coreAudioControlStreamOut(pStreamOut, PDMAUDIOSTREAMCMD_DISABLE);
+ int rc = drvHostCoreAudioControlOut(pInterface, &pStreamOut->streamOut, PDMAUDIOSTREAMCMD_DISABLE);
if (RT_SUCCESS(rc))
{
- ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_IN_UNINIT);
-
- rc = coreAudioStreamUninit(pCAStream);
- if (RT_SUCCESS(rc))
- {
- OSStatus err;
+ OSStatus err;
- /*
- * Unregister playback device callbacks.
- */
- AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
+ /*
+ * Unregister playback device callbacks.
+ */
+ AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
#ifdef DEBUG
- err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
- coreAudioPlaybackAudioDevicePropertyChanged, &pStreamOut->Common);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the playback processor overload listener (%RI32)\n", err));
- }
+ err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
+ drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
+ if ( err != noErr
+ && err != kAudioHardwareBadObjectError)
+ {
+ LogRel(("CoreAudio: Failed to remove the playback processor overload listener (%RI32)\n", err));
+ }
#endif /* DEBUG */
- propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
- err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
- coreAudioPlaybackAudioDevicePropertyChanged, &pStreamOut->Common);
+ propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
+ err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
+ drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
+ if ( err != noErr
+ && err != kAudioHardwareBadObjectError)
+ {
+ LogRel(("CoreAudio: Failed to remove the playback sample rate changed listener (%RI32)\n", err));
+ }
+
+ if (pStreamOut->fDefDevChgListReg)
+ {
+ propAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+ propAdr.mScope = kAudioObjectPropertyScopeGlobal;
+ propAdr.mElement = kAudioObjectPropertyElementMaster;
+ err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
+ drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
if ( err != noErr
&& err != kAudioHardwareBadObjectError)
{
- LogRel(("CoreAudio: Failed to remove the playback sample rate changed listener (%RI32)\n", err));
+ LogRel(("CoreAudio: Failed to remove the default playback device changed listener (%RI32)\n", err));
}
- if (pStreamOut->fDefDevChgListReg)
- {
- propAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
- propAdr.mScope = kAudioObjectPropertyScopeGlobal;
- propAdr.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
- coreAudioDefaultDeviceChanged, &pStreamOut->Common);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the default playback device changed listener (%RI32)\n", err));
- }
+ pStreamOut->fDefDevChgListReg = false;
+ }
- pStreamOut->fDefDevChgListReg = false;
- }
+ if (pStreamOut->fDevStateChgListReg)
+ {
+ Assert(pStreamOut->deviceID != kAudioDeviceUnknown);
- if (pStreamOut->fDevStateChgListReg)
+ AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+ err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr2,
+ drvHostCoreAudioDeviceStateChangedCb, &pStreamOut->cbCtx);
+ if ( err != noErr
+ && err != kAudioHardwareBadObjectError)
{
- Assert(pStreamOut->deviceID != kAudioDeviceUnknown);
-
- AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr2,
- drvHostCoreAudioDeviceStateChanged, &pStreamOut->Common);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the playback device state changed listener (%RI32)\n", err));
- }
-
- pStreamOut->fDevStateChgListReg = false;
+ LogRel(("CoreAudio: Failed to remove the playback device state changed listener (%RI32)\n", err));
}
-#ifndef VBOX_WITH_AUDIO_CA_QUEUES
- err = AudioUnitUninitialize(pStreamOut->audioUnit);
- if (err == noErr)
- err = AudioComponentInstanceDispose(pStreamOut->audioUnit);
+ pStreamOut->fDevStateChgListReg = false;
+ }
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
+ if (RT_SUCCESS(rc))
+ {
+ PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
+
+ rc = coreAudioStreamUninitQueue(pCAStream);
+ if (RT_FAILURE(rc))
{
- LogRel(("CoreAudio: Failed to uninit the playback device (%RI32)\n", err));
+ LogRel(("CoreAudio: Failed to uninit stream queue: %Rrc)\n", rc));
+ return rc;
}
- pStreamOut->deviceID = kAudioDeviceUnknown;
- pStreamOut->audioUnit = NULL;
-#else
if (RTCritSectIsInitialized(&pCAStream->CritSect))
RTCritSectDelete(&pCAStream->CritSect);
-#endif
- if (pStreamOut->pCircBuf)
- {
- RTCircBufDestroy(pStreamOut->pCircBuf);
- pStreamOut->pCircBuf = NULL;
- }
+ }
- ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_UNINIT);
+ pStreamOut->deviceID = kAudioDeviceUnknown;
+ if (pStreamOut->pCircBuf)
+ {
+ RTCircBufDestroy(pStreamOut->pCircBuf);
+ pStreamOut->pCircBuf = NULL;
}
+
+ ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_UNINIT);
}
else
LogRel(("CoreAudio: Failed to stop playback on uninit, rc=%Rrc\n", rc));
@@ -3294,35 +1947,40 @@ static int coreAudioDestroyStreamOut(PPDMAUDIOSTREAM pStream)
return rc;
}
-static int coreAudioCreateStreamIn(PDRVHOSTCOREAUDIO pThis,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostCoreAudioInitIn(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
+ RT_NOREF(enmRecSource);
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
+ PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
- LogFlowFunc(("enmRecSource=%RU32\n", pCfgReq->DestSource.Source));
+ LogFlowFunc(("enmRecSource=%RU32\n", enmRecSource));
pStreamIn->deviceID = kAudioDeviceUnknown;
- pStreamIn->audioUnit = NULL;
- pStreamIn->pConverter = NULL;
- pStreamIn->sampleRatio = 1;
+#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
+ pStreamIn->ConverterRef = NULL;
+#endif
pStreamIn->pCircBuf = NULL;
pStreamIn->status = CA_STATUS_UNINIT;
pStreamIn->fDefDevChgListReg = false;
pStreamIn->fDevStateChgListReg = false;
- PCOREAUDIOSTREAM pCAStream = &pStreamIn->Common;
+ /* Set attributes. */
+ pStreamIn->Stream.enmDir = PDMAUDIODIR_IN;
+ pStreamIn->Stream.pIn = pStreamIn;
+
+ /* Set callback context. */
+ pStreamIn->cbCtx.pThis = pThis;
+ pStreamIn->cbCtx.pStream = &pStreamIn->Stream;
int rc;
- pCAStream->pThis = pThis;
- pCAStream->enmDir = PDMAUDIODIR_IN;
- pCAStream->pIn = pStreamIn;
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
+ PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
+
rc = RTCritSectInit(&pCAStream->CritSect);
if (RT_FAILURE(rc))
return rc;
@@ -3330,11 +1988,8 @@ static int coreAudioCreateStreamIn(PDRVHOSTCOREAUDIO pThis,
pCAStream->hThread = NIL_RTTHREAD;
pCAStream->fRun = false;
pCAStream->fIsRunning = false;
- pCAStream->fShutdown = false;
-#endif
bool fDeviceByUser = false; /* Do we use a device which was set by the user? */
-
#if 0
/* Try to find the audio device set by the user */
if (DeviceUID.pszInputDeviceUID)
@@ -3348,17 +2003,11 @@ static int coreAudioCreateStreamIn(PDRVHOSTCOREAUDIO pThis,
}
#endif
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_IN_INIT);
-
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = coreAudioStreamInitQueue(pCAStream, true /* fIn */, pCfgReq, pCfgAcq);
+ rc = coreAudioStreamInitQueue(pStreamIn->cbCtx.pStream, true /* fIn */, pCfgReq, pCfgAcq);
if (RT_SUCCESS(rc))
{
- pCfgAcq->cSampleBufferSize = _4K; /** @todo FIX THIS !!! */
+ *pcSamples = AQ_BUF_SAMPLES;
}
-#else
- rc = coreAudioStreamInitIn(pStreamIn, pCfgReq, pCfgAcq);
-#endif
if (RT_SUCCESS(rc))
{
ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_INIT);
@@ -3373,7 +2022,7 @@ static int coreAudioCreateStreamIn(PDRVHOSTCOREAUDIO pThis,
AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
- coreAudioDefaultDeviceChanged, &pStreamIn->Common);
+ drvHostCoreAudioDefaultDeviceChangedCb, &pStreamIn->cbCtx);
if ( err == noErr
|| err == kAudioHardwareIllegalOperationError)
{
@@ -3390,8 +2039,8 @@ static int coreAudioCreateStreamIn(PDRVHOSTCOREAUDIO pThis,
/* Register callback for being notified if the device stops being alive. */
AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
- err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr, drvHostCoreAudioDeviceStateChanged,
- &pStreamIn->Common);
+ err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr, drvHostCoreAudioDeviceStateChangedCb,
+ &pStreamIn->cbCtx);
if (err == noErr)
{
pStreamIn->fDevStateChgListReg = true;
@@ -3405,42 +2054,41 @@ static int coreAudioCreateStreamIn(PDRVHOSTCOREAUDIO pThis,
return rc;
}
-static int coreAudioCreateStreamOut(PDRVHOSTCOREAUDIO pThis,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostCoreAudioInitOut(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ uint32_t *pcSamples)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
+ PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
LogFlowFuncEnter();
pStreamOut->deviceID = kAudioDeviceUnknown;
- pStreamOut->audioUnit = NULL;
pStreamOut->pCircBuf = NULL;
pStreamOut->status = CA_STATUS_UNINIT;
pStreamOut->fDefDevChgListReg = false;
pStreamOut->fDevStateChgListReg = false;
- PCOREAUDIOSTREAM pCAStream = &pStreamOut->Common;
+ /* Set attributes. */
+ pStreamOut->Stream.enmDir = PDMAUDIODIR_OUT;
+ pStreamOut->Stream.pOut = pStreamOut;
- int rc;
+ /* Set callback context. */
+ pStreamOut->cbCtx.pThis = pThis;
+ pStreamOut->cbCtx.pStream = &pStreamOut->Stream;
- pCAStream->pThis = pThis;
- pCAStream->enmDir = PDMAUDIODIR_OUT;
- pCAStream->pOut = pStreamOut;
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = RTCritSectInit(&pCAStream->CritSect);
+ PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
+
+ int rc = RTCritSectInit(&pCAStream->CritSect);
if (RT_FAILURE(rc))
return rc;
pCAStream->hThread = NIL_RTTHREAD;
pCAStream->fRun = false;
pCAStream->fIsRunning = false;
- pCAStream->fShutdown = false;
-#endif
bool fDeviceByUser = false; /* Do we use a device which was set by the user? */
@@ -3459,15 +2107,11 @@ static int coreAudioCreateStreamOut(PDRVHOSTCOREAUDIO pThis,
}
#endif
-#ifdef VBOX_WITH_AUDIO_CA_QUEUES
- rc = coreAudioStreamInitQueue(pCAStream, false /* fIn */, pCfgReq, pCfgAcq);
+ rc = coreAudioStreamInitQueue(pStreamOut->cbCtx.pStream, false /* fIn */, pCfgReq, pCfgAcq);
if (RT_SUCCESS(rc))
{
- pCfgAcq->cSampleBufferSize = _4K; /** @todo FIX THIS !!! */
+ *pcSamples = AQ_BUF_SAMPLES;
}
-#else
- rc = coreAudioStreamInitOut(pStreamOut, pCfgReq, pCfgAcq);
-#endif
if (RT_SUCCESS(rc))
{
ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_INIT);
@@ -3480,7 +2124,7 @@ static int coreAudioCreateStreamOut(PDRVHOSTCOREAUDIO pThis,
AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
- coreAudioDefaultDeviceChanged, &pStreamOut->Common);
+ drvHostCoreAudioDefaultDeviceChangedCb, &pStreamOut->cbCtx);
if (err == noErr)
{
pStreamOut->fDefDevChgListReg = true;
@@ -3495,8 +2139,8 @@ static int coreAudioCreateStreamOut(PDRVHOSTCOREAUDIO pThis,
/* Register callback for being notified if the device stops being alive. */
AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster };
- err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr, drvHostCoreAudioDeviceStateChanged,
- (void *)&pStreamOut->Common);
+ err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr, drvHostCoreAudioDeviceStateChangedCb,
+ (void *)&pStreamOut->cbCtx);
if (err == noErr)
{
pStreamOut->fDevStateChgListReg = true;
@@ -3510,165 +2154,30 @@ static int coreAudioCreateStreamOut(PDRVHOSTCOREAUDIO pThis,
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnGetConfig}
- */
-static DECLCALLBACK(int) drvHostCoreAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
-
- PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
-
- return coreAudioUpdateStatusInternalEx(pThis, pBackendCfg, 0 /* fEnum */);
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostCoreAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- RT_NOREF(enmDir);
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
-
- return PDMAUDIOBACKENDSTS_RUNNING;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvHostCoreAudioStreamCreate(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
-
- PDRVHOSTCOREAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTCOREAUDIO(pInterface);
-
- int rc;
- if (pCfgReq->enmDir == PDMAUDIODIR_IN)
- rc = coreAudioCreateStreamIn(pThis, pStream, pCfgReq, pCfgAcq);
- else
- rc = coreAudioCreateStreamOut(pThis, pStream, pCfgReq, pCfgAcq);
-
- LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvHostCoreAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = coreAudioDestroyStreamIn(pStream);
- else
- rc = coreAudioDestroyStreamOut(pStream);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamControl}
- */
-static DECLCALLBACK(int) drvHostCoreAudioStreamControl(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = coreAudioControlStreamIn((PCOREAUDIOSTREAMIN)pStream, enmStreamCmd);
- else
- rc = coreAudioControlStreamOut((PCOREAUDIOSTREAMOUT)pStream, enmStreamCmd);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostCoreAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(bool) drvHostCoreAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
{
- RT_NOREF(pInterface);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
-
- PDMAUDIOSTRMSTS strmSts = PDMAUDIOSTRMSTS_FLAG_NONE;
-
- if (pStream->enmDir == PDMAUDIODIR_IN)
- {
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pStream;
-
- if (ASMAtomicReadU32(&pStreamIn->status) == CA_STATUS_INIT)
- strmSts |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED;
-
- if (strmSts & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_READABLE;
- }
- else if (pStream->enmDir == PDMAUDIODIR_OUT)
- {
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pStream;
-
- if (ASMAtomicReadU32(&pStreamOut->status) == CA_STATUS_INIT)
- strmSts |= PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED;
-
- if (strmSts & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
- }
- else
- AssertFailed();
-
- return strmSts;
+ NOREF(pInterface);
+ NOREF(enmDir);
+ return true; /* Always all enabled. */
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnStreamIterate}
- */
-static DECLCALLBACK(int) drvHostCoreAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostCoreAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
- /* Nothing to do here for Core Audio. */
- return VINF_SUCCESS;
+ return coreAudioUpdateStatusInternalEx(pThis, pCfg, 0 /* fEnum */);
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO, pfnShutdown}
- */
static DECLCALLBACK(void) drvHostCoreAudioShutdown(PPDMIHOSTAUDIO pInterface)
{
- RT_NOREF(pInterface);
+ NOREF(pInterface);
}
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
static DECLCALLBACK(void *) drvHostCoreAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
@@ -3676,14 +2185,13 @@ static DECLCALLBACK(void *) drvHostCoreAudioQueryInterface(PPDMIBASE pInterface,
return NULL;
}
-/**
- * @callback_method_impl{FNPDMDRVCONSTRUCT,
- * Construct a DirectSound Audio driver instance.}
+ /* Construct a DirectSound Audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
*/
static DECLCALLBACK(int) drvHostCoreAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
RT_NOREF(pCfg, fFlags);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
LogRel(("Audio: Initializing Core Audio driver\n"));
diff --git a/src/VBox/Devices/Audio/DrvHostDSound.cpp b/src/VBox/Devices/Audio/DrvHostDSound.cpp
index 7a196eb..150cccb 100644
--- a/src/VBox/Devices/Audio/DrvHostDSound.cpp
+++ b/src/VBox/Devices/Audio/DrvHostDSound.cpp
@@ -13,14 +13,12 @@
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ * --------------------------------------------------------------------
+ *
*/
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
#include <VBox/log.h>
+
#include <iprt/win/windows.h>
#include <dsound.h>
@@ -31,10 +29,6 @@
#include "DrvAudio.h"
#include "VBoxDD.h"
-
-/*********************************************************************************************************************************
-* Defined Constants And Macros *
-*********************************************************************************************************************************/
/*
* IDirectSound* interface uses HRESULT status codes and the driver callbacks use
* the IPRT status codes. To minimize HRESULT->IPRT conversion most internal functions
@@ -52,35 +46,26 @@
* Messages which always should go to the release log use LogRel.
*/
/* General code behavior. */
-#define DSLOG(a) do { LogRel2(a); } while(0)
+#define DSLOG(a) do { LogRel2(a); } while(0)
/* Something which produce a lot of logging during playback/recording. */
-#define DSLOGF(a) do { LogRel3(a); } while(0)
+#define DSLOGF(a) do { LogRel3(a); } while(0)
/* Important messages like errors. Limited in the default release log to avoid log flood. */
-#define DSLOGREL(a) \
- do { \
- static int8_t s_cLogged = 0; \
- if (s_cLogged < 8) { \
- ++s_cLogged; \
- LogRel(a); \
- } else DSLOG(a); \
+#define DSLOGREL(a) \
+ do { \
+ static int8_t scLogged = 0; \
+ if (scLogged < 8) { \
+ ++scLogged; \
+ LogRel(a); \
+ } \
+ else { \
+ DSLOG(a); \
+ } \
} while (0)
-
-/** Maximum number of attempts to restore the sound buffer before giving up. */
-#define DRV_DSOUND_RESTORE_ATTEMPTS_MAX 3
-
-/** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
-#define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \
- ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTDSOUND, IHostAudio)) )
-
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
/* Dynamically load dsound.dll. */
-typedef HRESULT WINAPI FNDIRECTSOUNDENUMERATEW(LPDSENUMCALLBACKW pDSEnumCallback, PVOID pContext);
+typedef HRESULT WINAPI FNDIRECTSOUNDENUMERATEW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext);
typedef FNDIRECTSOUNDENUMERATEW *PFNDIRECTSOUNDENUMERATEW;
-typedef HRESULT WINAPI FNDIRECTSOUNDCAPTUREENUMERATEW(LPDSENUMCALLBACKW pDSEnumCallback, PVOID pContext);
+typedef HRESULT WINAPI FNDIRECTSOUNDCAPTUREENUMERATEW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext);
typedef FNDIRECTSOUNDCAPTUREENUMERATEW *PFNDIRECTSOUNDCAPTUREENUMERATEW;
#ifdef VBOX_WITH_AUDIO_CALLBACKS
@@ -106,14 +91,11 @@ typedef struct DSOUNDHOSTCFG
typedef struct DSOUNDSTREAMOUT
{
- /** Note: Always must come first! */
- PDMAUDIOSTREAM Stream;
- /** The PCM properties of this stream. */
- PDMAUDIOPCMPROPS Props;
- LPDIRECTSOUND8 pDS; /** @todo Move this out of this structure! Not required per-stream (e.g. for multi-channel). */
+ PDMAUDIOHSTSTRMOUT strmOut; /* Always must come first! */
+ LPDIRECTSOUND8 pDS;
LPDIRECTSOUNDBUFFER8 pDSB;
- DWORD offPlayWritePos;
- DWORD cMaxSamplesInBuffer;
+ DWORD cbPlayWritePos;
+ DWORD csPlaybackBufferSize;
bool fEnabled;
bool fRestartPlayback;
PDMAUDIOSTREAMCFG streamCfg;
@@ -121,15 +103,12 @@ typedef struct DSOUNDSTREAMOUT
typedef struct DSOUNDSTREAMIN
{
- /** Associated host input stream. */
- PDMAUDIOSTREAM Stream;
- /** The PCM properties of this stream. */
- PDMAUDIOPCMPROPS Props;
+ PDMAUDIOHSTSTRMIN strmIn; /* Always must come first! */
LPDIRECTSOUNDCAPTURE8 pDSC;
LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB;
- DWORD idxSampleCaptureReadPos;
- DWORD cMaxSamplesInBuffer;
- HRESULT hrLastCapture;
+ DWORD csCaptureReadPos;
+ DWORD csCaptureBufferSize;
+ HRESULT hrLastCaptureIn;
PDMAUDIORECSOURCE enmRecSource;
bool fEnabled;
PDMAUDIOSTREAMCFG streamCfg;
@@ -182,14 +161,10 @@ typedef struct DRVHOSTDSOUND
*/
typedef struct DSOUNDENUMCBCTX
{
- /** Pointer to host backend driver. */
PDRVHOSTDSOUND pDrv;
+ PPDMAUDIOBACKENDCFG pCfg;
/** Enumeration flags. */
uint32_t fFlags;
- /** Number of found input devices. */
- uint8_t cDevIn;
- /** Number of found output devices. */
- uint8_t cDevOut;
} DSOUNDENUMCBCTX, *PDSOUNDENUMCBCTX;
typedef struct DSOUNDDEV
@@ -199,25 +174,26 @@ typedef struct DSOUNDDEV
GUID Guid;
} DSOUNDDEV, *PDSOUNDDEV;
+/** Maximum number of attempts to restore the sound buffer before giving up. */
+#define DRV_DSOUND_RESTORE_ATTEMPTS_MAX 3
-/*********************************************************************************************************************************
-* Internal Functions *
-*********************************************************************************************************************************/
-static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB);
-static void dsoundDeviceRemove(PDSOUNDDEV pDev);
-static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg);
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
-static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown);
-#endif
+/** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
+#define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \
+ ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTDSOUND, IHostAudio)) )
+static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB);
+static void dsoundDeviceRemove(PDSOUNDDEV pDev);
+static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg);
+#ifdef VBOX_WITH_AUDIO_CALLBACKS
+static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown);
+#endif
static DWORD dsoundRingDistance(DWORD offEnd, DWORD offBegin, DWORD cSize)
{
return offEnd >= offBegin ? offEnd - offBegin : cSize - offBegin + offEnd;
}
-
static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
{
AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
@@ -234,86 +210,95 @@ static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
switch (pCfg->enmFormat)
{
- case PDMAUDIOFMT_S8:
- case PDMAUDIOFMT_U8:
+ case AUD_FMT_S8:
+ case AUD_FMT_U8:
pFmt->wBitsPerSample = 8;
break;
- case PDMAUDIOFMT_S16:
- case PDMAUDIOFMT_U16:
+ case AUD_FMT_S16:
+ case AUD_FMT_U16:
pFmt->wBitsPerSample = 16;
pFmt->nAvgBytesPerSec <<= 1;
pFmt->nBlockAlign <<= 1;
break;
- case PDMAUDIOFMT_S32:
- case PDMAUDIOFMT_U32:
+ case AUD_FMT_S32:
+ case AUD_FMT_U32:
pFmt->wBitsPerSample = 32;
pFmt->nAvgBytesPerSec <<= 2;
pFmt->nBlockAlign <<= 2;
break;
default:
- AssertMsgFailed(("Wave format %d not supported\n", pCfg->enmFormat));
+ AssertMsgFailed(("Wave format %ld not supported\n", pCfg->enmFormat));
return VERR_NOT_SUPPORTED;
}
return VINF_SUCCESS;
}
-
static int dsoundGetPosOut(PDRVHOSTDSOUND pThis,
- PDSOUNDSTREAMOUT pDSoundStream, DWORD *pdwBuffer, DWORD *pdwFree, DWORD *pdwPlayPos)
+ PDSOUNDSTREAMOUT pDSoundStrmOut, DWORD *pdwBuffer, DWORD *pdwFree, DWORD *pdwPlayPos)
{
- AssertPtr(pThis);
- AssertPtrReturn(pDSoundStream, VERR_INVALID_POINTER);
- AssertPtrNull(pdwBuffer);
- AssertPtrNull(pdwFree);
- AssertPtrNull(pdwPlayPos);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pDSoundStrmOut, VERR_INVALID_POINTER);
- LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStream->pDSB;
+ LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStrmOut->pDSB;
if (!pDSB)
return VERR_INVALID_POINTER;
+ DWORD cbBuffer = AUDIOMIXBUF_S2B(&pDSoundStrmOut->strmOut.MixBuf, pDSoundStrmOut->csPlaybackBufferSize);
+
/* Get the current play position which is used for calculating the free space in the buffer. */
- DWORD cbPlayPos;
- HRESULT hr = E_FAIL;
+ DWORD cbPlayPos = 0; /* MSC maybe used uninitialized */
+ HRESULT hr = E_FAIL; /* MSC maybe used uninitialized */
for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
{
hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
- if (SUCCEEDED(hr))
+ if ( SUCCEEDED(hr)
+ || hr != DSERR_BUFFERLOST) /** @todo: MSDN doesn't state this error for GetCurrentPosition(). */
{
- DWORD const cbBuffer = AUDIOMIXBUF_S2B(&pDSoundStream->Stream.MixBuf, pDSoundStream->cMaxSamplesInBuffer);
- if (pdwBuffer)
- *pdwBuffer = cbBuffer;
- if (pdwFree)
- *pdwFree = cbBuffer - dsoundRingDistance(pDSoundStream->offPlayWritePos, cbPlayPos, cbBuffer);
- if (pdwPlayPos)
- *pdwPlayPos = cbPlayPos;
- return VINF_SUCCESS;
- }
- if (hr != DSERR_BUFFERLOST) /** @todo MSDN doesn't state this error for GetCurrentPosition(). */
break;
- LogFlowFunc(("Getting playing position failed due to lost buffer, restoring ...\n"));
- directSoundPlayRestore(pThis, pDSB);
+ }
+ else
+ {
+ LogFlowFunc(("Getting playing position failed due to lost buffer, restoring ...\n"));
+ directSoundPlayRestore(pThis, pDSB);
+ }
+ }
+
+ int rc = VINF_SUCCESS;
+
+ if (FAILED(hr))
+ {
+ if (hr != DSERR_BUFFERLOST) /* Avoid log flooding if the error is still there. */
+ DSLOGREL(("DSound: Getting current playback position failed with %Rhrc\n", hr));
+ LogFlowFunc(("Failed with %Rhrc\n", hr));
+
+ rc = VERR_NOT_AVAILABLE;
}
+ else
+ {
+ if (pdwBuffer)
+ *pdwBuffer = cbBuffer;
- if (hr != DSERR_BUFFERLOST) /* Avoid log flooding if the error is still there. */
- DSLOGREL(("DSound: Getting current playback position failed with %Rhrc\n", hr));
- LogFlowFunc(("Failed with %Rhrc\n", hr));
+ if (pdwFree)
+ *pdwFree = cbBuffer - dsoundRingDistance(pDSoundStrmOut->cbPlayWritePos, cbPlayPos, cbBuffer);
+
+ if (pdwPlayPos)
+ *pdwPlayPos = cbPlayPos;
+ }
- int rc = VERR_NOT_AVAILABLE;
LogFlowFuncLeaveRC(rc);
return rc;
}
-
-static char *dsoundGUIDToUtf8StrA(LPCGUID pGUID)
+static char *dsoundGUIDToUtf8StrA(LPCGUID lpGUID)
{
- if (pGUID)
+ if (lpGUID)
{
LPOLESTR lpOLEStr;
- HRESULT hr = StringFromCLSID(*pGUID, &lpOLEStr);
+ HRESULT hr = StringFromCLSID(*lpGUID, &lpOLEStr);
if (SUCCEEDED(hr))
{
char *pszGUID;
@@ -327,7 +312,6 @@ static char *dsoundGUIDToUtf8StrA(LPCGUID pGUID)
return RTStrDup("{Default device}");
}
-
/**
* Clears the list of the host's playback + capturing devices.
*
@@ -351,7 +335,6 @@ static void dsoundDevicesClear(PDRVHOSTDSOUND pThis)
}
}
-
static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB)
{
RT_NOREF(pThis);
@@ -361,9 +344,8 @@ static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8
return hr;
}
-
static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB,
- PVOID pv1, PVOID pv2,
+ LPVOID pv1, LPVOID pv2,
DWORD cb1, DWORD cb2)
{
RT_NOREF(pThis);
@@ -373,9 +355,8 @@ static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8
return hr;
}
-
static HRESULT directSoundCaptureUnlock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
- PVOID pv1, PVOID pv2,
+ LPVOID pv1, LPVOID pv2,
DWORD cb1, DWORD cb2)
{
HRESULT hr = IDirectSoundCaptureBuffer8_Unlock(pDSCB, pv1, cb1, pv2, cb2);
@@ -384,52 +365,63 @@ static HRESULT directSoundCaptureUnlock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
return hr;
}
-
static HRESULT directSoundPlayLock(PDRVHOSTDSOUND pThis,
- LPDIRECTSOUNDBUFFER8 pDSB, PPDMAUDIOPCMPROPS pProps,
+ LPDIRECTSOUNDBUFFER8 pDSB, PDMPCMPROPS *pProps,
DWORD dwOffset, DWORD dwBytes,
- PVOID *ppv1, PVOID *ppv2,
+ LPVOID *ppv1, LPVOID *ppv2,
DWORD *pcb1, DWORD *pcb2,
DWORD dwFlags)
{
- HRESULT hr = E_FAIL;
- AssertCompile(DRV_DSOUND_RESTORE_ATTEMPTS_MAX > 0);
+ LPVOID pv1 = NULL;
+ LPVOID pv2 = NULL;
+ DWORD cb1 = 0;
+ DWORD cb2 = 0;
+
+ HRESULT hr = E_FAIL; /* MSC maybe uninitalized */
for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
{
- *ppv1 = *ppv2 = NULL;
- *pcb1 = *pcb2 = 0;
- hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, ppv1, pcb1, ppv2, pcb2, dwFlags);
- if (SUCCEEDED(hr))
+ hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
+ if ( SUCCEEDED(hr)
+ || hr != DSERR_BUFFERLOST)
+ break;
+ else
{
- if ( (!*ppv1 || !(*pcb1 & pProps->uAlign))
- && (!*ppv2 || !(*pcb2 & pProps->uAlign)) )
- return S_OK;
- DSLOGREL(("DSound: Locking playback buffer returned misaligned buffer: cb1=%#RX32, cb2=%#RX32 (alignment: %#RX32)\n",
- *pcb1, *pcb2, pProps->uAlign));
- directSoundPlayUnlock(pThis, pDSB, *ppv1, *ppv2, *pcb1, *pcb2);
- return E_FAIL;
+ LogFlowFunc(("Locking failed due to lost buffer, restoring ...\n"));
+ directSoundPlayRestore(pThis, pDSB);
}
+ }
- if (hr != DSERR_BUFFERLOST)
- break;
+ if (FAILED(hr))
+ {
+ DSLOGREL(("DSound: Locking playback buffer failed with %Rhrc\n", hr));
+ return hr;
+ }
- LogFlowFunc(("Locking failed due to lost buffer, restoring ...\n"));
- directSoundPlayRestore(pThis, pDSB);
+ if ( (pv1 && (cb1 & pProps->uAlign))
+ || (pv2 && (cb2 & pProps->uAlign)))
+ {
+ DSLOGREL(("DSound: Locking playback buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
+ cb1, cb2, pProps->uAlign));
+ directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
+ return E_FAIL;
}
- DSLOGREL(("DSound: Locking playback buffer failed with %Rhrc\n", hr));
- return hr;
-}
+ *ppv1 = pv1;
+ *ppv2 = pv2;
+ *pcb1 = cb1;
+ *pcb2 = cb2;
+ return S_OK;
+}
-static HRESULT directSoundCaptureLock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB, PPDMAUDIOPCMPROPS pProps,
+static HRESULT directSoundCaptureLock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB, PPDMPCMPROPS pProps,
DWORD dwOffset, DWORD dwBytes,
- PVOID *ppv1, PVOID *ppv2,
+ LPVOID *ppv1, LPVOID *ppv2,
DWORD *pcb1, DWORD *pcb2,
DWORD dwFlags)
{
- PVOID pv1 = NULL;
- PVOID pv2 = NULL;
+ LPVOID pv1 = NULL;
+ LPVOID pv2 = NULL;
DWORD cb1 = 0;
DWORD cb2 = 0;
@@ -463,37 +455,36 @@ static HRESULT directSoundCaptureLock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB, PPDMAUD
* DirectSound playback
*/
-static void directSoundPlayInterfaceRelease(PDSOUNDSTREAMOUT pDSoundStream)
+static void directSoundPlayInterfaceRelease(PDSOUNDSTREAMOUT pDSoundStrmOut)
{
- if (pDSoundStream->pDS)
+ if (pDSoundStrmOut->pDS)
{
- IDirectSound8_Release(pDSoundStream->pDS);
- pDSoundStream->pDS = NULL;
+ IDirectSound8_Release(pDSoundStrmOut->pDS);
+ pDSoundStrmOut->pDS = NULL;
}
}
-
-static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStream)
+static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
{
- if (pDSoundStream->pDS != NULL)
+ if (pDSoundStrmOut->pDS != NULL)
{
DSLOG(("DSound: DirectSound instance already exists\n"));
return S_OK;
}
HRESULT hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_ALL,
- IID_IDirectSound8, (void **)&pDSoundStream->pDS);
+ IID_IDirectSound8, (void **)&pDSoundStrmOut->pDS);
if (FAILED(hr))
{
DSLOGREL(("DSound: Creating playback instance failed with %Rhrc\n", hr));
}
else
{
- hr = IDirectSound8_Initialize(pDSoundStream->pDS, pThis->cfg.pGuidPlay);
+ hr = IDirectSound8_Initialize(pDSoundStrmOut->pDS, pThis->cfg.pGuidPlay);
if (SUCCEEDED(hr))
{
HWND hWnd = GetDesktopWindow();
- hr = IDirectSound8_SetCooperativeLevel(pDSoundStream->pDS, hWnd, DSSCL_PRIORITY);
+ hr = IDirectSound8_SetCooperativeLevel(pDSoundStrmOut->pDS, hWnd, DSSCL_PRIORITY);
if (FAILED(hr))
DSLOGREL(("DSound: Setting cooperative level for window %p failed with %Rhrc\n", hWnd, hr));
}
@@ -505,26 +496,25 @@ static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREA
else
DSLOGREL(("DSound: DirectSound playback initialization failed with %Rhrc\n", hr));
- directSoundPlayInterfaceRelease(pDSoundStream);
+ directSoundPlayInterfaceRelease(pDSoundStrmOut);
}
}
return hr;
}
-
-static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStream)
+static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
{
AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStream, E_POINTER);
+ AssertPtrReturn(pDSoundStrmOut, E_POINTER);
- DSLOG(("DSound: Closing playback stream %p, buffer %p\n", pDSoundStream, pDSoundStream->pDSB));
+ DSLOG(("DSound: Closing playback stream %p, buffer %p\n", pDSoundStrmOut, pDSoundStrmOut->pDSB));
HRESULT hr = S_OK;
- if (pDSoundStream->pDSB)
+ if (pDSoundStrmOut->pDSB)
{
- hr = IDirectSoundBuffer8_Stop(pDSoundStream->pDSB);
+ hr = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
if (SUCCEEDED(hr))
{
#ifdef VBOX_WITH_AUDIO_CALLBACKS
@@ -536,52 +526,51 @@ static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSou
if (pThis->cEvents)
pThis->cEvents--;
- pThis->pDSStream = NULL;
+ pThis->pDSStrmOut = NULL;
}
int rc2 = dsoundNotifyThread(pThis, false /* fShutdown */);
AssertRC(rc2);
#endif
- IDirectSoundBuffer8_Release(pDSoundStream->pDSB);
- pDSoundStream->pDSB = NULL;
+ IDirectSoundBuffer8_Release(pDSoundStrmOut->pDSB);
+ pDSoundStrmOut->pDSB = NULL;
}
else
- DSLOGREL(("DSound: Stop playback stream %p when closing %Rhrc\n", pDSoundStream, hr));
+ DSLOGREL(("DSound: Stop playback stream %p when closing %Rhrc\n", pDSoundStrmOut, hr));
}
if (SUCCEEDED(hr))
- directSoundPlayInterfaceRelease(pDSoundStream);
+ directSoundPlayInterfaceRelease(pDSoundStrmOut);
return hr;
}
-
-static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStream)
+static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStream, E_POINTER);
+ AssertPtrReturn(pThis, E_POINTER);
+ AssertPtrReturn(pDSoundStrmOut, E_POINTER);
- DSLOG(("DSound: pDSoundStream=%p, cbBufferOut=%RU32, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
- pDSoundStream,
+ DSLOG(("DSound: pDSoundStrmOut=%p, cbBufferOut=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
+ pDSoundStrmOut,
pThis->cfg.cbBufferOut,
- pDSoundStream->Props.uHz,
- pDSoundStream->Props.cChannels,
- pDSoundStream->Props.cBits,
- pDSoundStream->Props.fSigned));
+ pDSoundStrmOut->strmOut.Props.uHz,
+ pDSoundStrmOut->strmOut.Props.cChannels,
+ pDSoundStrmOut->strmOut.Props.cBits,
+ pDSoundStrmOut->strmOut.Props.fSigned));
- if (pDSoundStream->pDSB != NULL)
+ if (pDSoundStrmOut->pDSB != NULL)
{
/* Should not happen but be forgiving. */
DSLOGREL(("DSound: Playback buffer already exists\n"));
- directSoundPlayClose(pThis, pDSoundStream);
+ directSoundPlayClose(pThis, pDSoundStrmOut);
}
WAVEFORMATEX wfx;
- int rc = dsoundWaveFmtFromCfg(&pDSoundStream->streamCfg, &wfx);
+ int rc = dsoundWaveFmtFromCfg(&pDSoundStrmOut->streamCfg, &wfx);
if (RT_FAILURE(rc))
return E_INVALIDARG;
- HRESULT hr = directSoundPlayInterfaceCreate(pThis, pDSoundStream);
+ HRESULT hr = directSoundPlayInterfaceCreate(pThis, pDSoundStrmOut);
if (FAILED(hr))
return hr;
@@ -611,7 +600,7 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
#endif
bd.dwBufferBytes = pThis->cfg.cbBufferOut;
- hr = IDirectSound8_CreateSoundBuffer(pDSoundStream->pDS, &bd, &pDSB, NULL);
+ hr = IDirectSound8_CreateSoundBuffer(pDSoundStrmOut->pDS, &bd, &pDSB, NULL);
if (FAILED(hr))
{
DSLOGREL(("DSound: Creating playback sound buffer failed with %Rhrc\n", hr));
@@ -619,7 +608,7 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
}
/* "Upgrade" to IDirectSoundBuffer8 interface. */
- hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (PVOID *)&pDSoundStream->pDSB);
+ hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (LPVOID *)&pDSoundStrmOut->pDSB);
IDirectSoundBuffer_Release(pDSB);
if (FAILED(hr))
{
@@ -630,7 +619,7 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
/*
* Query the actual parameters.
*/
- hr = IDirectSoundBuffer8_GetFormat(pDSoundStream->pDSB, &wfx, sizeof(wfx), NULL);
+ hr = IDirectSoundBuffer8_GetFormat(pDSoundStrmOut->pDSB, &wfx, sizeof(wfx), NULL);
if (FAILED(hr))
{
DSLOGREL(("DSound: Getting playback format failed with %Rhrc\n", hr));
@@ -640,7 +629,7 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
DSBCAPS bc;
RT_ZERO(bc);
bc.dwSize = sizeof(bc);
- hr = IDirectSoundBuffer8_GetCaps(pDSoundStream->pDSB, &bc);
+ hr = IDirectSoundBuffer8_GetCaps(pDSoundStrmOut->pDSB, &bc);
if (FAILED(hr))
{
DSLOGREL(("DSound: Getting playback capabilities failed with %Rhrc\n", hr));
@@ -667,9 +656,9 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
wfx.wBitsPerSample,
wfx.cbSize));
- if (bc.dwBufferBytes & pDSoundStream->Props.uAlign)
+ if (bc.dwBufferBytes & pDSoundStrmOut->strmOut.Props.uAlign)
DSLOGREL(("DSound: Playback capabilities returned misaligned buffer: size %RU32, alignment %RU32\n",
- bc.dwBufferBytes, pDSoundStream->Props.uAlign + 1));
+ bc.dwBufferBytes, pDSoundStrmOut->strmOut.Props.uAlign + 1));
if (bc.dwBufferBytes != pThis->cfg.cbBufferOut)
DSLOGREL(("DSound: Playback buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",
@@ -680,8 +669,8 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
* dsoundPlayStart initializes part of it to make sure that Stop/Start continues with a correct
* playback buffer position.
*/
- pDSoundStream->cMaxSamplesInBuffer = bc.dwBufferBytes >> pDSoundStream->Props.cShift;
- DSLOG(("DSound: cMaxSamplesInBuffer=%RU32\n", pDSoundStream->cMaxSamplesInBuffer));
+ pDSoundStrmOut->csPlaybackBufferSize = bc.dwBufferBytes >> pDSoundStrmOut->strmOut.Props.cShift;
+ DSLOG(("DSound: csPlaybackBufferSize=%RU32\n", pDSoundStrmOut->csPlaybackBufferSize));
#ifdef VBOX_WITH_AUDIO_CALLBACKS
/*
@@ -698,7 +687,7 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
}
LPDIRECTSOUNDNOTIFY8 pNotify;
- hr = IDirectSoundNotify_QueryInterface(pDSoundStream->pDSB, IID_IDirectSoundNotify8, (PVOID *)&pNotify);
+ hr = IDirectSoundNotify_QueryInterface(pDSoundStrmOut->pDSB, IID_IDirectSoundNotify8, (LPVOID *)&pNotify);
if (SUCCEEDED(hr))
{
DSBPOSITIONNOTIFY dsBufPosNotify;
@@ -718,7 +707,7 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
if (FAILED(hr))
break;
- pThis->pDSStreamOut = pDSoundStream;
+ pThis->pDSStrmOut = pDSoundStrmOut;
Assert(pThis->cEvents < VBOX_DSOUND_MAX_EVENTS);
pThis->cEvents++;
@@ -727,54 +716,53 @@ static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
dsoundNotifyThread(pThis, false /* fShutdown */);
/* Trigger the just installed output notification. */
- hr = IDirectSoundBuffer8_Play(pDSoundStream->pDSB, 0, 0, 0);
+ hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, 0);
#endif /* VBOX_WITH_AUDIO_CALLBACKS */
} while (0);
if (FAILED(hr))
- directSoundPlayClose(pThis, pDSoundStream);
+ directSoundPlayClose(pThis, pDSoundStrmOut);
return hr;
}
-
-static void dsoundPlayClearSamples(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStream)
+static void dsoundPlayClearSamples(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
{
- AssertPtrReturnVoid(pDSoundStream);
+ AssertPtrReturnVoid(pDSoundStrmOut);
- PPDMAUDIOSTREAM pStream = &pDSoundStream->Stream;
+ PPDMAUDIOHSTSTRMOUT pStrmOut = &pDSoundStrmOut->strmOut;
- PVOID pv1, pv2;
+ LPVOID pv1, pv2;
DWORD cb1, cb2;
- HRESULT hr = directSoundPlayLock(pThis, pDSoundStream->pDSB, &pDSoundStream->Props,
- 0 /* dwOffset */, AUDIOMIXBUF_S2B(&pStream->MixBuf, pDSoundStream->cMaxSamplesInBuffer),
+ HRESULT hr = directSoundPlayLock(pThis, pDSoundStrmOut->pDSB, &pDSoundStrmOut->strmOut.Props,
+ 0 /* dwOffset */, AUDIOMIXBUF_S2B(&pStrmOut->MixBuf, pDSoundStrmOut->csPlaybackBufferSize),
&pv1, &pv2, &cb1, &cb2, DSBLOCK_ENTIREBUFFER);
if (SUCCEEDED(hr))
{
- DWORD len1 = AUDIOMIXBUF_B2S(&pStream->MixBuf, cb1);
- DWORD len2 = AUDIOMIXBUF_B2S(&pStream->MixBuf, cb2);
+ DWORD len1 = AUDIOMIXBUF_B2S(&pStrmOut->MixBuf, cb1);
+ DWORD len2 = AUDIOMIXBUF_B2S(&pStrmOut->MixBuf, cb2);
if (pv1 && len1)
- DrvAudioHlpClearBuf(&pDSoundStream->Props, pv1, cb1, len1);
+ DrvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv1, cb1, len1);
if (pv2 && len2)
- DrvAudioHlpClearBuf(&pDSoundStream->Props, pv2, cb2, len2);
+ DrvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv2, cb2, len2);
- directSoundPlayUnlock(pThis, pDSoundStream->pDSB, pv1, pv2, cb1, cb2);
+ directSoundPlayUnlock(pThis, pDSoundStrmOut->pDSB, pv1, pv2, cb1, cb2);
}
}
-
static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
{
- AssertPtr(pThis);
+ AssertPtrReturn(pThis, E_POINTER);
AssertPtrReturn(pDSB, E_POINTER);
- AssertPtrNull(pdwStatus);
+ /* pdwStatus is optional. */
DWORD dwStatus = 0;
- HRESULT hr = E_FAIL;
+
+ HRESULT hr = E_FAIL; /* MSC maybe used uninitialized */
for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
{
hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
@@ -800,24 +788,23 @@ static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFE
return hr;
}
-
-static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStream)
+static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStream, E_POINTER);
+ AssertPtrReturn(pThis, E_POINTER);
+ AssertPtrReturn(pDSoundStrmOut, E_POINTER);
HRESULT hr;
- if (pDSoundStream->pDSB != NULL)
+ if (pDSoundStrmOut->pDSB != NULL)
{
DSLOG(("DSound: Stopping playback\n"));
- HRESULT hr2 = IDirectSoundBuffer8_Stop(pDSoundStream->pDSB);
+ HRESULT hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
if (FAILED(hr2))
{
- hr2 = directSoundPlayRestore(pThis, pDSoundStream->pDSB);
+ hr2 = directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
if (FAILED(hr2))
- hr2 = IDirectSoundBuffer8_Stop(pDSoundStream->pDSB);
+ hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
}
if (FAILED(hr2))
@@ -830,8 +817,8 @@ static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
if (SUCCEEDED(hr))
{
- dsoundPlayClearSamples(pThis, pDSoundStream);
- pDSoundStream->fEnabled = false;
+ dsoundPlayClearSamples(pThis, pDSoundStrmOut);
+ pDSoundStrmOut->fEnabled = false;
}
else
DSLOGREL(("DSound: Stopping playback failed with %Rhrc\n", hr));
@@ -839,17 +826,16 @@ static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoun
return hr;
}
-
-static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStream)
+static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStream, E_POINTER);
+ AssertPtrReturn(pThis, E_POINTER);
+ AssertPtrReturn(pDSoundStrmOut, E_POINTER);
HRESULT hr;
- if (pDSoundStream->pDSB != NULL)
+ if (pDSoundStrmOut->pDSB != NULL)
{
DWORD dwStatus;
- hr = directSoundPlayGetStatus(pThis, pDSoundStream->pDSB, &dwStatus);
+ hr = directSoundPlayGetStatus(pThis, pDSoundStrmOut->pDSB, &dwStatus);
if (SUCCEEDED(hr))
{
if (dwStatus & DSBSTATUS_PLAYING)
@@ -858,15 +844,15 @@ static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSou
}
else
{
- dsoundPlayClearSamples(pThis, pDSoundStream);
+ dsoundPlayClearSamples(pThis, pDSoundStrmOut);
- pDSoundStream->fRestartPlayback = true;
- pDSoundStream->fEnabled = true;
+ pDSoundStrmOut->fRestartPlayback = true;
+ pDSoundStrmOut->fEnabled = true;
DSLOG(("DSound: Playback started\n"));
/*
- * The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlay,
+ * The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlayOut,
* because it is necessary to put some samples into the buffer first.
*/
}
@@ -885,28 +871,19 @@ static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSou
* DirectSoundCapture
*/
-static LPCGUID dsoundCaptureSelectDevice(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStream)
+static LPCGUID dsoundCaptureSelectDevice(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
{
AssertPtrReturn(pThis, NULL);
- AssertPtrReturn(pDSoundStream, NULL);
-
- int rc = VINF_SUCCESS;
+ AssertPtrReturn(pDSoundStrmIn, NULL);
LPCGUID pGUID = pThis->cfg.pGuidCapture;
+
if (!pGUID)
{
- PDSOUNDDEV pDev = NULL;
+ PDSOUNDDEV pDev = NULL;
- switch (pDSoundStream->enmRecSource)
+ switch (pDSoundStrmIn->enmRecSource)
{
- case PDMAUDIORECSOURCE_LINE:
- /*
- * At the moment we're only supporting line-in in the HDA emulation,
- * and line-in + mic-in in the AC'97 emulation both are expected
- * to use the host's mic-in as well.
- *
- * So the fall through here is intentional for now.
- */
case PDMAUDIORECSOURCE_MIC:
{
RTListForEach(&pThis->lstDevInput, pDev, DSOUNDDEV, Node)
@@ -914,79 +891,64 @@ static LPCGUID dsoundCaptureSelectDevice(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN p
if (RTStrIStr(pDev->pszName, "Mic")) /** @todo what is with non en_us windows versions? */
break;
}
-
if (RTListNodeIsDummy(&pThis->lstDevInput, pDev, DSOUNDDEV, Node))
- pDev = NULL; /* Found nothing. */
+ pDev = NULL; /* Found nothing. */
break;
}
+ case PDMAUDIORECSOURCE_LINE_IN:
default:
- AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
+ /* Try opening the default device (NULL). */
break;
}
- if ( RT_SUCCESS(rc)
- && pDev)
+ if (pDev)
{
- DSLOG(("DSound: Guest source '%s' is using host recording device '%s'\n",
- DrvAudioHlpRecSrcToStr(pDSoundStream->enmRecSource), pDev->pszName));
+ DSLOG(("DSound: Guest \"%s\" is using host \"%s\"\n",
+ drvAudioRecSourceToString(pDSoundStrmIn->enmRecSource), pDev->pszName));
pGUID = &pDev->Guid;
}
}
- if (RT_FAILURE(rc))
- {
- LogRel(("DSound: Selecting recording device failed with %Rrc\n", rc));
- return NULL;
- }
-
char *pszGUID = dsoundGUIDToUtf8StrA(pGUID);
-
/* This always has to be in the release log. */
- LogRel(("DSound: Guest source '%s' is using host recording device with GUID '%s'\n",
- DrvAudioHlpRecSrcToStr(pDSoundStream->enmRecSource), pszGUID ? pszGUID: "{?}"));
-
- if (pszGUID)
- {
- RTStrFree(pszGUID);
- pszGUID = NULL;
- }
+ LogRel(("DSound: Guest \"%s\" is using host device with GUID: %s\n",
+ drvAudioRecSourceToString(pDSoundStrmIn->enmRecSource), pszGUID? pszGUID: "{?}"));
+ RTStrFree(pszGUID);
return pGUID;
}
-
-static void directSoundCaptureInterfaceRelease(PDSOUNDSTREAMIN pDSoundStream)
+static void directSoundCaptureInterfaceRelease(PDSOUNDSTREAMIN pDSoundStrmIn)
{
- if (pDSoundStream->pDSC)
+ if (pDSoundStrmIn->pDSC)
{
LogFlowFuncEnter();
- IDirectSoundCapture_Release(pDSoundStream->pDSC);
- pDSoundStream->pDSC = NULL;
+ IDirectSoundCapture_Release(pDSoundStrmIn->pDSC);
+ pDSoundStrmIn->pDSC = NULL;
}
}
-
-static HRESULT directSoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStream)
+static HRESULT directSoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
{
- if (pDSoundStream->pDSC != NULL)
+ if (pDSoundStrmIn->pDSC != NULL)
{
DSLOG(("DSound: DirectSoundCapture instance already exists\n"));
return S_OK;
}
HRESULT hr = CoCreateInstance(CLSID_DirectSoundCapture8, NULL, CLSCTX_ALL,
- IID_IDirectSoundCapture8, (void **)&pDSoundStream->pDSC);
+ IID_IDirectSoundCapture8, (void **)&pDSoundStrmIn->pDSC);
if (FAILED(hr))
{
DSLOGREL(("DSound: Creating capture instance failed with %Rhrc\n", hr));
}
else
{
- LPCGUID pGUID = dsoundCaptureSelectDevice(pThis, pDSoundStream);
- hr = IDirectSoundCapture_Initialize(pDSoundStream->pDSC, pGUID);
+ LPCGUID pGUID = dsoundCaptureSelectDevice(pThis, pDSoundStrmIn);
+ hr = IDirectSoundCapture_Initialize(pDSoundStrmIn->pDSC, pGUID);
if (FAILED(hr))
{
if (hr == DSERR_NODRIVER) /* Usually means that no capture devices are attached. */
@@ -994,7 +956,7 @@ static HRESULT directSoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDST
else
DSLOGREL(("DSound: Initializing capturing device failed with %Rhrc\n", hr));
- directSoundCaptureInterfaceRelease(pDSoundStream);
+ directSoundCaptureInterfaceRelease(pDSoundStrmIn);
}
}
@@ -1002,61 +964,59 @@ static HRESULT directSoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDST
return hr;
}
-
-static HRESULT directSoundCaptureClose(PDSOUNDSTREAMIN pDSoundStream)
+static HRESULT directSoundCaptureClose(PDSOUNDSTREAMIN pDSoundStrmIn)
{
- AssertPtrReturn(pDSoundStream, E_POINTER);
+ AssertPtrReturn(pDSoundStrmIn, E_POINTER);
- DSLOG(("DSound: pDSoundStream=%p, pDSCB=%p\n", pDSoundStream, pDSoundStream->pDSCB));
+ DSLOG(("DSound: pDSoundStrmIn=%p, pDSCB=%p\n", pDSoundStrmIn, pDSoundStrmIn->pDSCB));
HRESULT hr = S_OK;
- if (pDSoundStream->pDSCB)
+ if (pDSoundStrmIn->pDSCB)
{
- hr = IDirectSoundCaptureBuffer_Stop(pDSoundStream->pDSCB);
+ hr = IDirectSoundCaptureBuffer_Stop(pDSoundStrmIn->pDSCB);
if (SUCCEEDED(hr))
{
- IDirectSoundCaptureBuffer8_Release(pDSoundStream->pDSCB);
- pDSoundStream->pDSCB = NULL;
+ IDirectSoundCaptureBuffer8_Release(pDSoundStrmIn->pDSCB);
+ pDSoundStrmIn->pDSCB = NULL;
}
else
DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
}
if (SUCCEEDED(hr))
- directSoundCaptureInterfaceRelease(pDSoundStream);
+ directSoundCaptureInterfaceRelease(pDSoundStrmIn);
LogFlowFunc(("Returning %Rhrc\n", hr));
return hr;
}
-
-static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStream)
+static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
{
AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStream, E_POINTER);
+ AssertPtrReturn(pDSoundStrmIn, E_POINTER);
- DSLOG(("DSound: pDSoundStream=%p, cbBufferIn=%RU32, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
- pDSoundStream,
+ DSLOG(("DSound: pDSoundStrmIn=%p, cbBufferIn=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
+ pDSoundStrmIn,
pThis->cfg.cbBufferIn,
- pDSoundStream->Props.uHz,
- pDSoundStream->Props.cChannels,
- pDSoundStream->Props.cBits,
- pDSoundStream->Props.fSigned));
+ pDSoundStrmIn->strmIn.Props.uHz,
+ pDSoundStrmIn->strmIn.Props.cChannels,
+ pDSoundStrmIn->strmIn.Props.cBits,
+ pDSoundStrmIn->strmIn.Props.fSigned));
- if (pDSoundStream->pDSCB != NULL)
+ if (pDSoundStrmIn->pDSCB != NULL)
{
/* Should not happen but be forgiving. */
DSLOGREL(("DSound: DirectSoundCaptureBuffer already exists\n"));
- directSoundCaptureClose(pDSoundStream);
+ directSoundCaptureClose(pDSoundStrmIn);
}
WAVEFORMATEX wfx;
- int rc = dsoundWaveFmtFromCfg(&pDSoundStream->streamCfg, &wfx);
+ int rc = dsoundWaveFmtFromCfg(&pDSoundStrmIn->streamCfg, &wfx);
if (RT_FAILURE(rc))
return E_INVALIDARG;
- HRESULT hr = directSoundCaptureInterfaceCreate(pThis, pDSoundStream);
+ HRESULT hr = directSoundCaptureInterfaceCreate(pThis, pDSoundStrmIn);
if (FAILED(hr))
return hr;
@@ -1068,7 +1028,7 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSo
bd.dwSize = sizeof(bd);
bd.lpwfxFormat = &wfx;
bd.dwBufferBytes = pThis->cfg.cbBufferIn;
- hr = IDirectSoundCapture_CreateCaptureBuffer(pDSoundStream->pDSC,
+ hr = IDirectSoundCapture_CreateCaptureBuffer(pDSoundStrmIn->pDSC,
&bd, &pDSCB, NULL);
if (FAILED(hr))
{
@@ -1081,7 +1041,7 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSo
break;
}
- hr = IDirectSoundCaptureBuffer_QueryInterface(pDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pDSoundStream->pDSCB);
+ hr = IDirectSoundCaptureBuffer_QueryInterface(pDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pDSoundStrmIn->pDSCB);
IDirectSoundCaptureBuffer_Release(pDSCB);
if (FAILED(hr))
{
@@ -1092,16 +1052,16 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSo
/*
* Query the actual parameters.
*/
- DWORD offByteReadPos = 0;
- hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pDSoundStream->pDSCB, NULL, &offByteReadPos);
+ DWORD cbReadPos = 0;
+ hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pDSoundStrmIn->pDSCB, NULL, &cbReadPos);
if (FAILED(hr))
{
- offByteReadPos = 0;
+ cbReadPos = 0;
DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
}
RT_ZERO(wfx);
- hr = IDirectSoundCaptureBuffer8_GetFormat(pDSoundStream->pDSCB, &wfx, sizeof(wfx), NULL);
+ hr = IDirectSoundCaptureBuffer8_GetFormat(pDSoundStrmIn->pDSCB, &wfx, sizeof(wfx), NULL);
if (FAILED(hr))
{
DSLOGREL(("DSound: Getting capture format failed with %Rhrc\n", hr));
@@ -1111,7 +1071,7 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSo
DSCBCAPS bc;
RT_ZERO(bc);
bc.dwSize = sizeof(bc);
- hr = IDirectSoundCaptureBuffer8_GetCaps(pDSoundStream->pDSCB, &bc);
+ hr = IDirectSoundCaptureBuffer8_GetCaps(pDSoundStrmIn->pDSCB, &bc);
if (FAILED(hr))
{
DSLOGREL(("Getting capture capabilities failed with %Rhrc\n", hr));
@@ -1138,46 +1098,45 @@ static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSo
wfx.wBitsPerSample,
wfx.cbSize));
- if (bc.dwBufferBytes & pDSoundStream->Props.uAlign)
+ if (bc.dwBufferBytes & pDSoundStrmIn->strmIn.Props.uAlign)
DSLOGREL(("DSound: Capture GetCaps returned misaligned buffer: size %RU32, alignment %RU32\n",
- bc.dwBufferBytes, pDSoundStream->Props.uAlign + 1));
+ bc.dwBufferBytes, pDSoundStrmIn->strmIn.Props.uAlign + 1));
if (bc.dwBufferBytes != pThis->cfg.cbBufferIn)
DSLOGREL(("DSound: Capture buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",
bc.dwBufferBytes, pThis->cfg.cbBufferIn));
/* Initial state: reading at the initial capture position, no error. */
- pDSoundStream->idxSampleCaptureReadPos = offByteReadPos >> pDSoundStream->Props.cShift;
- pDSoundStream->cMaxSamplesInBuffer = bc.dwBufferBytes >> pDSoundStream->Props.cShift;
- pDSoundStream->hrLastCapture = S_OK;
+ pDSoundStrmIn->csCaptureReadPos = cbReadPos >> pDSoundStrmIn->strmIn.Props.cShift;
+ pDSoundStrmIn->csCaptureBufferSize = bc.dwBufferBytes >> pDSoundStrmIn->strmIn.Props.cShift;
+ pDSoundStrmIn->hrLastCaptureIn = S_OK;
- DSLOG(("DSound: idxSampleCaptureReadPos=%RU32, cMaxSamplesInBuffer=%RU32\n",
- pDSoundStream->idxSampleCaptureReadPos, pDSoundStream->cMaxSamplesInBuffer));
+ DSLOG(("DSound: csCaptureReadPos=%RU32, csCaptureBufferSize=%RU32\n",
+ pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize));
} while (0);
if (FAILED(hr))
- directSoundCaptureClose(pDSoundStream);
+ directSoundCaptureClose(pDSoundStrmIn);
LogFlowFunc(("Returning %Rhrc\n", hr));
return hr;
}
-
-static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStream)
+static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
{
AssertPtrReturn(pThis , E_POINTER);
- AssertPtrReturn(pDSoundStream, E_POINTER);
+ AssertPtrReturn(pDSoundStrmIn, E_POINTER);
NOREF(pThis);
HRESULT hr;
- if (pDSoundStream->pDSCB)
+ if (pDSoundStrmIn->pDSCB)
{
DSLOG(("DSound: Stopping capture\n"));
- hr = IDirectSoundCaptureBuffer_Stop(pDSoundStream->pDSCB);
+ hr = IDirectSoundCaptureBuffer_Stop(pDSoundStrmIn->pDSCB);
if (FAILED(hr))
DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
}
@@ -1185,23 +1144,22 @@ static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSo
hr = E_UNEXPECTED;
if (SUCCEEDED(hr))
- pDSoundStream->fEnabled = false;
+ pDSoundStrmIn->fEnabled = false;
LogFlowFunc(("Returning %Rhrc\n", hr));
return hr;
}
-
-static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStream)
+static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pDSoundStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pDSoundStrmIn, VERR_INVALID_POINTER);
HRESULT hr;
- if (pDSoundStream->pDSCB != NULL)
+ if (pDSoundStrmIn->pDSCB != NULL)
{
DWORD dwStatus;
- hr = IDirectSoundCaptureBuffer8_GetStatus(pDSoundStream->pDSCB, &dwStatus);
+ hr = IDirectSoundCaptureBuffer8_GetStatus(pDSoundStrmIn->pDSCB, &dwStatus);
if (FAILED(hr))
{
DSLOGREL(("DSound: Retrieving capture status failed with %Rhrc\n", hr));
@@ -1219,7 +1177,7 @@ static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDS
fFlags |= DSCBSTART_LOOPING;
#endif
DSLOG(("DSound: Starting to capture\n"));
- hr = IDirectSoundCaptureBuffer8_Start(pDSoundStream->pDSCB, fFlags);
+ hr = IDirectSoundCaptureBuffer8_Start(pDSoundStrmIn->pDSCB, fFlags);
if (FAILED(hr))
DSLOGREL(("DSound: Starting to capture failed with %Rhrc\n", hr));
}
@@ -1229,26 +1187,26 @@ static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDS
hr = E_UNEXPECTED;
if (SUCCEEDED(hr))
- pDSoundStream->fEnabled = true;
+ pDSoundStrmIn->fEnabled = true;
LogFlowFunc(("Returning %Rhrc\n", hr));
return hr;
}
-
-static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID pGUID, LPCWSTR pwszDescription, PDSOUNDDEV *ppDev)
+static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID lpGUID,
+ LPCWSTR lpwstrDescription, PDSOUNDDEV *ppDev)
{
AssertPtrReturn(pList, VERR_INVALID_POINTER);
- AssertPtrReturn(pGUID, VERR_INVALID_POINTER);
- AssertPtrReturn(pwszDescription, VERR_INVALID_POINTER);
+ AssertPtrReturn(lpGUID, VERR_INVALID_POINTER);
+ AssertPtrReturn(lpwstrDescription, VERR_INVALID_POINTER);
PDSOUNDDEV pDev = (PDSOUNDDEV)RTMemAlloc(sizeof(DSOUNDDEV));
if (!pDev)
return VERR_NO_MEMORY;
- int rc = RTUtf16ToUtf8(pwszDescription, &pDev->pszName);
+ int rc = RTUtf16ToUtf8(lpwstrDescription, &pDev->pszName);
if (RT_SUCCESS(rc))
- memcpy(&pDev->Guid, pGUID, sizeof(GUID));
+ memcpy(&pDev->Guid, lpGUID, sizeof(GUID));
if (RT_SUCCESS(rc))
RTListAppend(pList, &pDev->Node);
@@ -1259,7 +1217,6 @@ static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID pGUID, LPCWSTR pwszDescripti
return rc;
}
-
static void dsoundDeviceRemove(PDSOUNDDEV pDev)
{
if (pDev)
@@ -1273,80 +1230,84 @@ static void dsoundDeviceRemove(PDSOUNDDEV pDev)
}
}
-
-static void dsoundLogDevice(const char *pszType, LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule)
+static void dsoundLogDevice(const char *pszType, LPGUID lpGUID, LPCWSTR lpwstrDescription, LPCWSTR lpwstrModule)
{
- char *pszGUID = dsoundGUIDToUtf8StrA(pGUID);
+ char *pszGUID = dsoundGUIDToUtf8StrA(lpGUID);
/* This always has to be in the release log. */
- LogRel(("DSound: %s: GUID: %s [%ls] (Module: %ls)\n", pszType, pszGUID ? pszGUID : "{?}", pwszDescription, pwszModule));
+ LogRel(("DSound: %s: GUID: %s [%ls] (Module: %ls)\n",
+ pszType, pszGUID? pszGUID: "{?}", lpwstrDescription, lpwstrModule));
RTStrFree(pszGUID);
}
-
-static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule, PVOID lpContext)
+static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
+ LPCWSTR lpwstrModule, LPVOID lpContext)
{
PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
AssertPtrReturn(pCtx, FALSE);
AssertPtrReturn(pCtx->pDrv, FALSE);
+ AssertPtrReturn(pCtx->pCfg, FALSE);
- if (!pGUID)
+ if (!lpGUID)
return TRUE;
- AssertPtrReturn(pwszDescription, FALSE);
- /* Do not care about pwszModule. */
+ AssertPtrReturn(lpwstrDescription, FALSE);
+ /* Do not care about lpwstrModule. */
if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
- dsoundLogDevice("Output", pGUID, pwszDescription, pwszModule);
+ dsoundLogDevice("Output", lpGUID, lpwstrDescription, lpwstrModule);
int rc = dsoundDevAdd(&pCtx->pDrv->lstDevOutput,
- pGUID, pwszDescription, NULL /* ppDev */);
+ lpGUID, lpwstrDescription, NULL /* ppDev */);
if (RT_FAILURE(rc))
return FALSE; /* Abort enumeration. */
- pCtx->cDevOut++;
+ pCtx->pCfg->cMaxHstStrmsOut++;
return TRUE;
}
-
-static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID pGUID, LPCWSTR pwszDescription, LPCWSTR pwszModule, PVOID lpContext)
+static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID lpGUID, LPCWSTR lpwstrDescription,
+ LPCWSTR lpwstrModule, LPVOID lpContext)
{
PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
AssertPtrReturn(pCtx, FALSE);
AssertPtrReturn(pCtx->pDrv, FALSE);
+ AssertPtrReturn(pCtx->pCfg, FALSE);
- if (!pGUID)
+ if (!lpGUID)
return TRUE;
if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
- dsoundLogDevice("Input", pGUID, pwszDescription, pwszModule);
+ dsoundLogDevice("Input", lpGUID, lpwstrDescription, lpwstrModule);
int rc = dsoundDevAdd(&pCtx->pDrv->lstDevInput,
- pGUID, pwszDescription, NULL /* ppDev */);
+ lpGUID, lpwstrDescription, NULL /* ppDev */);
if (RT_FAILURE(rc))
return FALSE; /* Abort enumeration. */
- pCtx->cDevIn++;
+ pCtx->pCfg->cMaxHstStrmsIn++;
return TRUE;
}
-
/**
* Does a (Re-)enumeration of the host's playback + capturing devices.
*
* @return IPRT status code.
* @param pThis Host audio driver instance.
- * @param pEnmCtx Enumeration context to use.
+ * @param pCfg Where to store the enumeration results.
* @param fEnum Enumeration flags.
*/
-static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PDSOUNDENUMCBCTX pEnmCtx, uint32_t fEnum)
+static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pEnmCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
dsoundDevicesClear(pThis);
+ pCfg->cMaxHstStrmsOut = 0;
+ pCfg->cMaxHstStrmsIn = 0;
+
RTLDRMOD hDSound = NULL;
int rc = RTLdrLoadSystem("dsound.dll", true /*fNoUnload*/, &hDSound);
if (RT_SUCCESS(rc))
@@ -1360,19 +1321,15 @@ static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PDSOUNDENUMCBCTX pEnmCtx
if (RT_SUCCESS(rc))
{
- HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, pEnmCtx);
+ DSOUNDENUMCBCTX ctx = { pThis, pCfg, fEnum };
+
+ HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, &ctx);
if (FAILED(hr))
LogRel2(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
- hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, pEnmCtx);
+ hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, &ctx);
if (FAILED(hr))
LogRel2(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
-
- if (fEnum & DSOUNDENUMCBFLAGS_LOG)
- {
- LogRel2(("DSound: Found %RU8 host playback devices\n", pEnmCtx->cDevOut));
- LogRel2(("DSound: Found %RU8 host capturing devices\n", pEnmCtx->cDevIn));
- }
}
RTLdrClose(hDSound);
@@ -1386,7 +1343,6 @@ static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PDSOUNDENUMCBCTX pEnmCtx
return rc;
}
-
/**
* Updates this host driver's internal status, according to the global, overall input/output
* state and all connected (native) audio streams.
@@ -1395,7 +1351,7 @@ static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PDSOUNDENUMCBCTX pEnmCtx
* @param pCfg Where to store the backend configuration. Optional.
* @param fEnum Enumeration flags.
*/
-static void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
+void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
{
AssertPtrReturnVoid(pThis);
/* pCfg is optional. */
@@ -1403,80 +1359,92 @@ static void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDC
PDMAUDIOBACKENDCFG Cfg;
RT_ZERO(Cfg);
- Cfg.cbStreamOut = sizeof(DSOUNDSTREAMOUT);
- Cfg.cbStreamIn = sizeof(DSOUNDSTREAMIN);
+ Cfg.cbStreamOut = sizeof(DSOUNDSTREAMOUT);
+ Cfg.cbStreamIn = sizeof(DSOUNDSTREAMIN);
- DSOUNDENUMCBCTX cbCtx = { pThis, fEnum, 0, 0 };
+ int rc = dsoundDevicesEnumerate(pThis, &Cfg, fEnum);
+ AssertRC(rc);
- int rc = dsoundDevicesEnumerate(pThis, &cbCtx, fEnum);
- if (RT_SUCCESS(rc))
- {
#ifdef VBOX_WITH_AUDIO_CALLBACKS
- if ( pThis->fEnabledOut != RT_BOOL(cbCtx.cDevOut)
- || pThis->fEnabledIn != RT_BOOL(cbCtx.cDevIn))
- {
- /** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
- * let the connector know that something has changed within the host backend. */
- }
+ if ( pThis->fEnabledOut != RT_BOOL(Cfg.cMaxHstStrmsOut)
+ || pThis->fEnabledIn != RT_BOOL(Cfg.cMaxHstStrmsIn))
+ {
+ /** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
+ * let the connector know that something has changed within the host backend. */
+ }
#else
- pThis->fEnabledOut = RT_BOOL(cbCtx.cDevOut);
- pThis->fEnabledIn = RT_BOOL(cbCtx.cDevIn);
+ pThis->fEnabledOut = RT_BOOL(Cfg.cMaxHstStrmsOut);
+ pThis->fEnabledIn = RT_BOOL(Cfg.cMaxHstStrmsIn);
#endif
- Cfg.cSources = cbCtx.cDevIn;
- Cfg.cSinks = cbCtx.cDevOut;
- Cfg.cMaxStreamsIn = UINT32_MAX;
- Cfg.cMaxStreamsOut = UINT32_MAX;
-
- if (pCfg)
- memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
- }
+ if (pCfg)
+ memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
LogFlowFuncLeaveRC(rc);
}
-
-static void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
+void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
{
dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, 0 /* fEnum */);
}
+/*
+ * PDMIHOSTAUDIO
+ */
-static int dsoundCreateStreamOut(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostDSoundInitOut(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ uint32_t *pcSamples)
{
- LogFlowFunc(("pStream=%p, pCfg=%p\n", pStream, pCfgReq));
- PDSOUNDSTREAMOUT pDSoundStream = (PDSOUNDSTREAMOUT)pStream;
+ RT_NOREF(pCfgReq, pCfgAcq);
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+ /* pcSamples is optional. */
+
+ LogFlowFunc(("pHstStrmOut=%p, pCfg=%p\n", pHstStrmOut, pCfgReq));
- pDSoundStream->streamCfg = *pCfgReq;
- pDSoundStream->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+ PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+ PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
- int rc = DrvAudioHlpStreamCfgToProps(&pDSoundStream->streamCfg, &pDSoundStream->Props);
+ pDSoundStrmOut->streamCfg = *pCfgReq;
+ pDSoundStrmOut->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+ int rc = DrvAudioStreamCfgToProps(&pDSoundStrmOut->streamCfg, &pDSoundStrmOut->strmOut.Props);
if (RT_SUCCESS(rc))
{
- pDSoundStream->pDS = NULL;
- pDSoundStream->pDSB = NULL;
- pDSoundStream->offPlayWritePos = 0;
- pDSoundStream->fRestartPlayback = true;
- pDSoundStream->cMaxSamplesInBuffer = 0;
+ pDSoundStrmOut->pDS = NULL;
+ pDSoundStrmOut->pDSB = NULL;
+ pDSoundStrmOut->cbPlayWritePos = 0;
+ pDSoundStrmOut->fRestartPlayback = true;
+ pDSoundStrmOut->csPlaybackBufferSize = 0;
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = pThis->cfg.cbBufferOut >> pDSoundStream->Props.cShift;
+ if (pcSamples)
+ *pcSamples = pThis->cfg.cbBufferOut >> pHstStrmOut->Props.cShift;
/* Try to open playback in case the device is already there. */
- directSoundPlayOpen(pThis, pDSoundStream);
+ directSoundPlayOpen(pThis, pDSoundStrmOut);
}
else
- RT_ZERO(pDSoundStream->streamCfg);
+ {
+ RT_ZERO(pDSoundStrmOut->streamCfg);
+ }
LogFlowFuncLeaveRC(rc);
return rc;
}
-static int dsoundControlStreamOut(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostDSoundControlOut(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
{
- LogFlowFunc(("pStream=%p, cmd=%d\n", pStream, enmStreamCmd));
- PDSOUNDSTREAMOUT pDSoundStream = (PDSOUNDSTREAMOUT)pStream;
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+ LogFlowFunc(("pHstStrmOut=%p, cmd=%d\n", pHstStrmOut, enmStreamCmd));
+
+ PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+ PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
int rc = VINF_SUCCESS;
@@ -1488,14 +1456,14 @@ static int dsoundControlStreamOut(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream,
{
DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_ENABLE\n"));
/* Try to start playback. If it fails, then reopen and try again. */
- hr = directSoundPlayStart(pThis, pDSoundStream);
+ hr = directSoundPlayStart(pThis, pDSoundStrmOut);
if (FAILED(hr))
{
- hr = directSoundPlayClose(pThis, pDSoundStream);
+ hr = directSoundPlayClose(pThis, pDSoundStrmOut);
if (SUCCEEDED(hr))
- hr = directSoundPlayOpen(pThis, pDSoundStream);
+ hr = directSoundPlayOpen(pThis, pDSoundStrmOut);
if (SUCCEEDED(hr))
- hr = directSoundPlayStart(pThis, pDSoundStream);
+ hr = directSoundPlayStart(pThis, pDSoundStrmOut);
}
if (FAILED(hr))
@@ -1507,7 +1475,7 @@ static int dsoundControlStreamOut(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream,
case PDMAUDIOSTREAMCMD_PAUSE:
{
DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_DISABLE\n"));
- hr = directSoundPlayStop(pThis, pDSoundStream);
+ hr = directSoundPlayStop(pThis, pDSoundStrmOut);
if (FAILED(hr))
rc = VERR_NOT_SUPPORTED;
break;
@@ -1525,20 +1493,15 @@ static int dsoundControlStreamOut(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream,
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
- */
-int drvHostDSoundStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+static DECLCALLBACK(int) drvHostDSoundPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ uint32_t *pcSamplesPlayed)
{
- RT_NOREF2(pvBuf, cbBuf);
-
AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbRead is optional. */
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ /* pcSamplesPlayed is optional. */
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- PDSOUNDSTREAMOUT pDSoundStream = (PDSOUNDSTREAMOUT)pStream;
+ PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+ PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
int rc = VINF_SUCCESS;
uint32_t cReadTotal = 0;
@@ -1550,38 +1513,39 @@ int drvHostDSoundStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
do /* to use 'break' */
{
DWORD cbBuffer, cbFree, cbPlayPos;
- rc = dsoundGetPosOut(pThis, pDSoundStream, &cbBuffer, &cbFree, &cbPlayPos);
+ rc = dsoundGetPosOut(pThis, pDSoundStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
if (RT_FAILURE(rc))
break;
/*
- * Check for full buffer, do not allow the offPlayWritePos to catch cbPlayPos during playback,
+ * Check for full buffer, do not allow the cbPlayWritePos to catch cbPlayPos during playback,
* i.e. always leave a free space for 1 audio sample.
*/
- const DWORD cbSample = AUDIOMIXBUF_S2B(&pStream->MixBuf, 1);
+ const DWORD cbSample = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, 1);
if (cbFree <= cbSample)
break;
cbFree -= cbSample;
- uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
- uint32_t cbLive = AUDIOMIXBUF_S2B(&pStream->MixBuf, cLive);
+ uint32_t csLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+ uint32_t cbLive = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, csLive);
/* Do not write more than available space in the DirectSound playback buffer. */
cbLive = RT_MIN(cbFree, cbLive);
- cbLive &= ~pDSoundStream->Props.uAlign;
+
+ cbLive &= ~pHstStrmOut->Props.uAlign;
if (cbLive == 0 || cbLive > cbBuffer)
{
- DSLOG(("DSound: cbLive=%RU32, cbBuffer=%ld, offPlayWritePos=%ld, cbPlayPos=%ld\n",
- cbLive, cbBuffer, pDSoundStream->offPlayWritePos, cbPlayPos));
+ DSLOG(("DSound: cbLive=%RU32, cbBuffer=%ld, cbPlayWritePos=%ld, cbPlayPos=%ld\n",
+ cbLive, cbBuffer, pDSoundStrmOut->cbPlayWritePos, cbPlayPos));
break;
}
- LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStream->pDSB;
+ LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStrmOut->pDSB;
AssertPtr(pDSB);
- PVOID pv1, pv2;
+ LPVOID pv1, pv2;
DWORD cb1, cb2;
- HRESULT hr = directSoundPlayLock(pThis, pDSB, &pDSoundStream->Props, pDSoundStream->offPlayWritePos, cbLive,
+ HRESULT hr = directSoundPlayLock(pThis, pDSB, &pHstStrmOut->Props, pDSoundStrmOut->cbPlayWritePos, cbLive,
&pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
if (FAILED(hr))
{
@@ -1589,55 +1553,54 @@ int drvHostDSoundStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
break;
}
- /** @todo r=bird: Can pv1/cb1 really be NULL? Docs says they're always set
- * and pv2/cb2 only used when there is a buffer wrap araound. */
+ DWORD len1 = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cb1);
+ /*DWORD len2 = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cb2);*/
- DWORD cSamplesIn1 = AUDIOMIXBUF_B2S(&pStream->MixBuf, cb1);
uint32_t cRead = 0;
if (pv1 && cb1)
{
- rc = AudioMixBufReadCirc(&pStream->MixBuf, pv1, cb1, &cRead);
+ rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pv1, cb1, &cRead);
if (RT_SUCCESS(rc))
cReadTotal += cRead;
}
if ( RT_SUCCESS(rc)
- && cReadTotal == cSamplesIn1
+ && cReadTotal == len1
&& pv2 && cb2)
{
- rc = AudioMixBufReadCirc(&pStream->MixBuf, pv2, cb2, &cRead);
+ rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pv2, cb2, &cRead);
if (RT_SUCCESS(rc))
cReadTotal += cRead;
}
directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
- pDSoundStream->offPlayWritePos = (pDSoundStream->offPlayWritePos + AUDIOMIXBUF_S2B(&pStream->MixBuf, cReadTotal))
- % cbBuffer;
+ pDSoundStrmOut->cbPlayWritePos =
+ (pDSoundStrmOut->cbPlayWritePos + AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal)) % cbBuffer;
DSLOGF(("DSound: %RU32 (%RU32 samples) out of %RU32%s, buffer write pos %ld, rc=%Rrc\n",
- AUDIOMIXBUF_S2B(&pStream->MixBuf, cReadTotal), cReadTotal, cbLive,
- cbLive != AUDIOMIXBUF_S2B(&pStream->MixBuf, cReadTotal) ? " !!!": "",
- pDSoundStream->offPlayWritePos, rc));
+ AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal), cReadTotal, cbLive,
+ cbLive != AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal) ? " !!!": "",
+ pDSoundStrmOut->cbPlayWritePos, rc));
if (cReadTotal)
{
- AudioMixBufFinish(&pStream->MixBuf, cReadTotal);
+ AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
rc = VINF_SUCCESS; /* Played something. */
}
if (RT_FAILURE(rc))
break;
- if (pDSoundStream->fRestartPlayback)
+ if (pDSoundStrmOut->fRestartPlayback)
{
/*
* The playback has been just started.
* Some samples of the new sound have been copied to the buffer
* and it can start playing.
*/
- pDSoundStream->fRestartPlayback = false;
+ pDSoundStrmOut->fRestartPlayback = false;
DWORD fFlags = 0;
#ifndef VBOX_WITH_AUDIO_CALLBACKS
@@ -1645,14 +1608,14 @@ int drvHostDSoundStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
#endif
for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
{
- hr = IDirectSoundBuffer8_Play(pDSoundStream->pDSB, 0, 0, fFlags);
+ hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, fFlags);
if ( SUCCEEDED(hr)
|| hr != DSERR_BUFFERLOST)
break;
else
{
LogFlowFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
- directSoundPlayRestore(pThis, pDSoundStream->pDSB);
+ directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
}
}
@@ -1667,70 +1630,92 @@ int drvHostDSoundStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
} while (0);
if (RT_FAILURE(rc))
+ {
dsoundUpdateStatusInternal(pThis);
- else if (pcbWritten)
- *pcbWritten = cReadTotal;
+ }
+ else
+ {
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = cReadTotal;
+ }
LogFlowFuncLeaveRC(rc);
return rc;
}
-
-static int dsoundDestroyStreamOut(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostDSoundFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
- PDSOUNDSTREAMOUT pDSoundStream = (PDSOUNDSTREAMOUT)pStream;
+ PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+ PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
- directSoundPlayClose(pThis, pDSoundStream);
+ directSoundPlayClose(pThis, pDSoundStrmOut);
- pDSoundStream->offPlayWritePos = 0;
- pDSoundStream->fRestartPlayback = true;
- pDSoundStream->cMaxSamplesInBuffer = 0;
+ pDSoundStrmOut->cbPlayWritePos = 0;
+ pDSoundStrmOut->fRestartPlayback = true;
+ pDSoundStrmOut->csPlaybackBufferSize = 0;
- RT_ZERO(pDSoundStream->streamCfg);
+ RT_ZERO(pDSoundStrmOut->streamCfg);
return VINF_SUCCESS;
}
-static int dsoundCreateStreamIn(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostDSoundInitIn(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
{
- PDSOUNDSTREAMIN pDSoundStream = (PDSOUNDSTREAMIN)pStream;
+ RT_NOREF(pCfgAcq);
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+ /* pcSamples is optional. */
- LogFlowFunc(("pStream=%p, pCfg=%p, enmRecSource=%ld\n", pStream, pCfgReq, pCfgReq->DestSource.Source));
+ PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+ PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
+
+ LogFlowFunc(("pHstStrmIn=%p, pCfgReq=%p, enmRecSource=%ld\n",
+ pHstStrmIn, pCfgReq, enmRecSource));
- memcpy(&pDSoundStream->streamCfg, pCfgReq, sizeof(PDMAUDIOSTREAMCFG));
+ pDSoundStrmIn->streamCfg = *pCfgReq;
+ pDSoundStrmIn->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
/** @todo caller should already init Props? */
- int rc = DrvAudioHlpStreamCfgToProps(&pDSoundStream->streamCfg, &pDSoundStream->Props);
+ int rc = DrvAudioStreamCfgToProps(&pDSoundStrmIn->streamCfg, &pHstStrmIn->Props);
if (RT_SUCCESS(rc))
{
/* Init the stream structure and save relevant information to it. */
- pDSoundStream->idxSampleCaptureReadPos = 0;
- pDSoundStream->cMaxSamplesInBuffer = 0;
- pDSoundStream->pDSC = NULL;
- pDSoundStream->pDSCB = NULL;
- pDSoundStream->enmRecSource = pCfgReq->DestSource.Source;
- pDSoundStream->hrLastCapture = S_OK;
+ pDSoundStrmIn->csCaptureReadPos = 0;
+ pDSoundStrmIn->csCaptureBufferSize = 0;
+ pDSoundStrmIn->pDSC = NULL;
+ pDSoundStrmIn->pDSCB = NULL;
+ pDSoundStrmIn->enmRecSource = enmRecSource;
+ pDSoundStrmIn->hrLastCaptureIn = S_OK;
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = pThis->cfg.cbBufferIn >> pDSoundStream->Props.cShift;
+ if (pcSamples)
+ *pcSamples = pThis->cfg.cbBufferIn >> pHstStrmIn->Props.cShift;
/* Try to open capture in case the device is already there. */
- directSoundCaptureOpen(pThis, pDSoundStream); /** @todo r=andy Why not checking the result here?? */
+ directSoundCaptureOpen(pThis, pDSoundStrmIn);
}
else
{
- RT_ZERO(pDSoundStream->streamCfg);
+ RT_ZERO(pDSoundStrmIn->streamCfg);
}
LogFlowFuncLeaveRC(rc);
return rc;
}
-static int dsoundControlStreamIn(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostDSoundControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
- LogFlowFunc(("pStream=%p, enmStreamCmd=%ld\n", pStream, enmStreamCmd));
- PDSOUNDSTREAMIN pDSoundStream = (PDSOUNDSTREAMIN)pStream;
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+ LogFlowFunc(("pHstStrmIn=%p, enmStreamCmd=%ld\n", pHstStrmIn, enmStreamCmd));
+
+ PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+ PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
int rc = VINF_SUCCESS;
@@ -1741,15 +1726,15 @@ static int dsoundControlStreamIn(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream,
case PDMAUDIOSTREAMCMD_RESUME:
{
/* Try to start capture. If it fails, then reopen and try again. */
- hr = directSoundCaptureStart(pThis, pDSoundStream);
+ hr = directSoundCaptureStart(pThis, pDSoundStrmIn);
if (FAILED(hr))
{
- hr = directSoundCaptureClose(pDSoundStream);
+ hr = directSoundCaptureClose(pDSoundStrmIn);
if (SUCCEEDED(hr))
{
- hr = directSoundCaptureOpen(pThis, pDSoundStream);
+ hr = directSoundCaptureOpen(pThis, pDSoundStrmIn);
if (SUCCEEDED(hr))
- hr = directSoundCaptureStart(pThis, pDSoundStream);
+ hr = directSoundCaptureStart(pThis, pDSoundStrmIn);
}
}
@@ -1761,7 +1746,7 @@ static int dsoundControlStreamIn(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream,
case PDMAUDIOSTREAMCMD_DISABLE:
case PDMAUDIOSTREAMCMD_PAUSE:
{
- hr = directSoundCaptureStop(pThis, pDSoundStream);
+ hr = directSoundCaptureStop(pThis, pDSoundStrmIn);
if (FAILED(hr))
rc = VERR_NOT_SUPPORTED;
break;
@@ -1778,22 +1763,17 @@ static int dsoundControlStreamIn(PDRVHOSTDSOUND pThis, PPDMAUDIOSTREAM pStream,
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
- */
-int drvHostDSoundStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static DECLCALLBACK(int) drvHostDSoundCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ uint32_t *pcSamplesCaptured)
{
- RT_NOREF2(pvBuf, cbBuf);
-
PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- PDSOUNDSTREAMIN pDSoundStream = (PDSOUNDSTREAMIN)pStream;
- LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pDSoundStream->pDSCB;
+ PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
+ LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pDSoundStrmIn->pDSCB;
int rc = VINF_SUCCESS;
- uint32_t cSamplesProcessed = 0;
+ uint32_t cCaptured = 0;
do
{
@@ -1804,54 +1784,56 @@ int drvHostDSoundStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStrea
}
/* Get DirectSound capture position in bytes. */
- DWORD offByteReadPos;
- HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &offByteReadPos);
+ DWORD cbReadPos;
+ HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &cbReadPos);
if (FAILED(hr))
{
- if (hr != pDSoundStream->hrLastCapture)
+ if (hr != pDSoundStrmIn->hrLastCaptureIn)
{
DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
- pDSoundStream->hrLastCapture = hr;
+ pDSoundStrmIn->hrLastCaptureIn = hr;
}
rc = VERR_NOT_AVAILABLE;
break;
}
- pDSoundStream->hrLastCapture = hr;
+ pDSoundStrmIn->hrLastCaptureIn = hr;
- if (offByteReadPos & pDSoundStream->Props.uAlign)
- DSLOGF(("DSound: Misaligned capture read position %ld (alignment: %RU32)\n", offByteReadPos, pDSoundStream->Props.uAlign));
+ if (cbReadPos & pHstStrmIn->Props.uAlign)
+ DSLOGF(("DSound: Misaligned capture read position %ld (alignment: %RU32)\n", cbReadPos, pHstStrmIn->Props.uAlign));
/* Capture position in samples. */
- DWORD idxSampleReadPos = offByteReadPos >> pDSoundStream->Props.cShift;
+ DWORD csReadPos = cbReadPos >> pHstStrmIn->Props.cShift;
/* Number of samples available in the DirectSound capture buffer. */
- DWORD cSamplesToCapture = dsoundRingDistance(idxSampleReadPos, pDSoundStream->idxSampleCaptureReadPos,
- pDSoundStream->cMaxSamplesInBuffer);
- if (cSamplesToCapture == 0)
+ DWORD csCaptured = dsoundRingDistance(csReadPos, pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize);
+ if (csCaptured == 0)
break;
+ /* Using as an intermediate not circular buffer. */
+ AudioMixBufReset(&pHstStrmIn->MixBuf);
+
/* Get number of free samples in the mix buffer and check that is has free space */
- uint32_t cFreeMixSamples = AudioMixBufFree(&pStream->MixBuf);
- if (cFreeMixSamples == 0)
+ uint32_t csMixFree = AudioMixBufFree(&pHstStrmIn->MixBuf);
+ if (csMixFree == 0)
{
DSLOGF(("DSound: Capture buffer full\n"));
break;
}
- DSLOGF(("DSound: Capture cFreeMixSamples=%RU32, idxSampleReadPos=%u, idxSampleCaptureReadPos=%u, cSamplesToCapture=%u\n",
- cFreeMixSamples, idxSampleReadPos, pDSoundStream->idxSampleCaptureReadPos, cSamplesToCapture));
+ DSLOGF(("DSound: Capture csMixFree=%RU32, csReadPos=%ld, csCaptureReadPos=%ld, csCaptured=%ld\n",
+ csMixFree, csReadPos, pDSoundStrmIn->csCaptureReadPos, csCaptured));
/* No need to fetch more samples than mix buffer can receive. */
- cSamplesToCapture = RT_MIN(cSamplesToCapture, cFreeMixSamples);
+ csCaptured = RT_MIN(csCaptured, csMixFree);
/* Lock relevant range in the DirectSound capture buffer. */
- PVOID pv1, pv2;
+ LPVOID pv1, pv2;
DWORD cb1, cb2;
- hr = directSoundCaptureLock(pDSCB, &pDSoundStream->Props,
- AUDIOMIXBUF_S2B(&pStream->MixBuf, pDSoundStream->idxSampleCaptureReadPos), /* dwOffset */
- AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesToCapture), /* dwBytes */
+ hr = directSoundCaptureLock(pDSCB, &pHstStrmIn->Props,
+ AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, pDSoundStrmIn->csCaptureReadPos), /* dwOffset */
+ AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, csCaptured), /* dwBytes */
&pv1, &pv2, &cb1, &cb2,
0 /* dwFlags */);
if (FAILED(hr))
@@ -1860,82 +1842,97 @@ int drvHostDSoundStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStrea
break;
}
- DWORD len1 = AUDIOMIXBUF_B2S(&pStream->MixBuf, cb1);
- DWORD len2 = AUDIOMIXBUF_B2S(&pStream->MixBuf, cb2);
+ DWORD len1 = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cb1);
+ DWORD len2 = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cb2);
- uint32_t cSamplesWrittenTotal = 0;
- uint32_t cSamplesWritten;
+ uint32_t csWrittenTotal = 0;
+ uint32_t csWritten;
if (pv1 && len1)
{
- rc = AudioMixBufWriteCirc(&pStream->MixBuf, pv1, cb1, &cSamplesWritten);
+ rc = AudioMixBufWriteAt(&pHstStrmIn->MixBuf, 0 /* offWrite */,
+ pv1, cb1, &csWritten);
if (RT_SUCCESS(rc))
- cSamplesWrittenTotal += cSamplesWritten;
+ csWrittenTotal += csWritten;
}
if ( RT_SUCCESS(rc)
- && cSamplesWrittenTotal == len1
+ && csWrittenTotal == len1
&& pv2 && len2)
{
- rc = AudioMixBufWriteCirc(&pStream->MixBuf, pv2, cb2, &cSamplesWritten);
+ rc = AudioMixBufWriteAt(&pHstStrmIn->MixBuf, csWrittenTotal,
+ pv2, cb2, &csWritten);
if (RT_SUCCESS(rc))
- cSamplesWrittenTotal += cSamplesWritten;
+ csWrittenTotal += csWritten;
}
directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);
- if (cSamplesWrittenTotal) /* Captured something? */
- rc = AudioMixBufMixToParent(&pStream->MixBuf, cSamplesWrittenTotal, &cSamplesProcessed);
+ if (csWrittenTotal) /* Captured something? */
+ rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, csWrittenTotal, &cCaptured);
if (RT_SUCCESS(rc))
{
- pDSoundStream->idxSampleCaptureReadPos = (pDSoundStream->idxSampleCaptureReadPos + cSamplesProcessed)
- % pDSoundStream->cMaxSamplesInBuffer;
- DSLOGF(("DSound: Capture %u (%u+%u), processed %RU32/%RU32\n",
- cSamplesToCapture, len1, len2, cSamplesProcessed, cSamplesWrittenTotal));
+ pDSoundStrmIn->csCaptureReadPos = (pDSoundStrmIn->csCaptureReadPos + cCaptured) % pDSoundStrmIn->csCaptureBufferSize;
+ DSLOGF(("DSound: Capture %ld (%ld+%ld), processed %RU32/%RU32\n",
+ csCaptured, len1, len2, cCaptured, csWrittenTotal));
}
} while (0);
if (RT_FAILURE(rc))
+ {
dsoundUpdateStatusInternal(pThis);
- else if (pcbRead)
- *pcbRead = cSamplesProcessed;
+ }
+ else
+ {
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = cCaptured;
+ }
LogFlowFuncLeaveRC(rc);
return rc;
}
-static int dsoundDestroyStreamIn(PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostDSoundFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
- PDSOUNDSTREAMIN pDSoundStream = (PDSOUNDSTREAMIN)pStream;
+ RT_NOREF(pInterface);
+ PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
- directSoundCaptureClose(pDSoundStream);
+ directSoundCaptureClose(pDSoundStrmIn);
- pDSoundStream->idxSampleCaptureReadPos = 0;
- pDSoundStream->cMaxSamplesInBuffer = 0;
- RT_ZERO(pDSoundStream->streamCfg);
+ pDSoundStrmIn->csCaptureReadPos = 0;
+ pDSoundStrmIn->csCaptureBufferSize = 0;
+ RT_ZERO(pDSoundStrmIn->streamCfg);
return VINF_SUCCESS;
}
+/** @todo Replace PDMAUDIODIR with a (registered? unique) channel ID to provide multi-channel input/output. */
+static DECLCALLBACK(bool) drvHostDSoundIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+ AssertPtrReturn(pInterface, false);
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
- */
-int drvHostDSoundGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
+ PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+
+ if (enmDir == PDMAUDIODIR_IN)
+ return pThis->fEnabledIn;
+
+ return pThis->fEnabledOut;
+}
+
+static DECLCALLBACK(int) drvHostDSoundGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- dsoundUpdateStatusInternalEx(pThis, pBackendCfg, 0 /* fEnum */);
+ dsoundUpdateStatusInternalEx(pThis, pCfg, 0 /* fEnum */);
return VINF_SUCCESS;
}
#ifdef VBOX_WITH_AUDIO_CALLBACKS
-
static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
@@ -1953,8 +1950,7 @@ static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown)
return VINF_SUCCESS;
}
-
-static DECLCALLBACK(int) dsoundNotificationThread(RTTHREAD hThreadSelf, void *pvUser)
+static DECLCALLBACK(int) drvHostDSoundThread(RTTHREAD hThreadSelf, void *pvUser)
{
PDRVHOSTDSOUND pThis = (PDRVHOSTDSOUND)pvUser;
AssertPtr(pThis);
@@ -2007,7 +2003,7 @@ static DECLCALLBACK(int) dsoundNotificationThread(RTTHREAD hThreadSelf, void *pv
else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_OUTPUT])
{
DWORD cbBuffer, cbFree, cbPlayPos;
- rc = dsoundGetPosOut(pThis->pDSStream, &cbBuffer, &cbFree, &cbPlayPos);
+ rc = dsoundGetPosOut(pThis->pDSStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
if ( RT_SUCCESS(rc)
&& cbFree)
{
@@ -2042,14 +2038,9 @@ static DECLCALLBACK(int) dsoundNotificationThread(RTTHREAD hThreadSelf, void *pv
LogFlowFunc(("Exited with fShutdown=%RTbool, rc=%Rrc\n", pThis->fShutdown, rc));
return rc;
}
-
#endif /* VBOX_WITH_AUDIO_CALLBACKS */
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
- */
-void drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
+static DECLCALLBACK(void) drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
{
PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
@@ -2071,26 +2062,24 @@ void drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
pThis->aEvents[DSOUNDEVENT_NOTIFY] = NULL;
}
#else
- RT_NOREF_PV(pThis);
+ RT_NOREF(pThis);
#endif
LogFlowFuncLeave();
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
- */
static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
{
PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
+
LogFlowFuncEnter();
int rc;
/* Verify that IDirectSound is available. */
LPDIRECTSOUND pDirectSound = NULL;
- HRESULT hr = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_ALL, IID_IDirectSound, (void **)&pDirectSound);
+ HRESULT hr = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_ALL,
+ IID_IDirectSound, (void **)&pDirectSound);
if (SUCCEEDED(hr))
{
IDirectSound_Release(pDirectSound);
@@ -2103,9 +2092,9 @@ static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
Assert(pThis->aEvents[DSOUNDEVENT_NOTIFY] != NULL);
/* Start notification thread. */
- rc = RTThreadCreate(&pThis->Thread, dsoundNotificationThread,
+ rc = RTThreadCreate(&pThis->Thread, drvHostDSoundThread,
pThis /*pvUser*/, 0 /*cbStack*/,
- RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "dsoundNtfy");
+ RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "dSoundNtfy");
if (RT_SUCCESS(rc))
{
/* Wait for the thread to initialize. */
@@ -2119,7 +2108,11 @@ static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
rc = VINF_SUCCESS;
#endif
- dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
+ PDMAUDIOBACKENDCFG Cfg;
+ dsoundUpdateStatusInternalEx(pThis, &Cfg, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
+
+ DSLOGREL(("DSound: Found %RU32 host playback devices\n", Cfg.cMaxHstStrmsOut));
+ DSLOGREL(("DSound: Found %RU32 host capturing devices\n", Cfg.cMaxHstStrmsIn));
}
else
{
@@ -2131,6 +2124,15 @@ static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
return rc;
}
+static DECLCALLBACK(void *) drvHostDSoundQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
+
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+ return NULL;
+}
static LPCGUID dsoundConfigQueryGUID(PCFGMNODE pCfg, const char *pszName, RTUUID *pUuid)
{
@@ -2152,8 +2154,7 @@ static LPCGUID dsoundConfigQueryGUID(PCFGMNODE pCfg, const char *pszName, RTUUID
return pGuid;
}
-
-static void dsoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg)
+static void dSoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg)
{
unsigned int uBufsizeOut, uBufsizeIn;
@@ -2172,162 +2173,6 @@ static void dsoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg)
&pThis->cfg.uuidCapture));
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDSoundGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- RT_NOREF(enmDir);
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
-
- return PDMAUDIOBACKENDSTS_RUNNING;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvHostDSoundStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- int rc;
- if (pCfgReq->enmDir == PDMAUDIODIR_IN)
- rc = dsoundCreateStreamIn(pThis, pStream, pCfgReq, pCfgAcq);
- else
- rc = dsoundCreateStreamOut(pThis, pStream, pCfgReq, pCfgAcq);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvHostDSoundStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = dsoundDestroyStreamIn(pStream);
- else
- rc = dsoundDestroyStreamOut(pThis, pStream);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
- */
-static DECLCALLBACK(int) drvHostDSoundStreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = dsoundControlStreamIn(pThis, pStream, enmStreamCmd);
- else
- rc = dsoundControlStreamOut(pThis, pStream, enmStreamCmd);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostDSoundStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, PDMAUDIOSTRMSTS_FLAG_NONE);
- AssertPtrReturn(pStream, PDMAUDIOSTRMSTS_FLAG_NONE);
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- PDMAUDIOSTRMSTS strmSts = PDMAUDIOSTRMSTS_FLAG_INITIALIZED;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- {
- PDSOUNDSTREAMIN pDSoundStream = (PDSOUNDSTREAMIN)pStream;
- if (pDSoundStream->fEnabled)
- strmSts |= PDMAUDIOSTRMSTS_FLAG_ENABLED | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE;
- }
- else
- {
- PDSOUNDSTREAMOUT pDSoundStream = (PDSOUNDSTREAMOUT)pStream;
- if (pDSoundStream->fEnabled)
- {
- strmSts |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
-
- DWORD cbFree;
- int rc = dsoundGetPosOut(pThis, pDSoundStream, NULL /* cbBuffer */, &cbFree, NULL /* cbPlayPos */);
- if ( RT_SUCCESS(rc)
- && cbFree)
- {
- LogFlowFunc(("cbFree=%ld\n", cbFree));
- strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
- }
- }
- }
-
- return strmSts;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
- */
-static DECLCALLBACK(int) drvHostDSoundStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
-
- /* Nothing to do here for DSound. */
- return VINF_SUCCESS;
-}
-
-
-/*********************************************************************************************************************************
-* PDMDRVINS::IBase Interface *
-*********************************************************************************************************************************/
-
-/**
- * @callback_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvHostDSoundQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
- return NULL;
-}
-
-
-/*********************************************************************************************************************************
-* PDMDRVREG Interface *
-*********************************************************************************************************************************/
-
-/**
- * @callback_method_impl{FNPDMDRVDESTRUCT, pfnDestruct}
- */
static DECLCALLBACK(void) drvHostDSoundDestruct(PPDMDRVINS pDrvIns)
{
PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
@@ -2340,20 +2185,19 @@ static DECLCALLBACK(void) drvHostDSoundDestruct(PPDMDRVINS pDrvIns)
LogFlowFuncLeave();
}
-
/**
- * @callback_method_impl{FNPDMDRVCONSTRUCT,
- * Construct a DirectSound Audio driver instance.}
+ * Construct a DirectSound Audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
*/
static DECLCALLBACK(int) drvHostDSoundConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
RT_NOREF(fFlags);
+ PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
LogRel(("Audio: Initializing DirectSound audio driver\n"));
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
-
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
{
@@ -2401,12 +2245,11 @@ static DECLCALLBACK(int) drvHostDSoundConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pC
/*
* Initialize configuration values.
*/
- dsoundConfigInit(pThis, pCfg);
+ dSoundConfigInit(pThis, pCfg);
return VINF_SUCCESS;
}
-
/**
* PDM driver registration.
*/
diff --git a/src/VBox/Devices/Audio/DrvHostDebugAudio.cpp b/src/VBox/Devices/Audio/DrvHostDebugAudio.cpp
deleted file mode 100644
index f4ba434..0000000
--- a/src/VBox/Devices/Audio/DrvHostDebugAudio.cpp
+++ /dev/null
@@ -1,486 +0,0 @@
-/* $Id: DrvHostDebugAudio.cpp $ */
-/** @file
- * Debug audio driver -- host backend for dumping and injecting audio data
- * from/to the device emulation.
- */
-
-/*
- * Copyright (C) 2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- */
-
-#include <iprt/alloc.h>
-#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
-
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <VBox/log.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-#include "VBoxDD.h"
-
-
-/**
- * Structure for keeping a debug input/output stream.
- */
-typedef struct DEBUGAUDIOSTREAM
-{
- /** Note: Always must come first! */
- PDMAUDIOSTREAM Stream;
- /** Audio file to dump output to or read input from. */
- PDMAUDIOFILE File;
- union
- {
- struct
- {
- /** Timestamp of last captured samples. */
- uint64_t tsLastCaptured;
- } In;
- struct
- {
- /** Timestamp of last played samples. */
- uint64_t tsLastPlayed;
- uint64_t cMaxSamplesInPlayBuffer;
- uint8_t *pu8PlayBuffer;
- } Out;
- };
-
-} DEBUGAUDIOSTREAM, *PDEBUGAUDIOSTREAM;
-
-/**
- * Debug audio driver instance data.
- * @implements PDMIAUDIOCONNECTOR
- */
-typedef struct DRVHOSTDEBUGAUDIO
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
-} DRVHOSTDEBUGAUDIO, *PDRVHOSTDEBUGAUDIO;
-
-/*******************************************PDM_AUDIO_DRIVER******************************/
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
- */
-static DECLCALLBACK(int) drvHostDebugAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
-{
- NOREF(pInterface);
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
-
- pBackendCfg->cbStreamOut = sizeof(DEBUGAUDIOSTREAM);
- pBackendCfg->cbStreamIn = sizeof(DEBUGAUDIOSTREAM);
-
- /* The NULL backend has exactly one input source and one output sink. */
- pBackendCfg->cSources = 1;
- pBackendCfg->cSinks = 1;
-
- pBackendCfg->cMaxStreamsOut = 1; /* Output */
- pBackendCfg->cMaxStreamsIn = 2; /* Line input + microphone input. */
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
- */
-static DECLCALLBACK(int) drvHostDebugAudioInit(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-
- LogFlowFuncLeaveRC(VINF_SUCCESS);
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
- */
-static DECLCALLBACK(void) drvHostDebugAudioShutdown(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDebugAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- RT_NOREF(enmDir);
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
-
- return PDMAUDIOBACKENDSTS_RUNNING;
-}
-
-
-static int debugCreateStreamIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- RT_NOREF(pInterface, pStream);
-
- /* Just adopt the wanted stream configuration. */
- PDMAUDIOPCMPROPS Props;
- int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &Props);
- if (RT_SUCCESS(rc))
- {
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = _1K;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-
-static int debugCreateStreamOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- NOREF(pInterface);
-
- PDEBUGAUDIOSTREAM pDbgStream = (PDEBUGAUDIOSTREAM)pStream;
-
- /* Just adopt the wanted stream configuration. */
- PDMAUDIOPCMPROPS Props;
- int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &Props);
- if (RT_SUCCESS(rc))
- {
- pDbgStream->Out.tsLastPlayed = 0;
- pDbgStream->Out.cMaxSamplesInPlayBuffer = _1K;
- pDbgStream->Out.pu8PlayBuffer = (uint8_t *)RTMemAlloc(pDbgStream->Out.cMaxSamplesInPlayBuffer << Props.cShift);
- if (!pDbgStream->Out.pu8PlayBuffer)
- rc = VERR_NO_MEMORY;
- }
-
- if (RT_SUCCESS(rc))
- {
- char szTemp[RTPATH_MAX];
- rc = RTPathTemp(szTemp, sizeof(szTemp));
- if (RT_SUCCESS(rc))
- {
- char szFile[RTPATH_MAX];
- rc = DrvAudioHlpGetFileName(szFile, RT_ELEMENTS(szFile), szTemp, NULL, PDMAUDIOFILETYPE_WAV);
- if (RT_SUCCESS(rc))
- {
- LogFlowFunc(("%s\n", szFile));
- rc = DrvAudioHlpWAVFileOpen(&pDbgStream->File, szFile,
- RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
- &Props, PDMAUDIOFILEFLAG_NONE);
- if (RT_FAILURE(rc))
- LogRel(("DebugAudio: Creating output file '%s' failed with %Rrc\n", szFile, rc));
- }
- else
- LogRel(("DebugAudio: Unable to build file name for temp dir '%s': %Rrc\n", szTemp, rc));
- }
- else
- LogRel(("DebugAudio: Unable to retrieve temp dir: %Rrc\n", rc));
- }
-
- if (RT_SUCCESS(rc))
- {
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = pDbgStream->Out.cMaxSamplesInPlayBuffer;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvHostDebugAudioStreamCreate(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
-
- int rc;
- if (pCfgReq->enmDir == PDMAUDIODIR_IN)
- rc = debugCreateStreamIn( pInterface, pStream, pCfgReq, pCfgAcq);
- else
- rc = debugCreateStreamOut(pInterface, pStream, pCfgReq, pCfgAcq);
-
- LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
- */
-static DECLCALLBACK(int) drvHostDebugAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf,
- uint32_t *pcbWritten)
-{
- RT_NOREF(pvBuf, cbBuf);
-
- PDRVHOSTDEBUGAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTDEBUGAUDIO, IHostAudio);
- PDEBUGAUDIOSTREAM pDbgStream = (PDEBUGAUDIOSTREAM)pStream;
-
- /* Consume as many samples as would be played at the current frequency since last call. */
- /*uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);*/
-
- uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
- // uint64_t u64TicksElapsed = u64TicksNow - pDbgStream->Out.tsLastPlayed;
- // uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
-
- /*
- * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
- * If rounding is not taken into account then the playback rate will be consistently lower that expected.
- */
- // uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pStream->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
-
- /* Don't play more than available. */
- /*if (cSamplesPlayed > cLive)
- cSamplesPlayed = cLive;*/
-
- uint32_t cSamplesPlayed = 0;
- uint32_t cSamplesAvail = RT_MIN(AudioMixBufUsed(&pStream->MixBuf), pDbgStream->Out.cMaxSamplesInPlayBuffer);
- while (cSamplesAvail)
- {
- uint32_t cSamplesRead = 0;
- int rc2 = AudioMixBufReadCirc(&pStream->MixBuf, pDbgStream->Out.pu8PlayBuffer,
- AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesAvail), &cSamplesRead);
-
- if (RT_FAILURE(rc2))
- LogRel(("DebugAudio: Reading output failed with %Rrc\n", rc2));
-
- if (!cSamplesRead)
- break;
-#if 0
- RTFILE fh;
- RTFileOpen(&fh, "/tmp/AudioDebug-Output.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- RTFileWrite(fh, pDbgStream->Out.pu8PlayBuffer, AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesRead), NULL);
- RTFileClose(fh);
-#endif
- rc2 = DrvAudioHlpWAVFileWrite(&pDbgStream->File,
- pDbgStream->Out.pu8PlayBuffer, AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesRead),
- 0 /* fFlags */);
- if (RT_FAILURE(rc2))
- LogRel(("DebugAudio: Writing output failed with %Rrc\n", rc2));
-
- AudioMixBufFinish(&pStream->MixBuf, cSamplesRead);
-
- Assert(cSamplesAvail >= cSamplesRead);
- cSamplesAvail -= cSamplesRead;
-
- cSamplesPlayed += cSamplesRead;
- }
-
- /* Remember when samples were consumed. */
- pDbgStream->Out.tsLastPlayed = u64TicksNow;
-
- if (pcbWritten)
- *pcbWritten = cSamplesPlayed;
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
- */
-static DECLCALLBACK(int) drvHostDebugAudioStreamCapture(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
-{
- RT_NOREF(pInterface, pStream, pvBuf, cbBuf);
-
- /* Never capture anything. */
- if (pcbRead)
- *pcbRead = 0;
-
- return VINF_SUCCESS;
-}
-
-
-static int debugDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- RT_NOREF(pInterface, pStream);
- LogFlowFuncLeaveRC(VINF_SUCCESS);
- return VINF_SUCCESS;
-}
-
-
-static int debugDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- RT_NOREF(pInterface);
- PDEBUGAUDIOSTREAM pDbgStream = (PDEBUGAUDIOSTREAM)pStream;
- if ( pDbgStream
- && pDbgStream->Out.pu8PlayBuffer)
- {
- RTMemFree(pDbgStream->Out.pu8PlayBuffer);
- pDbgStream->Out.pu8PlayBuffer = NULL;
- }
-
- size_t cbDataSize = DrvAudioHlpWAVFileGetDataSize(&pDbgStream->File);
-
- int rc = DrvAudioHlpWAVFileClose(&pDbgStream->File);
- if (RT_SUCCESS(rc))
- {
- /* Delete the file again if nothing but the header was written to it. */
- bool fDeleteEmptyFiles = true; /** @todo Make deletion configurable? */
-
- if ( !cbDataSize
- && fDeleteEmptyFiles)
- {
- rc = RTFileDelete(pDbgStream->File.szName);
- }
- else
- LogRel(("DebugAudio: Created output file '%s' (%zu bytes)\n", pDbgStream->File.szName, cbDataSize));
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-
-static DECLCALLBACK(int) drvHostDebugAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = debugDestroyStreamIn(pInterface, pStream);
- else
- rc = debugDestroyStreamOut(pInterface, pStream);
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostDebugAudioStreamControl(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- RT_NOREF(enmStreamCmd);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostDebugAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- NOREF(pInterface);
- NOREF(pStream);
-
- return ( PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
- | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE);
-}
-
-static DECLCALLBACK(int) drvHostDebugAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- NOREF(pInterface);
- NOREF(pStream);
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvHostDebugAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTDEBUGAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDEBUGAUDIO);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
- return NULL;
-}
-
-
-/**
- * Constructs a Null audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvHostDebugAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(pCfg, fFlags);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
- PDRVHOSTDEBUGAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDEBUGAUDIO);
- LogRel(("Audio: Initializing DEBUG driver\n"));
-
- /*
- * Init the static parts.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvHostDebugAudioQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostDebugAudio);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Char driver registration record.
- */
-const PDMDRVREG g_DrvHostDebugAudio =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "DebugAudio",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Debug audio host driver",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVHOSTDEBUGAUDIO),
- /* pfnConstruct */
- drvHostDebugAudioConstruct,
- /* pfnDestruct */
- NULL,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
-
diff --git a/src/VBox/Devices/Audio/DrvHostNullAudio.cpp b/src/VBox/Devices/Audio/DrvHostNullAudio.cpp
index 01137ab..a91d7db 100644
--- a/src/VBox/Devices/Audio/DrvHostNullAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvHostNullAudio.cpp
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -40,46 +40,31 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#include <iprt/mem.h>
-#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
-
#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
#include <VBox/log.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
#include "DrvAudio.h"
#include "AudioMixBuffer.h"
+
#include "VBoxDD.h"
+#include <iprt/alloc.h>
+#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
+#include <VBox/vmm/pdmaudioifs.h>
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
typedef struct NULLAUDIOSTREAMOUT
{
- /** @note Always must come first! */
- PDMAUDIOSTREAM Stream;
- /** The PCM properties of this stream. */
- PDMAUDIOPCMPROPS Props;
- uint64_t u64TicksLast;
- uint64_t cMaxSamplesInPlayBuffer;
- uint8_t *pbPlayBuffer;
-} NULLAUDIOSTREAMOUT;
-typedef NULLAUDIOSTREAMOUT *PNULLAUDIOSTREAMOUT;
+ /** Note: Always must come first! */
+ PDMAUDIOHSTSTRMOUT streamOut;
+ uint64_t u64TicksLast;
+ uint64_t csPlayBuffer;
+ uint8_t *pu8PlayBuffer;
+} NULLAUDIOSTREAMOUT, *PNULLAUDIOSTREAMOUT;
typedef struct NULLAUDIOSTREAMIN
{
- /** @note Always must come first! */
- PDMAUDIOSTREAM Stream;
- /** The PCM properties of this stream. */
- PDMAUDIOPCMPROPS Props;
-} NULLAUDIOSTREAMIN;
-typedef NULLAUDIOSTREAMIN *PNULLAUDIOSTREAMIN;
+ /** Note: Always must come first! */
+ PDMAUDIOHSTSTRMIN streamIn;
+} NULLAUDIOSTREAMIN, *PNULLAUDIOSTREAMIN;
/**
* NULL audio driver instance data.
@@ -88,271 +73,179 @@ typedef NULLAUDIOSTREAMIN *PNULLAUDIOSTREAMIN;
typedef struct DRVHOSTNULLAUDIO
{
/** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
+ PPDMDRVINS pDrvIns;
/** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
+ PDMIHOSTAUDIO IHostAudio;
} DRVHOSTNULLAUDIO, *PDRVHOSTNULLAUDIO;
+/*******************************************PDM_AUDIO_DRIVER******************************/
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
- */
-static DECLCALLBACK(int) drvHostNullAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
+static DECLCALLBACK(int) drvHostNullAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
{
NOREF(pInterface);
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- pBackendCfg->cbStreamOut = sizeof(NULLAUDIOSTREAMOUT);
- pBackendCfg->cbStreamIn = sizeof(NULLAUDIOSTREAMIN);
+ pCfg->cbStreamOut = sizeof(NULLAUDIOSTREAMOUT);
+ pCfg->cbStreamIn = sizeof(NULLAUDIOSTREAMIN);
- /* The NULL backend has exactly one input source and one output sink. */
- pBackendCfg->cSources = 1;
- pBackendCfg->cSinks = 1;
-
- pBackendCfg->cMaxStreamsOut = 1; /* Output */
- pBackendCfg->cMaxStreamsIn = 2; /* Line input + microphone input. */
+ pCfg->cMaxHstStrmsOut = 1; /* Output */
+ pCfg->cMaxHstStrmsIn = 2; /* Line input + microphone input. */
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
- */
static DECLCALLBACK(int) drvHostNullAudioInit(PPDMIHOSTAUDIO pInterface)
{
NOREF(pInterface);
- LogFlowFuncLeaveRC(VINF_SUCCESS);
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
- */
-static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
-{
- RT_NOREF(pInterface);
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostNullAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- RT_NOREF(enmDir);
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
-
- return PDMAUDIOBACKENDSTS_RUNNING;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
- */
-static DECLCALLBACK(int) drvHostNullAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- RT_NOREF2(pvBuf, cbBuf);
-
- PDRVHOSTNULLAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTNULLAUDIO, IHostAudio);
- PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
-
- /* Consume as many samples as would be played at the current frequency since last call. */
- uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
-
- uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
- uint64_t u64TicksElapsed = u64TicksNow - pNullStream->u64TicksLast;
- uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
-
- /* Remember when samples were consumed. */
- pNullStream->u64TicksLast = u64TicksNow;
-
- /*
- * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
- * If rounding is not taken into account then the playback rate will be consistently lower that expected.
- */
- uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pNullStream->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
-
- /* Don't play more than available. */
- if (cSamplesPlayed > cLive)
- cSamplesPlayed = cLive;
-
- cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStream->cMaxSamplesInPlayBuffer);
-
- uint32_t cSamplesToRead = 0;
- AudioMixBufReadCirc(&pStream->MixBuf, pNullStream->pbPlayBuffer,
- AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesPlayed), &cSamplesToRead);
- AudioMixBufFinish(&pStream->MixBuf, cSamplesToRead);
-
- if (pcbWritten)
- *pcbWritten = cSamplesToRead;
-
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
- */
-static DECLCALLBACK(int) drvHostNullAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static DECLCALLBACK(int) drvHostNullAudioInitIn(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
{
- RT_NOREF4(pInterface, pStream, pvBuf, cbBuf);
-
- /* Never capture anything. */
- if (pcbRead)
- *pcbRead = 0;
-
- return VINF_SUCCESS;
-}
-
-
-static int nullCreateStreamIn(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- PNULLAUDIOSTREAMIN pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMIN, Stream);
+ NOREF(pInterface);
+ NOREF(enmRecSource);
+ NOREF(pCfgAcq);
/* Just adopt the wanted stream configuration. */
- int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pNullStream->Props);
+ int rc = DrvAudioStreamCfgToProps(pCfgReq, &pHstStrmIn->Props);
if (RT_SUCCESS(rc))
{
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = _1K;
+ if (pcSamples)
+ *pcSamples = _1K;
}
- LogFlowFuncLeaveRC(rc);
- return rc;
+ return VINF_SUCCESS;
}
-
-static int nullCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostNullAudioInitOut(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ uint32_t *pcSamples)
{
- PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
+ NOREF(pInterface);
+ NOREF(pCfgAcq);
/* Just adopt the wanted stream configuration. */
- int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pNullStream->Props);
+ int rc = DrvAudioStreamCfgToProps(pCfgReq, &pHstStrmOut->Props);
if (RT_SUCCESS(rc))
{
- pNullStream->u64TicksLast = 0;
- pNullStream->cMaxSamplesInPlayBuffer = _1K;
-
- pNullStream->pbPlayBuffer = (uint8_t *)RTMemAlloc(_1K << pNullStream->Props.cShift);
- if (pNullStream->pbPlayBuffer)
+ PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
+ pNullStrmOut->u64TicksLast = 0;
+ pNullStrmOut->csPlayBuffer = _1K;
+ pNullStrmOut->pu8PlayBuffer = (uint8_t *)RTMemAlloc(_1K << pHstStrmOut->Props.cShift);
+ if (pNullStrmOut->pu8PlayBuffer)
{
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = pNullStream->cMaxSamplesInPlayBuffer;
+ if (pcSamples)
+ *pcSamples = pNullStrmOut->csPlayBuffer;
}
else
+ {
rc = VERR_NO_MEMORY;
+ }
}
- LogFlowFuncLeaveRC(rc);
return rc;
}
+static DECLCALLBACK(bool) drvHostNullAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+ NOREF(pInterface);
+ NOREF(enmDir);
+ return true; /* Always all enabled. */
+}
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvHostNullAudioStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostNullAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ uint32_t *pcSamplesPlayed)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+ PDRVHOSTNULLAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTNULLAUDIO, IHostAudio);
+ PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
- int rc;
- if (pCfgReq->enmDir == PDMAUDIODIR_IN)
- rc = nullCreateStreamIn( pStream, pCfgReq, pCfgAcq);
- else
- rc = nullCreateStreamOut(pStream, pCfgReq, pCfgAcq);
+ /* Consume as many samples as would be played at the current frequency since last call. */
+ uint32_t csLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
+ uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
+ uint64_t u64TicksElapsed = u64TicksNow - pNullStrmOut->u64TicksLast;
+ uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
- LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
- return rc;
-}
+ /* Remember when samples were consumed. */
+ pNullStrmOut->u64TicksLast = u64TicksNow;
+
+ /*
+ * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
+ * If rounding is not taken into account then the playback rate will be consistently lower that expected.
+ */
+ uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pHstStrmOut->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
+
+ /* Don't play more than available. */
+ if (cSamplesPlayed > csLive)
+ cSamplesPlayed = csLive;
+ cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStrmOut->csPlayBuffer);
+
+ uint32_t csRead = 0;
+ AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pNullStrmOut->pu8PlayBuffer,
+ AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cSamplesPlayed), &csRead);
+ AudioMixBufFinish(&pHstStrmOut->MixBuf, csRead);
+
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = csRead;
-static int nullDestroyStreamIn(void)
-{
- LogFlowFuncLeaveRC(VINF_SUCCESS);
return VINF_SUCCESS;
}
-
-static int nullDestroyStreamOut(PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostNullAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ uint32_t *pcSamplesCaptured)
{
- PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
- if ( pNullStream
- && pNullStream->pbPlayBuffer)
- {
- RTMemFree(pNullStream->pbPlayBuffer);
- pNullStream->pbPlayBuffer = NULL;
- }
+ RT_NOREF(pInterface, pHstStrmIn);
+ /* Never capture anything. */
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = 0;
- LogFlowFuncLeaveRC(VINF_SUCCESS);
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvHostNullAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostNullAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = nullDestroyStreamIn();
- else
- rc = nullDestroyStreamOut(pStream);
+ NOREF(pInterface);
+ NOREF(pHstStrmIn);
+ NOREF(enmStreamCmd);
- return rc;
+ return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
- */
-static DECLCALLBACK(int) drvHostNullAudioStreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostNullAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
- RT_NOREF(enmStreamCmd);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
+ NOREF(pInterface);
+ NOREF(pHstStrmOut);
+ NOREF(enmStreamCmd);
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostNullAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostNullAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
- RT_NOREF(pInterface, pStream);
- return PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
- | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
+ RT_NOREF(pInterface, pHstStrmIn);
+ return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
- */
-static DECLCALLBACK(int) drvHostNullAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostNullAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
- NOREF(pInterface);
- NOREF(pStream);
-
+ RT_NOREF(pInterface);
+ PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
+ if ( pNullStrmOut
+ && pNullStrmOut->pu8PlayBuffer)
+ {
+ RTMemFree(pNullStrmOut->pu8PlayBuffer);
+ }
return VINF_SUCCESS;
}
-
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
@@ -366,6 +259,10 @@ static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface,
return NULL;
}
+static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
+{
+ NOREF(pInterface);
+}
/**
* Constructs a Null audio driver instance.
@@ -376,8 +273,6 @@ static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE
{
RT_NOREF(pCfg, fFlags);
PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
- AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
- /* pCfg is optional. */
PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
LogRel(("Audio: Initializing NULL driver\n"));
@@ -394,7 +289,6 @@ static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE
return VINF_SUCCESS;
}
-
/**
* Char driver registration record.
*/
diff --git a/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp b/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp
index a398aeb..098df56 100644
--- a/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvHostOSSAudio.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2014-2016 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -15,6 +15,13 @@
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
* --------------------------------------------------------------------
*/
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <VBox/log.h>
+#include "DrvAudio.h"
+#include "AudioMixBuffer.h"
+
+#include "VBoxDD.h"
+
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
@@ -24,36 +31,8 @@
#include <iprt/alloc.h>
#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
-
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <VBox/log.h>
#include <VBox/vmm/pdmaudioifs.h>
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-
-#include "VBoxDD.h"
-
-
-/*********************************************************************************************************************************
-* Defines *
-*********************************************************************************************************************************/
-
-#if ((SOUND_VERSION > 360) && (defined(OSS_SYSINFO)))
-/* OSS > 3.6 has a new syscall available for querying a bit more detailed information
- * about OSS' audio capabilities. This is handy for e.g. Solaris. */
-# define VBOX_WITH_AUDIO_OSS_SYSINFO 1
-#endif
-
-/** Makes DRVHOSTOSSAUDIO out of PDMIHOSTAUDIO. */
-#define PDMIHOSTAUDIO_2_DRVHOSTOSSAUDIO(pInterface) \
- ( (PDRVHOSTOSSAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTOSSAUDIO, IHostAudio)) )
-
-
-/*********************************************************************************************************************************
-* Structures *
-*********************************************************************************************************************************/
-
/**
* OSS host audio driver instance data.
* @implements PDMIAUDIOCONNECTOR
@@ -82,25 +61,21 @@ typedef struct OSSAUDIOSTREAMCFG
typedef struct OSSAUDIOSTREAMIN
{
/** Note: Always must come first! */
- PDMAUDIOSTREAM pStreamIn;
- /** The PCM properties of this stream. */
- PDMAUDIOPCMPROPS Props;
+ PDMAUDIOHSTSTRMIN pStreamIn;
int hFile;
int cFragments;
int cbFragmentSize;
/** Own PCM buffer. */
- void *pvBuf;
+ void *pvPCMBuf;
/** Size (in bytes) of own PCM buffer. */
- size_t cbBuf;
+ size_t cbPCMBuf;
int old_optr;
} OSSAUDIOSTREAMIN, *POSSAUDIOSTREAMIN;
typedef struct OSSAUDIOSTREAMOUT
{
/** Note: Always must come first! */
- PDMAUDIOSTREAM pStreamOut;
- /** The PCM properties of this stream. */
- PDMAUDIOPCMPROPS Props;
+ PDMAUDIOHSTSTRMOUT pStreamOut;
int hFile;
int cFragments;
int cbFragmentSize;
@@ -110,9 +85,9 @@ typedef struct OSSAUDIOSTREAMOUT
bool fMemMapped;
#endif
/** Own PCM buffer in case memory mapping is unavailable. */
- void *pvBuf;
+ void *pvPCMBuf;
/** Size (in bytes) of own PCM buffer. */
- size_t cbBuf;
+ size_t cbPCMBuf;
int old_optr;
} OSSAUDIOSTREAMOUT, *POSSAUDIOSTREAMOUT;
@@ -152,27 +127,25 @@ static uint32_t popcount(uint32_t u)
return u;
}
-
static uint32_t lsbindex(uint32_t u)
{
return popcount ((u&-u)-1);
}
-
-static int ossAudioFmtToOSS(PDMAUDIOFMT fmt)
+static int drvHostOSSAudioFmtToOSS(PDMAUDIOFMT fmt)
{
switch (fmt)
{
- case PDMAUDIOFMT_S8:
+ case AUD_FMT_S8:
return AFMT_S8;
- case PDMAUDIOFMT_U8:
+ case AUD_FMT_U8:
return AFMT_U8;
- case PDMAUDIOFMT_S16:
+ case AUD_FMT_S16:
return AFMT_S16_LE;
- case PDMAUDIOFMT_U16:
+ case AUD_FMT_U16:
return AFMT_U16_LE;
default:
@@ -183,43 +156,43 @@ static int ossAudioFmtToOSS(PDMAUDIOFMT fmt)
return AFMT_U8;
}
-
-static int ossOSSToAudioFmt(int fmt, PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pENDIANNESS)
+static int drvHostOSSAudioOSSToFmt(int fmt,
+ PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pENDIANNESS)
{
switch (fmt)
{
case AFMT_S8:
- *pFmt = PDMAUDIOFMT_S8;
+ *pFmt = AUD_FMT_S8;
if (pENDIANNESS)
*pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
break;
case AFMT_U8:
- *pFmt = PDMAUDIOFMT_U8;
+ *pFmt = AUD_FMT_U8;
if (pENDIANNESS)
*pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
break;
case AFMT_S16_LE:
- *pFmt = PDMAUDIOFMT_S16;
+ *pFmt = AUD_FMT_S16;
if (pENDIANNESS)
*pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
break;
case AFMT_U16_LE:
- *pFmt = PDMAUDIOFMT_U16;
+ *pFmt = AUD_FMT_U16;
if (pENDIANNESS)
*pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
break;
case AFMT_S16_BE:
- *pFmt = PDMAUDIOFMT_S16;
+ *pFmt = AUD_FMT_S16;
if (pENDIANNESS)
*pENDIANNESS = PDMAUDIOENDIANNESS_BIG;
break;
case AFMT_U16_BE:
- *pFmt = PDMAUDIOFMT_U16;
+ *pFmt = AUD_FMT_U16;
if (pENDIANNESS)
*pENDIANNESS = PDMAUDIOENDIANNESS_BIG;
break;
@@ -232,8 +205,7 @@ static int ossOSSToAudioFmt(int fmt, PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEND
return VINF_SUCCESS;
}
-
-static int ossStreamClose(int *phFile)
+static int drvHostOSSAudioClose(int *phFile)
{
if (!phFile || !*phFile)
return VINF_SUCCESS;
@@ -241,7 +213,8 @@ static int ossStreamClose(int *phFile)
int rc;
if (close(*phFile))
{
- LogRel(("OSS: Closing stream failed: %s\n", strerror(errno)));
+ LogRel(("OSS: Closing descriptor failed: %s\n",
+ strerror(errno)));
rc = VERR_GENERAL_FAILURE; /** @todo */
}
else
@@ -253,26 +226,40 @@ static int ossStreamClose(int *phFile)
return rc;
}
-
-static int ossStreamOpen(const char *pszDev, int fOpen, POSSAUDIOSTREAMCFG pReq, POSSAUDIOSTREAMCFG pObt, int *phFile)
+static int drvHostOSSAudioOpen(bool fIn,
+ POSSAUDIOSTREAMCFG pReq, POSSAUDIOSTREAMCFG pObt,
+ int *phFile)
{
+ AssertPtrReturn(pReq, VERR_INVALID_POINTER);
+ AssertPtrReturn(pObt, VERR_INVALID_POINTER);
+ AssertPtrReturn(phFile, VERR_INVALID_POINTER);
+
int rc;
+ int hFile;
- int hFile = -1;
do
{
- hFile = open(pszDev, fOpen);
+ const char *pszDev = fIn ? s_OSSConf.devpath_in : s_OSSConf.devpath_out;
+ if (!pszDev)
+ {
+ LogRel(("OSS: Invalid or no %s device name set\n",
+ fIn ? "input" : "output"));
+ rc = VERR_INVALID_PARAMETER;
+ break;
+ }
+
+ hFile = open(pszDev, (fIn ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
if (hFile == -1)
{
- LogRel(("OSS: Failed to open %s: %s (%d)\n", pszDev, strerror(errno), errno));
+ LogRel(("OSS: Failed to open %s: %s(%d)\n", pszDev, strerror(errno), errno));
rc = RTErrConvertFromErrno(errno);
break;
}
- int iFormat = ossAudioFmtToOSS(pReq->enmFormat);
+ int iFormat = drvHostOSSAudioFmtToOSS(pReq->enmFormat);
if (ioctl(hFile, SNDCTL_DSP_SAMPLESIZE, &iFormat))
{
- LogRel(("OSS: Failed to set audio format to %ld: %s (%d)\n", iFormat, strerror(errno), errno));
+ LogRel(("OSS: Failed to set audio format to %ld errno=%s(%d)\n", iFormat, strerror(errno), errno));
rc = RTErrConvertFromErrno(errno);
break;
}
@@ -280,7 +267,7 @@ static int ossStreamOpen(const char *pszDev, int fOpen, POSSAUDIOSTREAMCFG pReq,
int cChannels = pReq->cChannels;
if (ioctl(hFile, SNDCTL_DSP_CHANNELS, &cChannels))
{
- LogRel(("OSS: Failed to set number of audio channels (%d): %s (%d)\n", pReq->cChannels, strerror(errno), errno));
+ LogRel(("OSS: Failed to set number of audio channels (%d): %s(%d)\n", pReq->cChannels, strerror(errno), errno));
rc = RTErrConvertFromErrno(errno);
break;
}
@@ -288,7 +275,7 @@ static int ossStreamOpen(const char *pszDev, int fOpen, POSSAUDIOSTREAMCFG pReq,
int freq = pReq->uFreq;
if (ioctl(hFile, SNDCTL_DSP_SPEED, &freq))
{
- LogRel(("OSS: Failed to set audio frequency (%dHZ): %s (%d)\n", pReq->uFreq, strerror(errno), errno));
+ LogRel(("OSS: Failed to set audio frequency (%dHZ): %s(%d)\n", pReq->uFreq, strerror(errno), errno));
rc = RTErrConvertFromErrno(errno);
break;
}
@@ -297,7 +284,7 @@ static int ossStreamOpen(const char *pszDev, int fOpen, POSSAUDIOSTREAMCFG pReq,
#if !(defined(VBOX) && defined(RT_OS_SOLARIS))
if (ioctl(hFile, SNDCTL_DSP_NONBLOCK))
{
- LogRel(("OSS: Failed to set non-blocking mode: %s (%d)\n", strerror(errno), errno));
+ LogRel(("OSS: Failed to set non-blocking mode: %s(%d)\n", strerror(errno), errno));
rc = RTErrConvertFromErrno(errno);
break;
}
@@ -305,24 +292,21 @@ static int ossStreamOpen(const char *pszDev, int fOpen, POSSAUDIOSTREAMCFG pReq,
int mmmmssss = (pReq->cFragments << 16) | lsbindex(pReq->cbFragmentSize);
if (ioctl(hFile, SNDCTL_DSP_SETFRAGMENT, &mmmmssss))
{
- LogRel(("OSS: Failed to set %RU16 fragments to %RU32 bytes each: %s (%d)\n",
+ LogRel(("OSS: Failed to set %RU16 fragments to %RU32 bytes each: %s(%d)\n",
pReq->cFragments, pReq->cbFragmentSize, strerror(errno), errno));
rc = RTErrConvertFromErrno(errno);
break;
}
- /* Check access mode (input or output). */
- bool fIn = ((fOpen & O_ACCMODE) == O_RDONLY);
-
audio_buf_info abinfo;
if (ioctl(hFile, fIn ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo))
{
- LogRel(("OSS: Failed to retrieve %s buffer length: %s (%d)\n", fIn ? "input" : "output", strerror(errno), errno));
+ LogRel(("OSS: Failed to retrieve buffer length: %s(%d)\n", strerror(errno), errno));
rc = RTErrConvertFromErrno(errno);
break;
}
- rc = ossOSSToAudioFmt(iFormat, &pObt->enmFormat, &pObt->enmENDIANNESS);
+ rc = drvHostOSSAudioOSSToFmt(iFormat, &pObt->enmFormat, &pObt->enmENDIANNESS);
if (RT_SUCCESS(rc))
{
pObt->cChannels = cChannels;
@@ -336,29 +320,36 @@ static int ossStreamOpen(const char *pszDev, int fOpen, POSSAUDIOSTREAMCFG pReq,
while (0);
if (RT_FAILURE(rc))
- ossStreamClose(&hFile);
+ drvHostOSSAudioClose(&hFile);
LogFlowFuncLeaveRC(rc);
return rc;
}
-
-static int ossControlStreamIn(/*PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd*/ void)
+static DECLCALLBACK(int) drvHostOSSAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
+ NOREF(pInterface);
+ NOREF(pHstStrmIn);
+ NOREF(enmStreamCmd);
+
/** @todo Nothing to do here right now!? */
return VINF_SUCCESS;
}
-
-static int ossControlStreamOut(PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostOSSAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
- POSSAUDIOSTREAMOUT pStreamOut = (POSSAUDIOSTREAMOUT)pStream;
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+ POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
#ifdef RT_OS_L4
return VINF_SUCCESS;
#else
- if (!pStreamOut->fMemMapped)
+ if (!pThisStrmOut->fMemMapped)
return VINF_SUCCESS;
#endif
@@ -369,11 +360,11 @@ static int ossControlStreamOut(PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStr
case PDMAUDIOSTREAMCMD_ENABLE:
case PDMAUDIOSTREAMCMD_RESUME:
{
- DrvAudioHlpClearBuf(&pStreamOut->Props,
- pStreamOut->pvBuf, pStreamOut->cbBuf, AudioMixBufSize(&pStream->MixBuf));
+ DrvAudioClearBuf(&pHstStrmOut->Props,
+ pThisStrmOut->pvPCMBuf, pThisStrmOut->cbPCMBuf, AudioMixBufSize(&pHstStrmOut->MixBuf));
mask = PCM_ENABLE_OUTPUT;
- if (ioctl(pStreamOut->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
+ if (ioctl(pThisStrmOut->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
{
LogRel(("OSS: Failed to enable output stream: %s\n", strerror(errno)));
rc = RTErrConvertFromErrno(errno);
@@ -386,7 +377,7 @@ static int ossControlStreamOut(PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStr
case PDMAUDIOSTREAMCMD_PAUSE:
{
mask = 0;
- if (ioctl(pStreamOut->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
+ if (ioctl(pThisStrmOut->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
{
LogRel(("OSS: Failed to disable output stream: %s\n", strerror(errno)));
rc = RTErrConvertFromErrno(errno);
@@ -405,33 +396,26 @@ static int ossControlStreamOut(PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStr
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
- */
static DECLCALLBACK(int) drvHostOSSAudioInit(PPDMIHOSTAUDIO pInterface)
{
- RT_NOREF(pInterface);
+ NOREF(pInterface);
LogFlowFuncEnter();
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
- */
-static DECLCALLBACK(int) drvHostOSSAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static DECLCALLBACK(int) drvHostOSSAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ uint32_t *pcSamplesCaptured)
{
- RT_NOREF(pInterface, cbBuf, pvBuf);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- POSSAUDIOSTREAMIN pStrm = (POSSAUDIOSTREAMIN)pStream;
+ POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
int rc = VINF_SUCCESS;
- size_t cbToRead = RT_MIN(pStrm->cbBuf,
- AudioMixBufFreeBytes(&pStream->MixBuf));
+ size_t cbToRead = RT_MIN(pThisStrmIn->cbPCMBuf,
+ AudioMixBufFreeBytes(&pHstStrmIn->MixBuf));
LogFlowFunc(("cbToRead=%zu\n", cbToRead));
@@ -442,11 +426,12 @@ static DECLCALLBACK(int) drvHostOSSAudioStreamCapture(PPDMIHOSTAUDIO pInterface,
while (cbToRead)
{
- cbTemp = RT_MIN(cbToRead, pStrm->cbBuf);
+ cbTemp = RT_MIN(cbToRead, pThisStrmIn->cbPCMBuf);
AssertBreakStmt(cbTemp, rc = VERR_NO_DATA);
- cbRead = read(pStrm->hFile, (uint8_t *)pStrm->pvBuf + offWrite, cbTemp);
+ cbRead = read(pThisStrmIn->hFile, (uint8_t *)pThisStrmIn->pvPCMBuf + offWrite, cbTemp);
- LogFlowFunc(("cbRead=%zi, cbTemp=%RU32, cbToRead=%zu\n", cbRead, cbTemp, cbToRead));
+ LogFlowFunc(("cbRead=%zi, cbTemp=%RU32, cbToRead=%zu\n",
+ cbRead, cbTemp, cbToRead));
if (cbRead < 0)
{
@@ -465,8 +450,9 @@ static DECLCALLBACK(int) drvHostOSSAudioStreamCapture(PPDMIHOSTAUDIO pInterface,
break;
default:
- LogFlowFunc(("Failed to read %zu input frames, rc=%Rrc\n", cbTemp, rc));
- rc = VERR_GENERAL_FAILURE; /** @todo Fix this. */
+ LogFlowFunc(("Failed to read %zu input frames, rc=%Rrc\n",
+ cbTemp, rc));
+ rc = VERR_GENERAL_FAILURE; /** @todo */
break;
}
@@ -476,11 +462,13 @@ static DECLCALLBACK(int) drvHostOSSAudioStreamCapture(PPDMIHOSTAUDIO pInterface,
else if (cbRead)
{
uint32_t cWritten;
- rc = AudioMixBufWriteCirc(&pStream->MixBuf, pStrm->pvBuf, cbRead, &cWritten);
+ rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
+ pThisStrmIn->pvPCMBuf, cbRead,
+ &cWritten);
if (RT_FAILURE(rc))
break;
- uint32_t cbWritten = AUDIOMIXBUF_S2B(&pStream->MixBuf, cWritten);
+ uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
Assert(cbToRead >= cbWritten);
cbToRead -= cbWritten;
@@ -498,10 +486,11 @@ static DECLCALLBACK(int) drvHostOSSAudioStreamCapture(PPDMIHOSTAUDIO pInterface,
{
uint32_t cProcessed = 0;
if (cWrittenTotal)
- rc = AudioMixBufMixToParent(&pStream->MixBuf, cWrittenTotal, &cProcessed);
+ rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
+ &cProcessed);
- if (pcbRead)
- *pcbRead = cWrittenTotal;
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = cWrittenTotal;
LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
cWrittenTotal, cProcessed, rc));
@@ -511,153 +500,77 @@ static DECLCALLBACK(int) drvHostOSSAudioStreamCapture(PPDMIHOSTAUDIO pInterface,
return rc;
}
-
-static int ossDestroyStreamIn(PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostOSSAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
- POSSAUDIOSTREAMIN pStrm = (POSSAUDIOSTREAMIN)pStream;
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+
+ POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
LogFlowFuncEnter();
- if (pStrm->pvBuf)
+ if (pThisStrmIn->pvPCMBuf)
{
- Assert(pStrm->cbBuf);
+ Assert(pThisStrmIn->cbPCMBuf);
- RTMemFree(pStrm->pvBuf);
- pStrm->pvBuf = NULL;
+ RTMemFree(pThisStrmIn->pvPCMBuf);
+ pThisStrmIn->pvPCMBuf = NULL;
}
- pStrm->cbBuf = 0;
-
- ossStreamClose(&pStrm->hFile);
+ pThisStrmIn->cbPCMBuf = 0;
return VINF_SUCCESS;
}
-
-static int ossDestroyStreamOut(PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostOSSAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
- POSSAUDIOSTREAMOUT pStrm = (POSSAUDIOSTREAMOUT)pStream;
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+
+ POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
LogFlowFuncEnter();
#ifndef RT_OS_L4
- if (pStrm->fMemMapped)
- {
- if (pStrm->pvBuf)
- {
- Assert(pStrm->cbBuf);
-
- int rc2 = munmap(pStrm->pvBuf, pStrm->cbBuf);
- if (rc2 == 0)
- {
- pStrm->pvBuf = NULL;
- pStrm->cbBuf = 0;
-
- pStrm->fMemMapped = false;
- }
- else
- LogRel(("OSS: Failed to memory unmap playback buffer on close: %s\n", strerror(errno)));
- }
- }
- else
+ if (!pThisStrmOut->fMemMapped)
{
-#endif
- if (pStrm->pvBuf)
+ if (pThisStrmOut->pvPCMBuf)
{
- Assert(pStrm->cbBuf);
+ Assert(pThisStrmOut->cbPCMBuf);
- RTMemFree(pStrm->pvBuf);
- pStrm->pvBuf = NULL;
+ RTMemFree(pThisStrmOut->pvPCMBuf);
+ pThisStrmOut->pvPCMBuf = NULL;
}
- pStrm->cbBuf = 0;
-#ifndef RT_OS_L4
+ pThisStrmOut->cbPCMBuf = 0;
}
#endif
- ossStreamClose(&pStrm->hFile);
-
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
- */
-static DECLCALLBACK(int) drvHostOSSAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
+static DECLCALLBACK(int) drvHostOSSAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
{
- RT_NOREF(pInterface);
-
- pBackendCfg->cbStreamIn = sizeof(OSSAUDIOSTREAMIN);
- pBackendCfg->cbStreamOut = sizeof(OSSAUDIOSTREAMOUT);
-
- pBackendCfg->cSources = 0;
- pBackendCfg->cSinks = 0;
-
- int hFile = open("/dev/dsp", O_WRONLY | O_NONBLOCK, 0);
- if (hFile == -1)
- {
- /* Try opening the mixing device instead. */
- hFile = open("/dev/mixer", O_RDONLY | O_NONBLOCK, 0);
- }
-
- int ossVer = -1;
-
-#ifdef VBOX_WITH_AUDIO_OSS_SYSINFO
- oss_sysinfo ossInfo;
- RT_ZERO(ossInfo);
-#endif
-
- if (hFile != -1)
- {
- int err = ioctl(hFile, OSS_GETVERSION, &ossVer);
- if (err == 0)
- {
- LogRel2(("OSS: Using version: %d\n", ossVer));
-#ifdef VBOX_WITH_AUDIO_OSS_SYSINFO
- err = ioctl(hFile, OSS_SYSINFO, &ossInfo);
- if (err == 0)
- {
- LogRel2(("OSS: Number of DSPs: %d\n", ossInfo.numaudios));
- LogRel2(("OSS: Number of mixers: %d\n", ossInfo.nummixers));
-
- int cDev = ossInfo.nummixers;
- if (!cDev)
- cDev = ossInfo.numaudios;
+ NOREF(pInterface);
- pBackendCfg->cSources = cDev;
- pBackendCfg->cSinks = cDev;
-
- pBackendCfg->cMaxStreamsIn = UINT32_MAX;
- pBackendCfg->cMaxStreamsOut = UINT32_MAX;
- }
- else
- {
-#endif
- /* Since we cannot query anything, assume that we have at least
- * one input and one output if we found "/dev/dsp" or "/dev/mixer". */
- pBackendCfg->cSources = 1;
- pBackendCfg->cSinks = 1;
-
- pBackendCfg->cMaxStreamsIn = UINT32_MAX;
- pBackendCfg->cMaxStreamsOut = UINT32_MAX;
-#ifdef VBOX_WITH_AUDIO_OSS_SYSINFO
- }
-#endif
- }
- else
- LogRel(("OSS: Unable to determine installed version: %s (%d)\n", strerror(err), err));
- }
- else
- LogRel(("OSS: No devices found, audio is not available\n"));
+ pCfg->cbStreamOut = sizeof(OSSAUDIOSTREAMOUT);
+ pCfg->cbStreamIn = sizeof(OSSAUDIOSTREAMIN);
+ pCfg->cMaxHstStrmsOut = INT_MAX;
+ pCfg->cMaxHstStrmsIn = INT_MAX;
return VINF_SUCCESS;
}
-
-static int ossCreateStreamIn(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostOSSAudioInitIn(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
{
- POSSAUDIOSTREAMIN pStrm = (POSSAUDIOSTREAMIN)pStream;
+ RT_NOREF(pInterface, pCfgAcq, enmRecSource);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+
+ POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
int rc;
int hFile = -1;
@@ -673,63 +586,69 @@ static int ossCreateStreamIn(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq
reqStream.cFragments = s_OSSConf.nfrags;
reqStream.cbFragmentSize = s_OSSConf.fragsize;
- rc = ossStreamOpen(s_OSSConf.devpath_in, O_RDONLY | O_NONBLOCK, &reqStream, &obtStream, &hFile);
+ rc = drvHostOSSAudioOpen(true /* fIn */,
+ &reqStream, &obtStream, &hFile);
if (RT_SUCCESS(rc))
{
- pCfgAcq->enmFormat = obtStream.enmFormat;
- pCfgAcq->uHz = obtStream.uFreq;
- pCfgAcq->cChannels = pCfgReq->cChannels; /** @todo r=andy Why not using obtStream? */
- pCfgAcq->enmEndianness = obtStream.enmENDIANNESS;
+ if (obtStream.cFragments * obtStream.cbFragmentSize & pHstStrmIn->Props.uAlign)
+ LogRel(("OSS: Warning: Misaligned DAC output buffer: Size = %zu, Alignment = %u\n",
+ obtStream.cFragments * obtStream.cbFragmentSize,
+ pHstStrmIn->Props.uAlign + 1));
+
+ pThisStrmIn->hFile = hFile;
- rc = DrvAudioHlpStreamCfgToProps(pCfgAcq, &pStrm->Props);
+ PDMAUDIOSTREAMCFG streamCfg;
+ streamCfg.enmFormat = obtStream.enmFormat;
+ streamCfg.uHz = obtStream.uFreq;
+ streamCfg.cChannels = pCfgReq->cChannels;
+ streamCfg.enmEndianness = obtStream.enmENDIANNESS;
+
+ rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
if (RT_SUCCESS(rc))
{
- if (obtStream.cFragments * obtStream.cbFragmentSize & pStrm->Props.uAlign)
- {
- LogRel(("OSS: Warning: Misaligned capturing buffer: Size = %zu, Alignment = %u\n",
- obtStream.cFragments * obtStream.cbFragmentSize, pStrm->Props.uAlign + 1));
- }
-
- cSamples = (obtStream.cFragments * obtStream.cbFragmentSize) >> pStrm->Props.cShift;
+ cSamples = (obtStream.cFragments * obtStream.cbFragmentSize)
+ >> pHstStrmIn->Props.cShift;
if (!cSamples)
rc = VERR_INVALID_PARAMETER;
}
+ }
- if (RT_SUCCESS(rc))
+ if (RT_SUCCESS(rc))
+ {
+ size_t cbSample = (1 << pHstStrmIn->Props.cShift);
+ size_t cbBuf = cSamples * cbSample;
+ pThisStrmIn->pvPCMBuf = RTMemAlloc(cbBuf);
+ if (!pThisStrmIn->pvPCMBuf)
{
- size_t cbSample = (1 << pStrm->Props.cShift);
-
- size_t cbBuf = cSamples * cbSample;
- void *pvBuf = RTMemAlloc(cbBuf);
- if (!pvBuf)
- {
- LogRel(("OSS: Failed allocating capturing buffer with %RU32 samples (%zu bytes per sample)\n",
- cSamples, cbSample));
- rc = VERR_NO_MEMORY;
- break;
- }
+ LogRel(("OSS: Failed allocating ADC buffer with %RU32 samples (%zu bytes per sample)\n", cSamples, cbSample));
+ rc = VERR_NO_MEMORY;
+ }
- pStrm->hFile = hFile;
- pStrm->pvBuf = pvBuf;
- pStrm->cbBuf = cbBuf;
+ pThisStrmIn->cbPCMBuf = cbBuf;
- pCfgAcq->cSampleBufferSize = cSamples;
- }
+ if (pcSamples)
+ *pcSamples = cSamples;
}
} while (0);
if (RT_FAILURE(rc))
- ossStreamClose(&hFile);
+ drvHostOSSAudioClose(&hFile);
LogFlowFuncLeaveRC(rc);
return rc;
}
-
-static int ossCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostOSSAudioInitOut(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ uint32_t *pcSamples)
{
- POSSAUDIOSTREAMOUT pStrm = (POSSAUDIOSTREAMOUT)pStream;
+ RT_NOREF(pInterface, pCfgAcq);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+
+ POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
int rc;
int hFile = -1;
@@ -745,41 +664,41 @@ static int ossCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgRe
reqStream.cFragments = s_OSSConf.nfrags;
reqStream.cbFragmentSize = s_OSSConf.fragsize;
- rc = ossStreamOpen(s_OSSConf.devpath_out, O_WRONLY | O_NONBLOCK, &reqStream, &obtStream, &hFile);
+ rc = drvHostOSSAudioOpen(false /* fIn */,
+ &reqStream, &obtStream, &hFile);
if (RT_SUCCESS(rc))
{
- pCfgAcq->enmFormat = obtStream.enmFormat;
- pCfgAcq->uHz = obtStream.uFreq;
- pCfgAcq->cChannels = pCfgReq->cChannels; /** @todo r=andy Why not using obtStream? */
- pCfgAcq->enmEndianness = obtStream.enmENDIANNESS;
+ if (obtStream.cFragments * obtStream.cbFragmentSize & pHstStrmOut->Props.uAlign)
+ LogRel(("OSS: Warning: Misaligned DAC output buffer: Size = %zu, Alignment = %u\n",
+ obtStream.cFragments * obtStream.cbFragmentSize,
+ pHstStrmOut->Props.uAlign + 1));
- rc = DrvAudioHlpStreamCfgToProps(pCfgAcq, &pStrm->Props);
- if (RT_SUCCESS(rc))
- {
- cSamples = (obtStream.cFragments * obtStream.cbFragmentSize) >> pStrm->Props.cShift;
+ pThisStrmOut->hFile = hFile;
- if (obtStream.cFragments * obtStream.cbFragmentSize & pStrm->Props.uAlign)
- {
- LogRel(("OSS: Warning: Misaligned playback buffer: Size = %zu, Alignment = %u\n",
- obtStream.cFragments * obtStream.cbFragmentSize, pStrm->Props.uAlign + 1));
- }
- }
+ PDMAUDIOSTREAMCFG streamCfg;
+ streamCfg.enmFormat = obtStream.enmFormat;
+ streamCfg.uHz = obtStream.uFreq;
+ streamCfg.cChannels = pCfgReq->cChannels;
+ streamCfg.enmEndianness = obtStream.enmENDIANNESS;
+
+ rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
+ if (RT_SUCCESS(rc))
+ cSamples = (obtStream.cFragments * obtStream.cbFragmentSize)
+ >> pHstStrmOut->Props.cShift;
}
if (RT_SUCCESS(rc))
{
- pStrm->fMemMapped = false;
-
- size_t cbSamples = cSamples << pStrm->Props.cShift;
- Assert(cbSamples);
-
#ifndef RT_OS_L4
+ pThisStrmOut->fMemMapped = false;
if (s_OSSConf.try_mmap)
{
- pStrm->pvBuf = mmap(0, cbSamples, PROT_READ | PROT_WRITE, MAP_SHARED, hFile, 0);
- if (pStrm->pvBuf == MAP_FAILED)
+ pThisStrmOut->pvPCMBuf = mmap(0, cSamples << pHstStrmOut->Props.cShift,
+ PROT_READ | PROT_WRITE, MAP_SHARED, hFile, 0);
+ if (pThisStrmOut->pvPCMBuf == MAP_FAILED)
{
- LogRel(("OSS: Failed to memory map %zu bytes of playback buffer: %s\n", cbSamples, strerror(errno)));
+ LogRel(("OSS: Failed to memory map %zu bytes of DAC output file: %s\n",
+ cSamples << pHstStrmOut->Props.cShift, strerror(errno)));
rc = RTErrConvertFromErrno(errno);
break;
}
@@ -788,7 +707,8 @@ static int ossCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgRe
int mask = 0;
if (ioctl(hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
{
- LogRel(("OSS: Failed to retrieve initial trigger mask for playback buffer: %s\n", strerror(errno)));
+ LogRel(("OSS: Failed to retrieve initial trigger mask: %s\n",
+ strerror(errno)));
rc = RTErrConvertFromErrno(errno);
/* Note: No break here, need to unmap file first! */
}
@@ -797,19 +717,21 @@ static int ossCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgRe
mask = PCM_ENABLE_OUTPUT;
if (ioctl (hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
{
- LogRel(("OSS: Failed to retrieve PCM_ENABLE_OUTPUT mask: %s\n", strerror(errno)));
+ LogRel(("OSS: Failed to retrieve PCM_ENABLE_OUTPUT mask: %s\n",
+ strerror(errno)));
rc = RTErrConvertFromErrno(errno);
/* Note: No break here, need to unmap file first! */
}
else
- pStrm->fMemMapped = true;
+ pThisStrmOut->fMemMapped = true;
}
- if (RT_FAILURE(rc))
+ if (!pThisStrmOut->fMemMapped)
{
- int rc2 = munmap(pStrm->pvBuf, cbSamples);
+ int rc2 = munmap(pThisStrmOut->pvPCMBuf,
+ cSamples << pHstStrmOut->Props.cShift);
if (rc2)
- LogRel(("OSS: Failed to memory unmap playback buffer: %s\n", strerror(errno)));
+ LogRel(("OSS: Failed to unmap DAC output file: %s\n", strerror(errno)));
break;
}
}
@@ -818,45 +740,53 @@ static int ossCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgRe
/* Memory mapping failed above? Try allocating an own buffer. */
#ifndef RT_OS_L4
- if (!pStrm->fMemMapped)
+ if (!pThisStrmOut->fMemMapped)
{
#endif
- void *pvBuf = RTMemAlloc(cbSamples);
- if (!pvBuf)
+ size_t cbSample = (1 << pHstStrmOut->Props.cShift);
+ size_t cbPCMBuf = cSamples * cbSample;
+
+ LogFlowFunc(("cSamples=%RU32\n", cSamples));
+
+ pThisStrmOut->pvPCMBuf = RTMemAlloc(cbPCMBuf);
+ if (!pThisStrmOut->pvPCMBuf)
{
- LogRel(("OSS: Failed allocating playback buffer with %RU32 samples (%zu bytes)\n", cSamples, cbSamples));
+ LogRel(("OSS: Failed allocating DAC buffer with %RU32 samples (%zu bytes per sample)\n", cSamples, cbSample));
rc = VERR_NO_MEMORY;
break;
}
- pStrm->hFile = hFile;
- pStrm->pvBuf = pvBuf;
- pStrm->cbBuf = cbSamples;
+ pThisStrmOut->cbPCMBuf = cbPCMBuf;
#ifndef RT_OS_L4
}
#endif
- pCfgAcq->cSampleBufferSize = cSamples;
+ if (pcSamples)
+ *pcSamples = cSamples;
}
} while (0);
if (RT_FAILURE(rc))
- ossStreamClose(&hFile);
+ drvHostOSSAudioClose(&hFile);
LogFlowFuncLeaveRC(rc);
return rc;
}
+static DECLCALLBACK(bool) drvHostOSSAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+ NOREF(pInterface);
+ NOREF(enmDir);
+ return true; /* Always all enabled. */
+}
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
- */
-static DECLCALLBACK(int) drvHostOSSAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+static DECLCALLBACK(int) drvHostOSSAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ uint32_t *pcSamplesPlayed)
{
- RT_NOREF(pInterface, cbBuf, pvBuf);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- POSSAUDIOSTREAMOUT pStrm = (POSSAUDIOSTREAMOUT)pStream;
+ POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
int rc = VINF_SUCCESS;
uint32_t cbReadTotal = 0;
@@ -864,16 +794,16 @@ static DECLCALLBACK(int) drvHostOSSAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PP
do
{
- size_t cbBufSize = AudioMixBufSizeBytes(&pStream->MixBuf);
+ size_t cbBuf = AudioMixBufSizeBytes(&pHstStrmOut->MixBuf);
- uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
+ uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
uint32_t cToRead;
#ifndef RT_OS_L4
- if (pStrm->fMemMapped)
+ if (pThisStrmOut->fMemMapped)
{
/* Get current playback pointer. */
- int rc2 = ioctl(pStrm->hFile, SNDCTL_DSP_GETOPTR, &cntinfo);
+ int rc2 = ioctl(pThisStrmOut->hFile, SNDCTL_DSP_GETOPTR, &cntinfo);
if (!rc2)
{
LogRel(("OSS: Failed to retrieve current playback pointer: %s\n",
@@ -883,63 +813,69 @@ static DECLCALLBACK(int) drvHostOSSAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PP
}
/* Nothing to play? */
- if (cntinfo.ptr == pStrm->old_optr)
+ if (cntinfo.ptr == pThisStrmOut->old_optr)
break;
int cbData;
- if (cntinfo.ptr > pStrm->old_optr)
- cbData = cntinfo.ptr - pStrm->old_optr;
+ if (cntinfo.ptr > pThisStrmOut->old_optr)
+ cbData = cntinfo.ptr - pThisStrmOut->old_optr;
else
- cbData = cbBufSize + cntinfo.ptr - pStrm->old_optr;
+ cbData = cbBuf + cntinfo.ptr - pThisStrmOut->old_optr;
Assert(cbData);
- cToRead = RT_MIN((uint32_t)AUDIOMIXBUF_B2S(&pStream->MixBuf, cbData),
+ cToRead = RT_MIN((uint32_t)AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbData),
cLive);
}
else
{
#endif
audio_buf_info abinfo;
- int rc2 = ioctl(pStrm->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
+ int rc2 = ioctl(pThisStrmOut->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
if (rc2 < 0)
{
- LogRel(("OSS: Failed to retrieve current playback buffer: %s\n", strerror(errno)));
+ LogRel(("OSS: Failed to retrieve current playback buffer: %s\n",
+ strerror(errno)));
rc = RTErrConvertFromErrno(errno);
break;
}
- if ((size_t)abinfo.bytes > cbBufSize)
+ if ((size_t)abinfo.bytes > cbBuf)
{
- LogFlowFunc(("Warning: Invalid available size, size=%d, bufsize=%zu\n", abinfo.bytes, cbBufSize));
- abinfo.bytes = cbBufSize;
+ LogFlowFunc(("Warning: Invalid available size, size=%d, bufsize=%d\n",
+ abinfo.bytes, cbBuf));
+ abinfo.bytes = cbBuf;
/* Keep going. */
}
if (abinfo.bytes < 0)
{
- LogFlowFunc(("Warning: Invalid available size, size=%d, bufsize=%zu\n", abinfo.bytes, cbBufSize));
+ LogFlowFunc(("Warning: Invalid available size, size=%d, bufsize=%d\n",
+ abinfo.bytes, cbBuf));
rc = VERR_INVALID_PARAMETER;
break;
}
- cToRead = RT_MIN((uint32_t)AUDIOMIXBUF_B2S(&pStream->MixBuf, abinfo.bytes), cLive);
+ cToRead = RT_MIN((uint32_t)AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, abinfo.bytes),
+ cLive);
if (!cToRead)
break;
#ifndef RT_OS_L4
}
#endif
- size_t cbToRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cToRead);
+ size_t cbToRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cToRead);
LogFlowFunc(("cbToRead=%zu\n", cbToRead));
uint32_t cRead, cbRead;
while (cbToRead)
{
- rc = AudioMixBufReadCirc(&pStream->MixBuf, pStrm->pvBuf, cbToRead, &cRead);
+ rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf,
+ pThisStrmOut->pvPCMBuf, cbToRead, &cRead);
if (RT_FAILURE(rc))
break;
- cbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead);
- ssize_t cbWritten = write(pStrm->hFile, pStrm->pvBuf, cbRead);
+ cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
+ ssize_t cbWritten = write(pThisStrmOut->hFile, pThisStrmOut->pvPCMBuf,
+ cbRead);
if (cbWritten == -1)
{
LogRel(("OSS: Failed writing output data: %s\n", strerror(errno)));
@@ -948,145 +884,38 @@ static DECLCALLBACK(int) drvHostOSSAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PP
}
Assert(cbToRead >= cbRead);
- cbToRead -= cbRead;
+ cbToRead -= cbRead;
cbReadTotal += cbRead;
}
#ifndef RT_OS_L4
/* Update read pointer. */
- if (pStrm->fMemMapped)
- pStrm->old_optr = cntinfo.ptr;
+ if (pThisStrmOut->fMemMapped)
+ pThisStrmOut->old_optr = cntinfo.ptr;
#endif
} while(0);
if (RT_SUCCESS(rc))
{
- uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pStream->MixBuf, cbReadTotal);
+ uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
if (cReadTotal)
- AudioMixBufFinish(&pStream->MixBuf, cReadTotal);
+ AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
- if (pcbWritten)
- *pcbWritten = cReadTotal;
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = cReadTotal;
- LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n", cReadTotal, cbReadTotal, rc));
+ LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
+ cReadTotal, cbReadTotal, rc));
}
LogFlowFuncLeaveRC(rc);
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
- */
static DECLCALLBACK(void) drvHostOSSAudioShutdown(PPDMIHOSTAUDIO pInterface)
{
- RT_NOREF(pInterface);
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostOSSAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
- RT_NOREF(enmDir);
-
- return PDMAUDIOBACKENDSTS_RUNNING;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvHostOSSAudioStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
-
- int rc;
- if (pCfgReq->enmDir == PDMAUDIODIR_IN)
- rc = ossCreateStreamIn(pStream, pCfgReq, pCfgAcq);
- else
- rc = ossCreateStreamOut(pStream, pCfgReq, pCfgAcq);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvHostOSSAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = ossDestroyStreamIn(pStream);
- else
- rc = ossDestroyStreamOut(pStream);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
- */
-static DECLCALLBACK(int) drvHostOSSAudioStreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = ossControlStreamIn(/*pInterface, pStream, enmStreamCmd*/);
- else
- rc = ossControlStreamOut(pStream, enmStreamCmd);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
- */
-static DECLCALLBACK(int) drvHostOSSAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
-
- /* Nothing to do here for OSS. */
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostOSSAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- RT_NOREF(pInterface);
- RT_NOREF(pStream);
-
- PDMAUDIOSTRMSTS strmSts = PDMAUDIOSTRMSTS_FLAG_INITIALIZED
- | PDMAUDIOSTRMSTS_FLAG_ENABLED;
-
- strmSts |= pStream->enmDir == PDMAUDIODIR_IN
- ? PDMAUDIOSTRMSTS_FLAG_DATA_READABLE
- : PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
-
- return strmSts;
+ NOREF(pInterface);
}
/**
@@ -1094,9 +923,8 @@ static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostOSSAudioStreamGetStatus(PPDMIHOSTAUD
*/
static DECLCALLBACK(void *) drvHostOSSAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTOSSAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
-
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVHOSTOSSAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
@@ -1111,7 +939,6 @@ static DECLCALLBACK(void *) drvHostOSSAudioQueryInterface(PPDMIBASE pInterface,
static DECLCALLBACK(int) drvHostOSSAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
RT_NOREF(pCfg, fFlags);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
PDRVHOSTOSSAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
LogRel(("Audio: Initializing OSS driver\n"));
@@ -1177,4 +1004,3 @@ const PDMDRVREG g_DrvHostOSSAudio =
/* u32EndVersion */
PDM_DRVREG_VERSION
};
-
diff --git a/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp b/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
index d234b14..951ab17 100644
--- a/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
+++ b/src/VBox/Devices/Audio/DrvHostPulseAudio.cpp
@@ -21,7 +21,6 @@
*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
#include <VBox/log.h>
-#include <VBox/vmm/pdmaudioifs.h>
#include <stdio.h>
@@ -41,10 +40,6 @@ RT_C_DECLS_END
#include "VBoxDD.h"
-
-/*********************************************************************************************************************************
-* Defines *
-*********************************************************************************************************************************/
#define VBOX_PULSEAUDIO_MAX_LOG_REL_ERRORS 32 /** @todo Make this configurable thru driver options. */
#ifndef PA_STREAM_NOFLAGS
@@ -55,19 +50,14 @@ RT_C_DECLS_END
# define PA_CONTEXT_NOFLAGS (pa_context_flags_t)0x0000U /* since 0.9.19 */
#endif
-/** No flags specified. */
-#define PULSEAUDIOENUMCBFLAGS_NONE 0
-/** (Release) log found devices. */
-#define PULSEAUDIOENUMCBFLAGS_LOG RT_BIT(0)
-
-/** Makes DRVHOSTPULSEAUDIO out of PDMIHOSTAUDIO. */
-#define PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface) \
- ( (PDRVHOSTPULSEAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPULSEAUDIO, IHostAudio)) )
-
-
-/*********************************************************************************************************************************
-* Structures *
-*********************************************************************************************************************************/
+/*
+ * We use a g_pMainLoop in a separate thread g_pContext. We have to call functions for
+ * manipulating objects either from callback functions or we have to protect
+ * these functions by pa_threaded_mainloop_lock() / pa_threaded_mainloop_unlock().
+ */
+static struct pa_threaded_mainloop *g_pMainLoop;
+static struct pa_context *g_pContext;
+static volatile bool g_fAbortMainLoop;
/**
* Host Pulse audio driver instance data.
@@ -76,30 +66,25 @@ RT_C_DECLS_END
typedef struct DRVHOSTPULSEAUDIO
{
/** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to PulseAudio's threaded main loop. */
- pa_threaded_mainloop *pMainLoop;
- /**
- * Pointer to our PulseAudio context.
- * Note: We use a pMainLoop in a separate thread (pContext).
- * So either use callback functions or protect these functions
- * by pa_threaded_mainloop_lock() / pa_threaded_mainloop_unlock().
- */
- pa_context *pContext;
- /** Shutdown indicator. */
- volatile bool fAbortLoop;
+ PPDMDRVINS pDrvIns;
/** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
+ PDMIHOSTAUDIO IHostAudio;
/** Error count for not flooding the release log.
- * Specify UINT32_MAX for unlimited logging. */
- uint32_t cLogErrors;
+ * UINT32_MAX for unlimited logging. */
+ uint32_t cLogErrors;
+ /** Configuration option: stream name. */
+ char *pszStreamName;
} DRVHOSTPULSEAUDIO, *PDRVHOSTPULSEAUDIO;
typedef struct PULSEAUDIOSTREAM
{
- /** Associated host input/output stream.
- * Note: Always must come first! */
- PDMAUDIOSTREAM Stream;
+ /** Must come first, as this struct might be
+ * casted to one of these structs. */
+ union
+ {
+ PDMAUDIOHSTSTRMIN In;
+ PDMAUDIOHSTSTRMOUT Out;
+ };
/** Pointer to driver instance. */
PDRVHOSTPULSEAUDIO pDrv;
/** DAC/ADC buffer. */
@@ -107,7 +92,7 @@ typedef struct PULSEAUDIOSTREAM
/** Size (in bytes) of DAC/ADC buffer. */
uint32_t cbPCMBuf;
/** Pointer to opaque PulseAudio stream. */
- pa_stream *pPAStream;
+ pa_stream *pStream;
/** Pulse sample format and attribute specification. */
pa_sample_spec SampleSpec;
/** Pulse playback and buffer metrics. */
@@ -138,62 +123,35 @@ static PULSEAUDIOCFG s_pulseCfg =
100 /* buffer_msecs_in */
};
-/**
- * Callback context for server enumeration callbacks.
- */
-typedef struct PULSEAUDIOENUMCBCTX
-{
- /** Pointer to host backend driver. */
- PDRVHOSTPULSEAUDIO pDrv;
- /** Enumeration flags. */
- uint32_t fFlags;
- /** Number of found input devices. */
- uint8_t cDevIn;
- /** Number of found output devices. */
- uint8_t cDevOut;
- /** Name of default sink being used. Must be free'd using RTStrFree(). */
- char *pszDefaultSink;
- /** Name of default source being used. Must be free'd using RTStrFree(). */
- char *pszDefaultSource;
-} PULSEAUDIOENUMCBCTX, *PPULSEAUDIOENUMCBCTX;
-
-
-/*********************************************************************************************************************************
-* Prototypes *
-*********************************************************************************************************************************/
-
-static int paEnumerate(PDRVHOSTPULSEAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum);
-static int paError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg);
-static void paStreamCbSuccess(pa_stream *pStream, int fSuccess, void *pvContext);
-
+/** Makes DRVHOSTPULSEAUDIO out of PDMIHOSTAUDIO. */
+#define PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface) \
+ ( (PDRVHOSTPULSEAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPULSEAUDIO, IHostAudio)) )
+static int drvHostPulseAudioError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg);
+static void drvHostPulseAudioCbSuccess(pa_stream *pStream, int fSuccess, void *pvContext);
/**
* Signal the main loop to abort. Just signalling isn't sufficient as the
* mainloop might not have been entered yet.
*/
-static void paSignalWaiter(PDRVHOSTPULSEAUDIO pThis)
+static void drvHostPulseAudioAbortMainLoop(void)
{
- if (!pThis)
- return;
-
- pThis->fAbortLoop = true;
- pa_threaded_mainloop_signal(pThis->pMainLoop, 0);
+ g_fAbortMainLoop = true;
+ pa_threaded_mainloop_signal(g_pMainLoop, 0);
}
-
-static pa_sample_format_t paFmtToPulse(PDMAUDIOFMT fmt)
+static pa_sample_format_t drvHostPulseAudioFmtToPulse(PDMAUDIOFMT fmt)
{
switch (fmt)
{
- case PDMAUDIOFMT_U8:
+ case AUD_FMT_U8:
return PA_SAMPLE_U8;
- case PDMAUDIOFMT_S16:
+ case AUD_FMT_S16:
return PA_SAMPLE_S16LE;
#ifdef PA_SAMPLE_S32LE
- case PDMAUDIOFMT_S32:
+ case AUD_FMT_S32:
return PA_SAMPLE_S32LE;
#endif
default:
@@ -204,37 +162,36 @@ static pa_sample_format_t paFmtToPulse(PDMAUDIOFMT fmt)
return PA_SAMPLE_U8;
}
-
-static int paPulseToFmt(pa_sample_format_t pulsefmt,
- PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
+static int drvHostPulseAudioPulseToFmt(pa_sample_format_t pulsefmt,
+ PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
{
switch (pulsefmt)
{
case PA_SAMPLE_U8:
- *pFmt = PDMAUDIOFMT_U8;
+ *pFmt = AUD_FMT_U8;
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
case PA_SAMPLE_S16LE:
- *pFmt = PDMAUDIOFMT_S16;
+ *pFmt = AUD_FMT_S16;
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
case PA_SAMPLE_S16BE:
- *pFmt = PDMAUDIOFMT_S16;
+ *pFmt = AUD_FMT_S16;
*pEndianness = PDMAUDIOENDIANNESS_BIG;
break;
#ifdef PA_SAMPLE_S32LE
case PA_SAMPLE_S32LE:
- *pFmt = PDMAUDIOFMT_S32;
+ *pFmt = AUD_FMT_S32;
*pEndianness = PDMAUDIOENDIANNESS_LITTLE;
break;
#endif
#ifdef PA_SAMPLE_S32BE
case PA_SAMPLE_S32BE:
- *pFmt = PDMAUDIOFMT_S32;
+ *pFmt = AUD_FMT_S32;
*pEndianness = PDMAUDIOENDIANNESS_BIG;
break;
#endif
@@ -247,67 +204,55 @@ static int paPulseToFmt(pa_sample_format_t pulsefmt,
return VINF_SUCCESS;
}
-
/**
* Synchronously wait until an operation completed.
*/
-static int paWaitForEx(PDRVHOSTPULSEAUDIO pThis, pa_operation *pOP, RTMSINTERVAL cMsTimeout)
+static int drvHostPulseAudioWaitFor(pa_operation *pOP, RTMSINTERVAL cMsTimeout)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pOP, VERR_INVALID_POINTER);
+ AssertPtrReturn(pOP, VERR_INVALID_POINTER);
int rc = VINF_SUCCESS;
-
- uint64_t u64StartMs = RTTimeMilliTS();
- while (pa_operation_get_state(pOP) == PA_OPERATION_RUNNING)
+ if (pOP)
{
- if (!pThis->fAbortLoop)
+ uint64_t u64StartMs = RTTimeMilliTS();
+ while (pa_operation_get_state(pOP) == PA_OPERATION_RUNNING)
{
- AssertPtr(pThis->pMainLoop);
- pa_threaded_mainloop_wait(pThis->pMainLoop);
- }
- pThis->fAbortLoop = false;
+ if (!g_fAbortMainLoop)
+ pa_threaded_mainloop_wait(g_pMainLoop);
+ g_fAbortMainLoop = false;
- uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
- if (u64ElapsedMs >= cMsTimeout)
- {
- rc = VERR_TIMEOUT;
- break;
+ uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
+ if (u64ElapsedMs >= cMsTimeout)
+ {
+ rc = VERR_TIMEOUT;
+ break;
+ }
}
- }
- pa_operation_unref(pOP);
+ pa_operation_unref(pOP);
+ }
return rc;
}
-
-static int paWaitFor(PDRVHOSTPULSEAUDIO pThis, pa_operation *pOP)
-{
- return paWaitForEx(pThis, pOP, 10 * 1000 /* 10s timeout */);
-}
-
-
/**
* Context status changed.
*/
-static void paContextCbStateChanged(pa_context *pCtx, void *pvUser)
+static void drvHostPulseAudioCbCtxState(pa_context *pContext, void *pvUser)
{
- AssertPtrReturnVoid(pCtx);
-
- PDRVHOSTPULSEAUDIO pThis = (PDRVHOSTPULSEAUDIO)pvUser;
- AssertPtrReturnVoid(pThis);
+ AssertPtrReturnVoid(pContext);
+ NOREF(pvUser);
- switch (pa_context_get_state(pCtx))
+ switch (pa_context_get_state(pContext))
{
case PA_CONTEXT_READY:
case PA_CONTEXT_TERMINATED:
- paSignalWaiter(pThis);
+ drvHostPulseAudioAbortMainLoop();
break;
case PA_CONTEXT_FAILED:
- LogRel(("PulseAudio: Audio context has failed, stopping\n"));
- paSignalWaiter(pThis);
+ LogRel(("PulseAudio: Audio input/output stopped!\n"));
+ drvHostPulseAudioAbortMainLoop();
break;
default:
@@ -315,50 +260,43 @@ static void paContextCbStateChanged(pa_context *pCtx, void *pvUser)
}
}
-
/**
* Callback called when our pa_stream_drain operation was completed.
*/
-static void paStreamCbDrain(pa_stream *pStream, int fSuccess, void *pvUser)
+static void drvHostPulseAudioCbStreamDrain(pa_stream *pStream, int fSuccess, void *pvContext)
{
AssertPtrReturnVoid(pStream);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvUser;
+ PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvContext;
AssertPtrReturnVoid(pStrm);
pStrm->fOpSuccess = fSuccess;
if (fSuccess)
{
pa_operation_unref(pa_stream_cork(pStream, 1,
- paStreamCbSuccess, pvUser));
+ drvHostPulseAudioCbSuccess, pvContext));
}
else
- paError(pStrm->pDrv, "Failed to drain stream");
+ drvHostPulseAudioError(pStrm->pDrv, "Failed to drain stream");
- if (pStrm->pDrainOp)
- {
- pa_operation_unref(pStrm->pDrainOp);
- pStrm->pDrainOp = NULL;
- }
+ pa_operation_unref(pStrm->pDrainOp);
+ pStrm->pDrainOp = NULL;
}
-
/**
* Stream status changed.
*/
-static void paStreamCbStateChanged(pa_stream *pStream, void *pvUser)
+static void drvHostPulseAudioCbStreamState(pa_stream *pStream, void *pvContext)
{
AssertPtrReturnVoid(pStream);
-
- PDRVHOSTPULSEAUDIO pThis = (PDRVHOSTPULSEAUDIO)pvUser;
- AssertPtrReturnVoid(pThis);
+ NOREF(pvContext);
switch (pa_stream_get_state(pStream))
{
case PA_STREAM_READY:
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED:
- paSignalWaiter(pThis);
+ drvHostPulseAudioAbortMainLoop();
break;
default:
@@ -366,32 +304,29 @@ static void paStreamCbStateChanged(pa_stream *pStream, void *pvUser)
}
}
-
-static void paStreamCbSuccess(pa_stream *pStream, int fSuccess, void *pvUser)
+static void drvHostPulseAudioCbSuccess(pa_stream *pStream, int fSuccess, void *pvContext)
{
AssertPtrReturnVoid(pStream);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvUser;
+ PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvContext;
AssertPtrReturnVoid(pStrm);
pStrm->fOpSuccess = fSuccess;
if (fSuccess)
- paSignalWaiter(pStrm->pDrv);
+ drvHostPulseAudioAbortMainLoop();
else
- paError(pStrm->pDrv, "Failed to finish stream operation");
+ drvHostPulseAudioError(pStrm->pDrv, "Failed to finish stream operation");
}
-
-static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
- pa_sample_spec *pSampleSpec, pa_buffer_attr *pBufAttr,
- pa_stream **ppStream)
+static int drvHostPulseAudioOpen(bool fIn, const char *pszName,
+ pa_sample_spec *pSampleSpec, pa_buffer_attr *pBufAttr,
+ pa_stream **ppStream)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszName, VERR_INVALID_POINTER);
AssertPtrReturn(pSampleSpec, VERR_INVALID_POINTER);
- AssertPtrReturn(pBufAttr, VERR_INVALID_POINTER);
- AssertPtrReturn(ppStream, VERR_INVALID_POINTER);
+ AssertPtrReturn(pBufAttr, VERR_INVALID_POINTER);
+ AssertPtrReturn(ppStream, VERR_INVALID_POINTER);
if (!pa_sample_spec_valid(pSampleSpec))
{
@@ -409,12 +344,11 @@ static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
pszName, pSampleSpec->rate, pSampleSpec->channels,
pa_sample_format_to_string(pSampleSpec->format)));
- pa_threaded_mainloop_lock(pThis->pMainLoop);
+ pa_threaded_mainloop_lock(g_pMainLoop);
do
{
- /** @todo r=andy Use pa_stream_new_with_proplist instead. */
- if (!(pStream = pa_stream_new(pThis->pContext, pszName, pSampleSpec,
+ if (!(pStream = pa_stream_new(g_pContext, pszName, pSampleSpec,
NULL /* pa_channel_map */)))
{
LogRel(("PulseAudio: Could not create stream \"%s\"\n", pszName));
@@ -422,7 +356,7 @@ static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
break;
}
- pa_stream_set_state_callback(pStream, paStreamCbStateChanged, pThis);
+ pa_stream_set_state_callback(pStream, drvHostPulseAudioCbStreamState, NULL);
#if PA_API_VERSION >= 12
/* XXX */
@@ -444,7 +378,7 @@ static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
if (pa_stream_connect_record(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags) < 0)
{
LogRel(("PulseAudio: Could not connect input stream \"%s\": %s\n",
- pszName, pa_strerror(pa_context_errno(pThis->pContext))));
+ pszName, pa_strerror(pa_context_errno(g_pContext))));
rc = VERR_AUDIO_BACKEND_INIT_FAILED;
break;
}
@@ -458,7 +392,7 @@ static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
/*cvolume=*/NULL, /*sync_stream=*/NULL) < 0)
{
LogRel(("PulseAudio: Could not connect playback stream \"%s\": %s\n",
- pszName, pa_strerror(pa_context_errno(pThis->pContext))));
+ pszName, pa_strerror(pa_context_errno(g_pContext))));
rc = VERR_AUDIO_BACKEND_INIT_FAILED;
break;
}
@@ -467,17 +401,18 @@ static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
/* Wait until the stream is ready. */
for (;;)
{
- if (!pThis->fAbortLoop)
- pa_threaded_mainloop_wait(pThis->pMainLoop);
- pThis->fAbortLoop = false;
+ if (!g_fAbortMainLoop)
+ pa_threaded_mainloop_wait(g_pMainLoop);
+ g_fAbortMainLoop = false;
- pa_stream_state_t streamSt = pa_stream_get_state(pStream);
- if (streamSt == PA_STREAM_READY)
+ pa_stream_state_t sstate = pa_stream_get_state(pStream);
+ if (sstate == PA_STREAM_READY)
break;
- else if ( streamSt == PA_STREAM_FAILED
- || streamSt == PA_STREAM_TERMINATED)
+ else if ( sstate == PA_STREAM_FAILED
+ || sstate == PA_STREAM_TERMINATED)
{
- LogRel(("PulseAudio: Failed to initialize stream \"%s\" (state %ld)\n", pszName, streamSt));
+ LogRel(("PulseAudio: Failed to initialize stream \"%s\" (state %ld)\n",
+ pszName, sstate));
rc = VERR_AUDIO_BACKEND_INIT_FAILED;
break;
}
@@ -504,7 +439,7 @@ static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
&& pStream)
pa_stream_disconnect(pStream);
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
if (RT_FAILURE(rc))
{
@@ -518,15 +453,9 @@ static int paStreamOpen(PDRVHOSTPULSEAUDIO pThis, bool fIn, const char *pszName,
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
- */
static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
-
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
+ NOREF(pInterface);
LogFlowFuncEnter();
@@ -537,60 +466,56 @@ static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface)
return rc;
}
- pThis->fAbortLoop = false;
- pThis->pMainLoop = NULL;
-
bool fLocked = false;
do
{
- if (!(pThis->pMainLoop = pa_threaded_mainloop_new()))
+ if (!(g_pMainLoop = pa_threaded_mainloop_new()))
{
LogRel(("PulseAudio: Failed to allocate main loop: %s\n",
- pa_strerror(pa_context_errno(pThis->pContext))));
+ pa_strerror(pa_context_errno(g_pContext))));
rc = VERR_NO_MEMORY;
break;
}
- if (!(pThis->pContext = pa_context_new(pa_threaded_mainloop_get_api(pThis->pMainLoop), "VirtualBox")))
+ if (!(g_pContext = pa_context_new(pa_threaded_mainloop_get_api(g_pMainLoop), "VirtualBox")))
{
LogRel(("PulseAudio: Failed to allocate context: %s\n",
- pa_strerror(pa_context_errno(pThis->pContext))));
+ pa_strerror(pa_context_errno(g_pContext))));
rc = VERR_NO_MEMORY;
break;
}
- if (pa_threaded_mainloop_start(pThis->pMainLoop) < 0)
+ if (pa_threaded_mainloop_start(g_pMainLoop) < 0)
{
LogRel(("PulseAudio: Failed to start threaded mainloop: %s\n",
- pa_strerror(pa_context_errno(pThis->pContext))));
+ pa_strerror(pa_context_errno(g_pContext))));
rc = VERR_AUDIO_BACKEND_INIT_FAILED;
break;
}
- /* Install a global callback to known if something happens to our acquired context. */
- pa_context_set_state_callback(pThis->pContext, paContextCbStateChanged, pThis /* pvUserData */);
-
- pa_threaded_mainloop_lock(pThis->pMainLoop);
+ g_fAbortMainLoop = false;
+ pa_context_set_state_callback(g_pContext, drvHostPulseAudioCbCtxState, NULL);
+ pa_threaded_mainloop_lock(g_pMainLoop);
fLocked = true;
- if (pa_context_connect(pThis->pContext, NULL /* pszServer */,
+ if (pa_context_connect(g_pContext, NULL /* pszServer */,
PA_CONTEXT_NOFLAGS, NULL) < 0)
{
LogRel(("PulseAudio: Failed to connect to server: %s\n",
- pa_strerror(pa_context_errno(pThis->pContext))));
+ pa_strerror(pa_context_errno(g_pContext))));
rc = VERR_AUDIO_BACKEND_INIT_FAILED;
break;
}
- /* Wait until the pThis->pContext is ready. */
+ /* Wait until the g_pContext is ready */
for (;;)
{
- if (!pThis->fAbortLoop)
- pa_threaded_mainloop_wait(pThis->pMainLoop);
- pThis->fAbortLoop = false;
+ if (!g_fAbortMainLoop)
+ pa_threaded_mainloop_wait(g_pMainLoop);
+ g_fAbortMainLoop = false;
- pa_context_state_t cstate = pa_context_get_state(pThis->pContext);
+ pa_context_state_t cstate = pa_context_get_state(g_pContext);
if (cstate == PA_CONTEXT_READY)
break;
else if ( cstate == PA_CONTEXT_TERMINATED
@@ -605,24 +530,24 @@ static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface)
while (0);
if (fLocked)
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
if (RT_FAILURE(rc))
{
- if (pThis->pMainLoop)
- pa_threaded_mainloop_stop(pThis->pMainLoop);
+ if (g_pMainLoop)
+ pa_threaded_mainloop_stop(g_pMainLoop);
- if (pThis->pContext)
+ if (g_pContext)
{
- pa_context_disconnect(pThis->pContext);
- pa_context_unref(pThis->pContext);
- pThis->pContext = NULL;
+ pa_context_disconnect(g_pContext);
+ pa_context_unref(g_pContext);
+ g_pContext = NULL;
}
- if (pThis->pMainLoop)
+ if (g_pMainLoop)
{
- pa_threaded_mainloop_free(pThis->pMainLoop);
- pThis->pMainLoop = NULL;
+ pa_threaded_mainloop_free(g_pMainLoop);
+ g_pMainLoop = NULL;
}
}
@@ -630,60 +555,76 @@ static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface)
return rc;
}
-
-static int paCreateStreamOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostPulseAudioInitOut(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ uint32_t *pcSamples)
{
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pStream;
+ RT_NOREF(pCfgAcq);
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+ /* pcSamples is optional. */
+
+ PDRVHOSTPULSEAUDIO pDrv = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
+ PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
LogFlowFuncEnter();
- pStrm->pDrainOp = NULL;
+ pThisStrmOut->pDrainOp = NULL;
- pStrm->SampleSpec.format = paFmtToPulse(pCfgReq->enmFormat);
- pStrm->SampleSpec.rate = pCfgReq->uHz;
- pStrm->SampleSpec.channels = pCfgReq->cChannels;
+ pThisStrmOut->SampleSpec.format = drvHostPulseAudioFmtToPulse(pCfgReq->enmFormat);
+ pThisStrmOut->SampleSpec.rate = pCfgReq->uHz;
+ pThisStrmOut->SampleSpec.channels = pCfgReq->cChannels;
/* Note that setting maxlength to -1 does not work on PulseAudio servers
* older than 0.9.10. So use the suggested value of 3/2 of tlength */
- pStrm->BufAttr.tlength = (pa_bytes_per_second(&pStrm->SampleSpec)
+ pThisStrmOut->BufAttr.tlength = (pa_bytes_per_second(&pThisStrmOut->SampleSpec)
* s_pulseCfg.buffer_msecs_out) / 1000;
- pStrm->BufAttr.maxlength = (pStrm->BufAttr.tlength * 3) / 2;
- pStrm->BufAttr.prebuf = -1; /* Same as tlength */
- pStrm->BufAttr.minreq = -1;
+ pThisStrmOut->BufAttr.maxlength = (pThisStrmOut->BufAttr.tlength * 3) / 2;
+ pThisStrmOut->BufAttr.prebuf = -1; /* Same as tlength */
+ pThisStrmOut->BufAttr.minreq = -1; /* Pulse should set something sensible for minreq on it's own */
/* Note that the struct BufAttr is updated to the obtained values after this call! */
- int rc = paStreamOpen(pThis, false /* fIn */, "PulseAudio (Out)", &pStrm->SampleSpec, &pStrm->BufAttr, &pStrm->pPAStream);
+ char achName[64];
+ RTStrPrintf(achName, sizeof(achName), "%.32s (out)", pDrv->pszStreamName);
+ int rc = drvHostPulseAudioOpen(false /* fIn */, achName, &pThisStrmOut->SampleSpec, &pThisStrmOut->BufAttr,
+ &pThisStrmOut->pStream);
if (RT_FAILURE(rc))
return rc;
- rc = paPulseToFmt(pStrm->SampleSpec.format,
- &pCfgAcq->enmFormat, &pCfgAcq->enmEndianness);
+ PDMAUDIOSTREAMCFG streamCfg;
+ rc = drvHostPulseAudioPulseToFmt(pThisStrmOut->SampleSpec.format,
+ &streamCfg.enmFormat, &streamCfg.enmEndianness);
if (RT_FAILURE(rc))
{
- LogRel(("PulseAudio: Cannot find audio output format %ld\n", pStrm->SampleSpec.format));
+ LogRel(("PulseAudio: Cannot find audio output format %ld\n", pThisStrmOut->SampleSpec.format));
return rc;
}
- pCfgAcq->uHz = pStrm->SampleSpec.rate;
- pCfgAcq->cChannels = pStrm->SampleSpec.channels;
+ streamCfg.uHz = pThisStrmOut->SampleSpec.rate;
+ streamCfg.cChannels = pThisStrmOut->SampleSpec.channels;
- PDMAUDIOPCMPROPS Props;
- rc = DrvAudioHlpStreamCfgToProps(pCfgAcq, &Props);
+ rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
if (RT_SUCCESS(rc))
{
- uint32_t cbBuf = RT_MIN(pStrm->BufAttr.tlength * 2,
- pStrm->BufAttr.maxlength); /** @todo Make this configurable! */
+ uint32_t cbBuf = RT_MIN(pThisStrmOut->BufAttr.tlength * 2,
+ pThisStrmOut->BufAttr.maxlength); /** @todo Make this configurable! */
if (cbBuf)
{
- pStrm->pvPCMBuf = RTMemAllocZ(cbBuf);
- if (pStrm->pvPCMBuf)
+ pThisStrmOut->pvPCMBuf = RTMemAllocZ(cbBuf);
+ if (pThisStrmOut->pvPCMBuf)
{
- pStrm->cbPCMBuf = cbBuf;
- pStrm->pDrv = pThis;
+ pThisStrmOut->cbPCMBuf = cbBuf;
+
+ uint32_t cSamples = cbBuf >> pHstStrmOut->Props.cShift;
+ if (pcSamples)
+ *pcSamples = cSamples;
- pCfgAcq->cSampleBufferSize = cbBuf >> Props.cShift;
+ /* Save pointer to driver instance. */
+ pThisStrmOut->pDrv = pDrv;
+
+ LogFunc(("cbBuf=%RU32, cSamples=%RU32\n", cbBuf, cSamples));
}
else
rc = VERR_NO_MEMORY;
@@ -696,156 +637,176 @@ static int paCreateStreamOut(PPDMIHOSTAUDIO pInterface,
return rc;
}
+static DECLCALLBACK(bool) drvHostPulseAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
+{
+ NOREF(pInterface);
+ NOREF(enmDir);
+ return true; /* Always all enabled. */
+}
-static int paCreateStreamIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvHostPulseAudioInitIn(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ PDMAUDIORECSOURCE enmRecSource,
+ uint32_t *pcSamples)
{
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pPAStrm = (PPULSEAUDIOSTREAM)pStream;
+ RT_NOREF(pCfgAcq, enmRecSource);
+ AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
+ /* pcSamples is optional. */
+
+ PDRVHOSTPULSEAUDIO pDrv = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
+ PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
+
+ LogFunc(("enmRecSrc=%ld\n", enmRecSource));
- pPAStrm->SampleSpec.format = paFmtToPulse(pCfgReq->enmFormat);
- pPAStrm->SampleSpec.rate = pCfgReq->uHz;
- pPAStrm->SampleSpec.channels = pCfgReq->cChannels;
+ pThisStrmIn->SampleSpec.format = drvHostPulseAudioFmtToPulse(pCfgReq->enmFormat);
+ pThisStrmIn->SampleSpec.rate = pCfgReq->uHz;
+ pThisStrmIn->SampleSpec.channels = pCfgReq->cChannels;
- /** @todo Check these values! */
- pPAStrm->BufAttr.fragsize = (pa_bytes_per_second(&pPAStrm->SampleSpec) * s_pulseCfg.buffer_msecs_in) / 1000;
- pPAStrm->BufAttr.maxlength = (pPAStrm->BufAttr.fragsize * 3) / 2;
+ /* XXX check these values */
+ pThisStrmIn->BufAttr.fragsize = (pa_bytes_per_second(&pThisStrmIn->SampleSpec)
+ * s_pulseCfg.buffer_msecs_in) / 1000;
+ pThisStrmIn->BufAttr.maxlength = (pThisStrmIn->BufAttr.fragsize * 3) / 2;
+ /* Note: Other members of pa_buffer_attr are ignored for record streams. */
- /* Note: Other members of BufAttr are ignored for record streams. */
- int rc = paStreamOpen(pThis, true /* fIn */, "PulseAudio (In)", &pPAStrm->SampleSpec, &pPAStrm->BufAttr,
- &pPAStrm->pPAStream);
+ char achName[64];
+ RTStrPrintf(achName, sizeof(achName), "%.32s (in)", pDrv->pszStreamName);
+ int rc = drvHostPulseAudioOpen(true /* fIn */, achName, &pThisStrmIn->SampleSpec, &pThisStrmIn->BufAttr,
+ &pThisStrmIn->pStream);
if (RT_FAILURE(rc))
return rc;
- rc = paPulseToFmt(pPAStrm->SampleSpec.format, &pCfgAcq->enmFormat,
- &pCfgAcq->enmEndianness);
+ PDMAUDIOSTREAMCFG streamCfg;
+ rc = drvHostPulseAudioPulseToFmt(pThisStrmIn->SampleSpec.format, &streamCfg.enmFormat,
+ &streamCfg.enmEndianness);
if (RT_FAILURE(rc))
{
- LogRel(("PulseAudio: Cannot find audio capture format %ld\n", pPAStrm->SampleSpec.format));
+ LogRel(("PulseAudio: Cannot find audio capture format %ld\n", pThisStrmIn->SampleSpec.format));
return rc;
}
- PDMAUDIOPCMPROPS Props;
- rc = DrvAudioHlpStreamCfgToProps(pCfgAcq, &Props);
+ streamCfg.uHz = pThisStrmIn->SampleSpec.rate;
+ streamCfg.cChannels = pThisStrmIn->SampleSpec.channels;
+
+ rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
if (RT_SUCCESS(rc))
{
- pPAStrm->pDrv = pThis;
- pPAStrm->pu8PeekBuf = NULL;
+ uint32_t cSamples = RT_MIN(pThisStrmIn->BufAttr.fragsize * 10, pThisStrmIn->BufAttr.maxlength)
+ >> pHstStrmIn->Props.cShift;
+ LogFunc(("cShift=%RU8, cSamples=%RU32\n", pHstStrmIn->Props.cShift, cSamples));
+
+ if (pcSamples)
+ *pcSamples = cSamples;
- pCfgAcq->uHz = pPAStrm->SampleSpec.rate;
- pCfgAcq->cChannels = pPAStrm->SampleSpec.channels;
- pCfgAcq->cSampleBufferSize = RT_MIN(pPAStrm->BufAttr.fragsize * 10, pPAStrm->BufAttr.maxlength) >> Props.cShift;
+ /* Save pointer to driver instance. */
+ pThisStrmIn->pDrv = pDrv;
+
+ pThisStrmIn->pu8PeekBuf = NULL;
}
LogFlowFuncLeaveRC(rc);
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
- */
-static DECLCALLBACK(int) drvHostPulseAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static DECLCALLBACK(int) drvHostPulseAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ uint32_t *pcSamplesCaptured)
{
- RT_NOREF(pvBuf, cbBuf);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbRead is optional. */
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ /* pcSamplesPlayed is optional. */
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pStream;
+ PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
/* We should only call pa_stream_readable_size() once and trust the first value. */
- pa_threaded_mainloop_lock(pThis->pMainLoop);
- size_t cbAvail = pa_stream_readable_size(pStrm->pPAStream);
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_lock(g_pMainLoop);
+ size_t cbAvail = pa_stream_readable_size(pThisStrmIn->pStream);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
if (cbAvail == (size_t)-1)
- return paError(pStrm->pDrv, "Failed to determine input data size");
+ return drvHostPulseAudioError(pThisStrmIn->pDrv, "Failed to determine input data size");
/* If the buffer was not dropped last call, add what remains. */
- if (pStrm->pu8PeekBuf)
+ if (pThisStrmIn->pu8PeekBuf)
{
- Assert(pStrm->cbPeekBuf >= pStrm->offPeekBuf);
- cbAvail += (pStrm->cbPeekBuf - pStrm->offPeekBuf);
+ Assert(pThisStrmIn->cbPeekBuf >= pThisStrmIn->offPeekBuf);
+ cbAvail += (pThisStrmIn->cbPeekBuf - pThisStrmIn->offPeekBuf);
}
- LogFlowFunc(("cbAvail=%zu\n", cbAvail));
-
if (!cbAvail) /* No data? Bail out. */
{
- if (pcbRead)
- *pcbRead = 0;
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = 0;
return VINF_SUCCESS;
}
int rc = VINF_SUCCESS;
-
- size_t cbToRead = RT_MIN(cbAvail, AudioMixBufFreeBytes(&pStream->MixBuf));
+ size_t cbToRead = RT_MIN(cbAvail, AudioMixBufFreeBytes(&pHstStrmIn->MixBuf));
LogFlowFunc(("cbToRead=%zu, cbAvail=%zu, offPeekBuf=%zu, cbPeekBuf=%zu\n",
- cbToRead, cbAvail, pStrm->offPeekBuf, pStrm->cbPeekBuf));
+ cbToRead, cbAvail, pThisStrmIn->offPeekBuf, pThisStrmIn->cbPeekBuf));
uint32_t cWrittenTotal = 0;
while (cbToRead)
{
/* If there is no data, do another peek. */
- if (!pStrm->pu8PeekBuf)
+ if (!pThisStrmIn->pu8PeekBuf)
{
- pa_threaded_mainloop_lock(pThis->pMainLoop);
- pa_stream_peek(pStrm->pPAStream,
- (const void**)&pStrm->pu8PeekBuf, &pStrm->cbPeekBuf);
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_lock(g_pMainLoop);
+ pa_stream_peek(pThisStrmIn->pStream,
+ (const void**)&pThisStrmIn->pu8PeekBuf, &pThisStrmIn->cbPeekBuf);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
- pStrm->offPeekBuf = 0;
+ pThisStrmIn->offPeekBuf = 0;
/* No data anymore?
* Note: If there's a data hole (cbPeekBuf then contains the length of the hole)
* we need to drop the stream lateron. */
- if ( !pStrm->pu8PeekBuf
- && !pStrm->cbPeekBuf)
+ if ( !pThisStrmIn->pu8PeekBuf
+ && !pThisStrmIn->cbPeekBuf)
{
break;
}
}
- Assert(pStrm->cbPeekBuf >= pStrm->offPeekBuf);
- size_t cbToWrite = RT_MIN(pStrm->cbPeekBuf - pStrm->offPeekBuf, cbToRead);
+ Assert(pThisStrmIn->cbPeekBuf >= pThisStrmIn->offPeekBuf);
+ size_t cbToWrite = RT_MIN(pThisStrmIn->cbPeekBuf - pThisStrmIn->offPeekBuf, cbToRead);
LogFlowFunc(("cbToRead=%zu, cbToWrite=%zu, offPeekBuf=%zu, cbPeekBuf=%zu, pu8PeekBuf=%p\n",
cbToRead, cbToWrite,
- pStrm->offPeekBuf, pStrm->cbPeekBuf, pStrm->pu8PeekBuf));
+ pThisStrmIn->offPeekBuf, pThisStrmIn->cbPeekBuf, pThisStrmIn->pu8PeekBuf));
if (cbToWrite)
{
uint32_t cWritten;
- rc = AudioMixBufWriteCirc(&pStream->MixBuf,
- pStrm->pu8PeekBuf + pStrm->offPeekBuf,
+ rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
+ pThisStrmIn->pu8PeekBuf + pThisStrmIn->offPeekBuf,
cbToWrite, &cWritten);
if (RT_FAILURE(rc))
break;
- uint32_t cbWritten = AUDIOMIXBUF_S2B(&pStream->MixBuf, cWritten);
+ uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
Assert(cbToRead >= cbWritten);
cbToRead -= cbWritten;
cWrittenTotal += cWritten;
- pStrm->offPeekBuf += cbWritten;
+ pThisStrmIn->offPeekBuf += cbWritten;
}
if (/* Nothing to write anymore? Drop the buffer. */
!cbToWrite
/* Was there a hole in the peeking buffer? Drop it. */
- || !pStrm->pu8PeekBuf
+ || !pThisStrmIn->pu8PeekBuf
/* If the buffer is done, drop it. */
- || pStrm->offPeekBuf == pStrm->cbPeekBuf)
+ || pThisStrmIn->offPeekBuf == pThisStrmIn->cbPeekBuf)
{
- pa_threaded_mainloop_lock(pThis->pMainLoop);
- pa_stream_drop(pStrm->pPAStream);
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_lock(g_pMainLoop);
+ pa_stream_drop(pThisStrmIn->pStream);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
- pStrm->pu8PeekBuf = NULL;
+ pThisStrmIn->pu8PeekBuf = NULL;
}
}
@@ -853,10 +814,11 @@ static DECLCALLBACK(int) drvHostPulseAudioStreamCapture(PPDMIHOSTAUDIO pInterfac
{
uint32_t cProcessed = 0;
if (cWrittenTotal)
- rc = AudioMixBufMixToParent(&pStream->MixBuf, cWrittenTotal, &cProcessed);
+ rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
+ &cProcessed);
- if (pcbRead)
- *pcbRead = cWrittenTotal;
+ if (pcSamplesCaptured)
+ *pcSamplesCaptured = cWrittenTotal;
LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
cWrittenTotal, cProcessed, rc));
@@ -866,44 +828,40 @@ static DECLCALLBACK(int) drvHostPulseAudioStreamCapture(PPDMIHOSTAUDIO pInterfac
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
- */
-static DECLCALLBACK(int) drvHostPulseAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+static DECLCALLBACK(int) drvHostPulseAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ uint32_t *pcSamplesPlayed)
{
- RT_NOREF(pvBuf, cbBuf);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbWritten is optional. */
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ /* pcSamplesPlayed is optional. */
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pPAStream = (PPULSEAUDIOSTREAM)pStream;
+ PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
int rc = VINF_SUCCESS;
uint32_t cbReadTotal = 0;
- uint32_t cLive = AudioMixBufUsed(&pStream->MixBuf);
+ uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
if (!cLive)
{
- LogFlowFunc(("No live samples, skipping\n"));
- if (pcbWritten)
- *pcbWritten = 0;
+ LogFlowFunc(("%p: No live samples, skipping\n", pHstStrmOut));
+
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = 0;
return VINF_SUCCESS;
}
- pa_threaded_mainloop_lock(pThis->pMainLoop);
+ pa_threaded_mainloop_lock(g_pMainLoop);
do
{
- size_t cbWriteable = pa_stream_writable_size(pPAStream->pPAStream);
+ size_t cbWriteable = pa_stream_writable_size(pThisStrmOut->pStream);
if (cbWriteable == (size_t)-1)
{
- rc = paError(pPAStream->pDrv, "Failed to determine output data size");
+ rc = drvHostPulseAudioError(pThisStrmOut->pDrv, "Failed to determine output data size");
break;
}
- size_t cbLive = AUDIOMIXBUF_S2B(&pStream->MixBuf, cLive);
+ size_t cbLive = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cLive);
size_t cbToRead = RT_MIN(cbWriteable, cbLive);
LogFlowFunc(("cbToRead=%zu, cbWriteable=%zu, cbLive=%zu\n",
@@ -912,19 +870,19 @@ static DECLCALLBACK(int) drvHostPulseAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
uint32_t cRead, cbRead;
while (cbToRead)
{
- rc = AudioMixBufReadCirc(&pStream->MixBuf, pPAStream->pvPCMBuf,
- RT_MIN(cbToRead, pPAStream->cbPCMBuf), &cRead);
+ rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvPCMBuf,
+ RT_MIN(cbToRead, pThisStrmOut->cbPCMBuf), &cRead);
if ( !cRead
|| RT_FAILURE(rc))
{
break;
}
- cbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead);
- if (pa_stream_write(pPAStream->pPAStream, pPAStream->pvPCMBuf, cbRead, NULL /* Cleanup callback */,
+ cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
+ if (pa_stream_write(pThisStrmOut->pStream, pThisStrmOut->pvPCMBuf, cbRead, NULL /* Cleanup callback */,
0, PA_SEEK_RELATIVE) < 0)
{
- rc = paError(pPAStream->pDrv, "Failed to write to output stream");
+ rc = drvHostPulseAudioError(pThisStrmOut->pDrv, "Failed to write to output stream");
break;
}
@@ -933,21 +891,21 @@ static DECLCALLBACK(int) drvHostPulseAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
cbReadTotal += cbRead;
LogFlowFunc(("\tcRead=%RU32 (%zu bytes) cbReadTotal=%RU32, cbToRead=%RU32\n",
- cRead, AUDIOMIXBUF_S2B(&pStream->MixBuf, cRead), cbReadTotal, cbToRead));
+ cRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead), cbReadTotal, cbToRead));
}
} while (0);
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
if (RT_SUCCESS(rc))
{
- uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pStream->MixBuf, cbReadTotal);
+ uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
if (cReadTotal)
- AudioMixBufFinish(&pStream->MixBuf, cReadTotal);
+ AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
- if (pcbWritten)
- *pcbWritten = cReadTotal;
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = cReadTotal;
LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n", cReadTotal, cbReadTotal, rc));
}
@@ -956,262 +914,79 @@ static DECLCALLBACK(int) drvHostPulseAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
return rc;
}
-
/** @todo Implement va handling. */
-static int paError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg)
+static int drvHostPulseAudioError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
AssertPtrReturn(szMsg, VERR_INVALID_POINTER);
if (pThis->cLogErrors++ < VBOX_PULSEAUDIO_MAX_LOG_REL_ERRORS)
{
- int rc2 = pa_context_errno(pThis->pContext);
- LogRel2(("PulseAudio: %s: %s\n", szMsg, pa_strerror(rc2)));
+ int rc2 = pa_context_errno(g_pContext);
+ LogRel(("PulseAudio: %s: %s\n", szMsg, pa_strerror(rc2)));
}
/** @todo Implement some PulseAudio -> IPRT mapping here. */
return VERR_GENERAL_FAILURE;
}
-
-static void paEnumSinkCb(pa_context *pCtx, const pa_sink_info *pInfo, int eol, void *pvUserData)
-{
- if (eol != 0)
- return;
-
- AssertPtrReturnVoid(pCtx);
- AssertPtrReturnVoid(pInfo);
-
- PPULSEAUDIOENUMCBCTX pCbCtx = (PPULSEAUDIOENUMCBCTX)pvUserData;
- AssertPtrReturnVoid(pCbCtx);
- AssertPtrReturnVoid(pCbCtx->pDrv);
-
- LogRel2(("PulseAudio: Using output sink '%s'\n", pInfo->name));
-
- /** @todo Store sinks + channel mapping in callback context as soon as we have surround support. */
- pCbCtx->cDevOut++;
-
- pa_threaded_mainloop_signal(pCbCtx->pDrv->pMainLoop, 0);
-}
-
-
-static void paEnumSourceCb(pa_context *pCtx, const pa_source_info *pInfo, int eol, void *pvUserData)
-{
- if (eol != 0)
- return;
-
- AssertPtrReturnVoid(pCtx);
- AssertPtrReturnVoid(pInfo);
-
- PPULSEAUDIOENUMCBCTX pCbCtx = (PPULSEAUDIOENUMCBCTX)pvUserData;
- AssertPtrReturnVoid(pCbCtx);
- AssertPtrReturnVoid(pCbCtx->pDrv);
-
- LogRel2(("PulseAudio: Using input source '%s'\n", pInfo->name));
-
- /** @todo Store sources + channel mapping in callback context as soon as we have surround support. */
- pCbCtx->cDevIn++;
-
- pa_threaded_mainloop_signal(pCbCtx->pDrv->pMainLoop, 0);
-}
-
-
-static void paEnumServerCb(pa_context *pCtx, const pa_server_info *pInfo, void *pvUserData)
-{
- AssertPtrReturnVoid(pCtx);
- AssertPtrReturnVoid(pInfo);
-
- PPULSEAUDIOENUMCBCTX pCbCtx = (PPULSEAUDIOENUMCBCTX)pvUserData;
- AssertPtrReturnVoid(pCbCtx);
-
- PDRVHOSTPULSEAUDIO pThis = pCbCtx->pDrv;
- AssertPtrReturnVoid(pThis);
-
- if (pInfo->default_sink_name)
- {
- Assert(RTStrIsValidEncoding(pInfo->default_sink_name));
- pCbCtx->pszDefaultSink = RTStrDup(pInfo->default_sink_name);
- }
-
- if (pInfo->default_sink_name)
- {
- Assert(RTStrIsValidEncoding(pInfo->default_source_name));
- pCbCtx->pszDefaultSource = RTStrDup(pInfo->default_source_name);
- }
-
- pa_threaded_mainloop_signal(pThis->pMainLoop, 0);
-}
-
-
-static int paEnumerate(PDRVHOSTPULSEAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
+static DECLCALLBACK(int) drvHostPulseAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- PDMAUDIOBACKENDCFG Cfg;
- RT_ZERO(Cfg);
-
- Cfg.cbStreamOut = sizeof(PULSEAUDIOSTREAM);
- Cfg.cbStreamIn = sizeof(PULSEAUDIOSTREAM);
- Cfg.cMaxStreamsOut = UINT32_MAX;
- Cfg.cMaxStreamsIn = UINT32_MAX;
-
- PULSEAUDIOENUMCBCTX cbCtx;
- RT_ZERO(cbCtx);
-
- cbCtx.pDrv = pThis;
- cbCtx.fFlags = fEnum;
-
- bool fLog = (fEnum & PULSEAUDIOENUMCBFLAGS_LOG);
-
- int rc = paWaitFor(pThis, pa_context_get_server_info(pThis->pContext, paEnumServerCb, &cbCtx));
- if (RT_SUCCESS(rc))
- {
- if (cbCtx.pszDefaultSink)
- {
- if (fLog)
- LogRel2(("PulseAudio: Default output sink is '%s'\n", cbCtx.pszDefaultSink));
-
- rc = paWaitFor(pThis, pa_context_get_sink_info_by_name(pThis->pContext, cbCtx.pszDefaultSink,
- paEnumSinkCb, &cbCtx));
- if ( RT_FAILURE(rc)
- && fLog)
- {
- LogRel(("PulseAudio: Error enumerating properties for default output sink '%s'\n", cbCtx.pszDefaultSink));
- }
- }
- else if (fLog)
- LogRel2(("PulseAudio: No default output sink found\n"));
-
- if (RT_SUCCESS(rc))
- {
- if (cbCtx.pszDefaultSource)
- {
- if (fLog)
- LogRel2(("PulseAudio: Default input source is '%s'\n", cbCtx.pszDefaultSource));
-
- rc = paWaitFor(pThis, pa_context_get_source_info_by_name(pThis->pContext, cbCtx.pszDefaultSource,
- paEnumSourceCb, &cbCtx));
- if ( RT_FAILURE(rc)
- && fLog)
- {
- LogRel(("PulseAudio: Error enumerating properties for default input source '%s'\n", cbCtx.pszDefaultSource));
- }
- }
- else if (fLog)
- LogRel2(("PulseAudio: No default input source found\n"));
- }
-
- if (RT_SUCCESS(rc))
- {
- Cfg.cSinks = cbCtx.cDevOut;
- Cfg.cSources = cbCtx.cDevIn;
-
- if (fLog)
- {
- LogRel2(("PulseAudio: Found %RU8 host playback device(s)\n", cbCtx.cDevOut));
- LogRel2(("PulseAudio: Found %RU8 host capturing device(s)\n", cbCtx.cDevIn));
- }
-
- if (pCfg)
- memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
- }
-
- if (cbCtx.pszDefaultSink)
- {
- RTStrFree(cbCtx.pszDefaultSink);
- cbCtx.pszDefaultSink = NULL;
- }
-
- if (cbCtx.pszDefaultSource)
- {
- RTStrFree(cbCtx.pszDefaultSource);
- cbCtx.pszDefaultSource = NULL;
- }
- }
- else if (fLog)
- LogRel(("PulseAudio: Error enumerating PulseAudio server properties\n"));
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-
-static int paDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pStream;
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
LogFlowFuncEnter();
- if (pStrm->pPAStream)
+ PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
+ if (pThisStrmIn->pStream)
{
- pa_threaded_mainloop_lock(pThis->pMainLoop);
-
- pa_stream_disconnect(pStrm->pPAStream);
- pa_stream_unref(pStrm->pPAStream);
-
- pStrm->pPAStream = NULL;
+ pa_threaded_mainloop_lock(g_pMainLoop);
+ pa_stream_disconnect(pThisStrmIn->pStream);
+ pa_stream_unref(pThisStrmIn->pStream);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pThisStrmIn->pStream = NULL;
}
return VINF_SUCCESS;
}
-
-static int paDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvHostPulseAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pStream;
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
LogFlowFuncEnter();
- if (pStrm->pPAStream)
+ PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
+ if (pThisStrmOut->pStream)
{
- pa_threaded_mainloop_lock(pThis->pMainLoop);
-
- /* Make sure to cancel a pending draining operation, if any. */
- if (pStrm->pDrainOp)
- {
- pa_operation_cancel(pStrm->pDrainOp);
- pStrm->pDrainOp = NULL;
- }
+ pa_threaded_mainloop_lock(g_pMainLoop);
+ pa_stream_disconnect(pThisStrmOut->pStream);
+ pa_stream_unref(pThisStrmOut->pStream);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
- pa_stream_disconnect(pStrm->pPAStream);
- pa_stream_unref(pStrm->pPAStream);
-
- pStrm->pPAStream = NULL;
-
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pThisStrmOut->pStream = NULL;
}
- if (pStrm->pvPCMBuf)
+ if (pThisStrmOut->pvPCMBuf)
{
- RTMemFree(pStrm->pvPCMBuf);
- pStrm->pvPCMBuf = NULL;
- pStrm->cbPCMBuf = 0;
+ RTMemFree(pThisStrmOut->pvPCMBuf);
+ pThisStrmOut->pvPCMBuf = NULL;
+
+ pThisStrmOut->cbPCMBuf = 0;
}
return VINF_SUCCESS;
}
-
-static int paControlStreamOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostPulseAudioControlOut(PPDMIHOSTAUDIO pInterface,
+ PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
{
- AssertPtrReturn(pInterface , VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pStream;
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
int rc = VINF_SUCCESS;
LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
@@ -1221,22 +996,25 @@ static int paControlStreamOut(PPDMIHOSTAUDIO pInterface,
case PDMAUDIOSTREAMCMD_ENABLE:
case PDMAUDIOSTREAMCMD_RESUME:
{
- pa_threaded_mainloop_lock(pThis->pMainLoop);
+ pa_threaded_mainloop_lock(g_pMainLoop);
- if ( pStrm->pDrainOp
- && pa_operation_get_state(pStrm->pDrainOp) != PA_OPERATION_DONE)
+ if ( pThisStrmOut->pDrainOp
+ && pa_operation_get_state(pThisStrmOut->pDrainOp) != PA_OPERATION_DONE)
{
- pa_operation_cancel(pStrm->pDrainOp);
- pa_operation_unref(pStrm->pDrainOp);
+ pa_operation_cancel(pThisStrmOut->pDrainOp);
+ pa_operation_unref(pThisStrmOut->pDrainOp);
- pStrm->pDrainOp = NULL;
+ pThisStrmOut->pDrainOp = NULL;
}
else
{
- rc = paWaitFor(pThis, pa_stream_cork(pStrm->pPAStream, 0, paStreamCbSuccess, pStrm));
+ /* This should return immediately. */
+ rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmOut->pStream, 0,
+ drvHostPulseAudioCbSuccess, pThisStrmOut),
+ 15 * 1000 /* 15s timeout */);
}
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
break;
}
@@ -1245,14 +1023,18 @@ static int paControlStreamOut(PPDMIHOSTAUDIO pInterface,
{
/* Pause audio output (the Pause bit of the AC97 x_CR register is set).
* Note that we must return immediately from here! */
- pa_threaded_mainloop_lock(pThis->pMainLoop);
- if (!pStrm->pDrainOp)
+ pa_threaded_mainloop_lock(g_pMainLoop);
+ if (!pThisStrmOut->pDrainOp)
{
- rc = paWaitFor(pThis, pa_stream_trigger(pStrm->pPAStream, paStreamCbSuccess, pStrm));
- if (RT_SUCCESS(rc))
- pStrm->pDrainOp = pa_stream_drain(pStrm->pPAStream, paStreamCbDrain, pStrm);
+ /* This should return immediately. */
+ rc = drvHostPulseAudioWaitFor(pa_stream_trigger(pThisStrmOut->pStream,
+ drvHostPulseAudioCbSuccess, pThisStrmOut),
+ 15 * 1000 /* 15s timeout */);
+ if (RT_LIKELY(RT_SUCCESS(rc)))
+ pThisStrmOut->pDrainOp = pa_stream_drain(pThisStrmOut->pStream,
+ drvHostPulseAudioCbStreamDrain, pThisStrmOut);
}
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
break;
}
@@ -1266,16 +1048,13 @@ static int paControlStreamOut(PPDMIHOSTAUDIO pInterface,
return rc;
}
-
-static int paControlStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
- PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvHostPulseAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pStream;
+ NOREF(pInterface);
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
int rc = VINF_SUCCESS;
LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
@@ -1285,24 +1064,29 @@ static int paControlStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
case PDMAUDIOSTREAMCMD_ENABLE:
case PDMAUDIOSTREAMCMD_RESUME:
{
- pa_threaded_mainloop_lock(pThis->pMainLoop);
- rc = paWaitFor(pThis, pa_stream_cork(pStrm->pPAStream, 0 /* Play / resume */, paStreamCbSuccess, pStrm));
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ pa_threaded_mainloop_lock(g_pMainLoop);
+ /* This should return immediately. */
+ rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmIn->pStream, 0 /* Play / resume */,
+ drvHostPulseAudioCbSuccess, pThisStrmIn),
+ 15 * 1000 /* 15s timeout */);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
break;
}
case PDMAUDIOSTREAMCMD_DISABLE:
case PDMAUDIOSTREAMCMD_PAUSE:
{
- pa_threaded_mainloop_lock(pThis->pMainLoop);
- if (pStrm->pu8PeekBuf) /* Do we need to drop the peek buffer?*/
+ pa_threaded_mainloop_lock(g_pMainLoop);
+ if (pThisStrmIn->pu8PeekBuf) /* Do we need to drop the peek buffer?*/
{
- pa_stream_drop(pStrm->pPAStream);
- pStrm->pu8PeekBuf = NULL;
+ pa_stream_drop(pThisStrmIn->pStream);
+ pThisStrmIn->pu8PeekBuf = NULL;
}
-
- rc = paWaitFor(pThis, pa_stream_cork(pStrm->pPAStream, 1 /* Stop / pause */, paStreamCbSuccess, pStrm));
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
+ /* This should return immediately. */
+ rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmIn->pStream, 1 /* Stop / pause */,
+ drvHostPulseAudioCbSuccess, pThisStrmIn),
+ 15 * 1000 /* 15s timeout */);
+ pa_threaded_mainloop_unlock(g_pMainLoop);
break;
}
@@ -1315,184 +1099,44 @@ static int paControlStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
return rc;
}
+static DECLCALLBACK(int) drvHostPulseAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+{
+ NOREF(pInterface);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+
+ pCfg->cbStreamOut = sizeof(PULSEAUDIOSTREAM);
+ pCfg->cbStreamIn = sizeof(PULSEAUDIOSTREAM);
+ pCfg->cMaxHstStrmsOut = UINT32_MAX;
+ pCfg->cMaxHstStrmsIn = UINT32_MAX;
+
+ return VINF_SUCCESS;
+}
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
- */
static DECLCALLBACK(void) drvHostPulseAudioShutdown(PPDMIHOSTAUDIO pInterface)
{
- AssertPtrReturnVoid(pInterface);
-
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
+ NOREF(pInterface);
LogFlowFuncEnter();
- if (pThis->pMainLoop)
- pa_threaded_mainloop_stop(pThis->pMainLoop);
+ if (g_pMainLoop)
+ pa_threaded_mainloop_stop(g_pMainLoop);
- if (pThis->pContext)
+ if (g_pContext)
{
- pa_context_disconnect(pThis->pContext);
- pa_context_unref(pThis->pContext);
- pThis->pContext = NULL;
+ pa_context_disconnect(g_pContext);
+ pa_context_unref(g_pContext);
+ g_pContext = NULL;
}
- if (pThis->pMainLoop)
+ if (g_pMainLoop)
{
- pa_threaded_mainloop_free(pThis->pMainLoop);
- pThis->pMainLoop = NULL;
+ pa_threaded_mainloop_free(g_pMainLoop);
+ g_pMainLoop = NULL;
}
LogFlowFuncLeave();
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
- */
-static DECLCALLBACK(int) drvHostPulseAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
-
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
-
- return paEnumerate(pThis, pBackendCfg, PULSEAUDIOENUMCBFLAGS_LOG /* fEnum */);
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostPulseAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- RT_NOREF(enmDir);
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
-
- return PDMAUDIOBACKENDSTS_RUNNING;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvHostPulseAudioStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
-
- int rc;
- if (pCfgReq->enmDir == PDMAUDIODIR_IN)
- rc = paCreateStreamIn(pInterface, pStream, pCfgReq, pCfgAcq);
- else if (pStream->enmDir == PDMAUDIODIR_OUT)
- rc = paCreateStreamOut(pInterface, pStream, pCfgReq, pCfgAcq);
- else
- AssertFailedReturn(VERR_NOT_IMPLEMENTED);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvHostPulseAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = paDestroyStreamIn(pInterface, pStream);
- else if (pStream->enmDir == PDMAUDIODIR_OUT)
- rc = paDestroyStreamOut(pInterface, pStream);
- else
- AssertFailedReturn(VERR_NOT_IMPLEMENTED);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
- */
-static DECLCALLBACK(int) drvHostPulseAudioStreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
-
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = paControlStreamIn(pInterface, pStream, enmStreamCmd);
- else if (pStream->enmDir == PDMAUDIODIR_OUT)
- rc = paControlStreamOut(pInterface, pStream, enmStreamCmd);
- else
- AssertFailedReturn(VERR_NOT_IMPLEMENTED);
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostPulseAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pStream;
-
- PDMAUDIOSTRMSTS strmSts = PDMAUDIOSTRMSTS_FLAG_INITIALIZED
- | PDMAUDIOSTRMSTS_FLAG_ENABLED;
-
- pa_threaded_mainloop_lock(pThis->pMainLoop);
-
- /*pa_context_state_t ctxState = pa_context_get_state(pThis->pContext); - unused */
-
- if ( pa_context_get_state(pThis->pContext) == PA_CONTEXT_READY
- && pa_stream_get_state(pStrm->pPAStream) == PA_STREAM_READY)
- {
- if (pStream->enmDir == PDMAUDIODIR_IN)
- {
- strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_READABLE;
- }
- else
- {
- size_t cbSize = pa_stream_writable_size(pStrm->pPAStream);
- LogFlowFunc(("cbSize=%zu\n", cbSize));
-
- if (cbSize >= pStrm->BufAttr.minreq)
- strmSts |= PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
- }
- }
-
- pa_threaded_mainloop_unlock(pThis->pMainLoop);
-
- return strmSts;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetConfig}
- */
-static DECLCALLBACK(int) drvHostPulseAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
-
- /* Nothing to do here for PulseAudio. */
- return VINF_SUCCESS;
-}
-
-
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
@@ -1509,19 +1153,6 @@ static DECLCALLBACK(void *) drvHostPulseAudioQueryInterface(PPDMIBASE pInterface
return NULL;
}
-
-/**
- * Destructs a PulseAudio Audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(void) drvHostPulseAudioDestruct(PPDMDRVINS pDrvIns)
-{
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
- LogFlowFuncEnter();
-}
-
-
/**
* Constructs a PulseAudio Audio driver instance.
*
@@ -1529,13 +1160,14 @@ static DECLCALLBACK(void) drvHostPulseAudioDestruct(PPDMDRVINS pDrvIns)
*/
static DECLCALLBACK(int) drvHostPulseAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
- RT_NOREF(pCfg, fFlags);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+ RT_NOREF(fFlags);
AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO);
LogRel(("Audio: Initializing PulseAudio driver\n"));
+ CFGMR3QueryStringAlloc(pCfg, "StreamName", &pThis->pszStreamName);
+
pThis->pDrvIns = pDrvIns;
/* IBase */
pDrvIns->IBase.pfnQueryInterface = drvHostPulseAudioQueryInterface;
@@ -1545,9 +1177,24 @@ static DECLCALLBACK(int) drvHostPulseAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNOD
return VINF_SUCCESS;
}
+/**
+ * Destructs a PulseAudio Audio driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(void) drvHostPulseAudioDestruct(PPDMDRVINS pDrvIns)
+{
+ PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO);
+ LogFlowFuncEnter();
+ if (pThis->pszStreamName)
+ {
+ MMR3HeapFree(pThis->pszStreamName);
+ pThis->pszStreamName = NULL;
+ }
+}
/**
- * Pulse audio driver registration record.
+ * Char driver registration record.
*/
const PDMDRVREG g_DrvHostPulseAudio =
{
@@ -1597,13 +1244,14 @@ const PDMDRVREG g_DrvHostPulseAudio =
PDM_DRVREG_VERSION
};
-#if 0 /* unused */
+#if 0 // unused
static struct audio_option pulse_options[] =
{
{"DAC_MS", AUD_OPT_INT, &s_pulseCfg.buffer_msecs_out,
"DAC period size in milliseconds", NULL, 0},
{"ADC_MS", AUD_OPT_INT, &s_pulseCfg.buffer_msecs_in,
- "ADC period size in milliseconds", NULL, 0}
+ "ADC period size in milliseconds", NULL, 0},
+
+ NULL
};
#endif
-
diff --git a/src/VBox/Devices/Audio/HDACodec.cpp b/src/VBox/Devices/Audio/HDACodec.cpp
index 7e05c0f..ba6d027 100644
--- a/src/VBox/Devices/Audio/HDACodec.cpp
+++ b/src/VBox/Devices/Audio/HDACodec.cpp
@@ -34,10 +34,7 @@
#include <iprt/cpp/utils.h>
#include "VBoxDD.h"
-#include "DrvAudio.h"
-#include "HDACodec.h"
-#include "DevHDACommon.h"
-#include "AudioMixer.h"
+#include "DevIchHdaCodec.h"
/*********************************************************************************************************************************
@@ -105,17 +102,9 @@
#define CODEC_MAKE_F00_00(vendorID, deviceID) (((vendorID) << 16) | (deviceID))
#define CODEC_F00_00_VENDORID(f00_00) (((f00_00) >> 16) & 0xFFFF)
#define CODEC_F00_00_DEVICEID(f00_00) ((f00_00) & 0xFFFF)
-
-/** RevisionID (7.3.4.2). */
-#define CODEC_MAKE_F00_02(majRev, minRev, venFix, venProg, stepFix, stepProg) \
- ( (((majRev) & 0xF) << 20) \
- | (((minRev) & 0xF) << 16) \
- | (((venFix) & 0xF) << 12) \
- | (((venProg) & 0xF) << 8) \
- | (((stepFix) & 0xF) << 4) \
- | ((stepProg) & 0xF))
-
-/** Subordinate node count (7.3.4.3). */
+/* RevisionID (7.3.4.2)*/
+#define CODEC_MAKE_F00_02(MajRev, MinRev, RevisionID, SteppingID) (((MajRev) << 20)|((MinRev) << 16)|((RevisionID) << 8)|(SteppingID))
+/* Subordinate node count (7.3.4.3)*/
#define CODEC_MAKE_F00_04(startNodeNumber, totalNodeNumber) ((((startNodeNumber) & 0xFF) << 16)|((totalNodeNumber) & 0xFF))
#define CODEC_F00_04_TO_START_NODE_NUMBER(f00_04) (((f00_04) >> 16) & 0xFF)
#define CODEC_F00_04_TO_NODE_COUNT(f00_04) ((f00_04) & 0xFF)
@@ -130,19 +119,15 @@
#define CODEC_F00_05_MFG (0x2)
#define CODEC_F00_05_IS_UNSOL(f00_05) RT_BOOL((f00_05) & RT_BIT(8))
#define CODEC_F00_05_GROUP(f00_05) ((f00_05) & 0xff)
-/* Audio Function Group capabilities (7.3.4.5). */
+/* Audio Function Group capabilities (7.3.4.5) */
#define CODEC_MAKE_F00_08(BeepGen, InputDelay, OutputDelay) ((((BeepGen) & 0x1) << 16)| (((InputDelay) & 0xF) << 8) | ((OutputDelay) & 0xF))
#define CODEC_F00_08_BEEP_GEN(f00_08) ((f00_08) & RT_BIT(16)
-/* Converter Stream, Channel (7.3.3.11). */
-#define CODEC_F00_06_GET_STREAM_ID(cmd) (((cmd) >> 4) & 0x0F)
-#define CODEC_F00_06_GET_CHANNEL_ID(cmd) (((cmd) & 0x0F))
-
-/* Widget Capabilities (7.3.4.6). */
-#define CODEC_MAKE_F00_09(type, delay, chan_ext) \
- ( (((type) & 0xF) << 20) \
- | (((delay) & 0xF) << 16) \
- | (((chan_ext) & 0xF) << 13))
+/* Widget Capabilities (7.3.4.6) */
+#define CODEC_MAKE_F00_09(type, delay, chanel_count) \
+ ( (((type) & 0xF) << 20) \
+ | (((delay) & 0xF) << 16) \
+ | (((chanel_count) & 0xF) << 13))
/* note: types 0x8-0xe are reserved */
#define CODEC_F00_09_TYPE_AUDIO_OUTPUT (0x0)
#define CODEC_F00_09_TYPE_AUDIO_INPUT (0x1)
@@ -166,7 +151,7 @@
#define CODEC_F00_09_CAP_AMP_FMT_OVERRIDE RT_BIT(3)
#define CODEC_F00_09_CAP_OUT_AMP_PRESENT RT_BIT(2)
#define CODEC_F00_09_CAP_IN_AMP_PRESENT RT_BIT(1)
-#define CODEC_F00_09_CAP_STEREO RT_BIT(0)
+#define CODEC_F00_09_CAP_LSB RT_BIT(0)
#define CODEC_F00_09_TYPE(f00_09) (((f00_09) >> 20) & 0xF)
@@ -222,8 +207,8 @@
#define CODEC_F00_0C_CAP_BALANCED_IO RT_BIT(6)
#define CODEC_F00_0C_CAP_INPUT RT_BIT(5)
#define CODEC_F00_0C_CAP_OUTPUT RT_BIT(4)
-#define CODEC_F00_0C_CAP_HEADPHONE_AMP RT_BIT(3)
-#define CODEC_F00_0C_CAP_PRESENCE_DETECT RT_BIT(2)
+#define CODEC_F00_0C_CAP_HP RT_BIT(3)
+#define CODEC_F00_0C_CAP_PRESENSE_DETECT RT_BIT(2)
#define CODEC_F00_0C_CAP_TRIGGER_REQUIRED RT_BIT(1)
#define CODEC_F00_0C_CAP_IMPENDANCE_SENSE RT_BIT(0)
@@ -235,16 +220,16 @@
#define CODEC_F00_0C_IS_CAP_INPUT(f00_0c) ((f00_0c) & RT_BIT(5))
#define CODEC_F00_0C_IS_CAP_OUTPUT(f00_0c) ((f00_0c) & RT_BIT(4))
#define CODEC_F00_0C_IS_CAP_HP(f00_0c) ((f00_0c) & RT_BIT(3))
-#define CODEC_F00_0C_IS_CAP_PRESENCE_DETECT(f00_0c) ((f00_0c) & RT_BIT(2))
+#define CODEC_F00_0C_IS_CAP_PRESENSE_DETECT(f00_0c) ((f00_0c) & RT_BIT(2))
#define CODEC_F00_0C_IS_CAP_TRIGGER_REQUIRED(f00_0c) ((f00_0c) & RT_BIT(1))
#define CODEC_F00_0C_IS_CAP_IMPENDANCE_SENSE(f00_0c) ((f00_0c) & RT_BIT(0))
-/* Input Amplifier capabilities (7.3.4.10). */
+/* Input Amplifier capabilities (7.3.4.10) */
#define CODEC_MAKE_F00_0D(mute_cap, step_size, num_steps, offset) \
- ( (((mute_cap) & UINT32_C(0x1)) << 31) \
+ ( (((mute_cap) & UINT32_C(0x01)) << 31) \
| (((step_size) & UINT32_C(0xFF)) << 16) \
- | (((num_steps) & UINT32_C(0xFF)) << 8) \
- | ((offset) & UINT32_C(0xFF)))
+ | (((num_steps) & UINT32_C(0xFF)) << 8) \
+ | ( (offset) & UINT32_C(0xFF)) )
#define CODEC_F00_0D_CAP_MUTE RT_BIT(7)
@@ -253,24 +238,6 @@
#define CODEC_F00_0D_NUM_STEPS(f00_0d) ((((f00_0d) & (0x7F << 8)) >> 8) + 1)
#define CODEC_F00_0D_OFFSET(f00_0d) ( (f00_0d) & 0x7F)
-/** Indicates that the amplifier can be muted. */
-#define CODEC_AMP_CAP_MUTE 0x1
-/** The amplifier's maximum number of steps. We want
- * a ~90dB dynamic range, so 64 steps with 1.25dB each
- * should do the trick.
- *
- * As we want to map our range to [0..128] values we can avoid
- * multiplication and simply doing a shift later.
- *
- * Produces -96dB to +0dB.
- * "0" indicates a step of 0.25dB, "127" indicates a step of 32dB.
- */
-#define CODEC_AMP_NUM_STEPS 0x7F
-/** The initial gain offset (and when doing a node reset). */
-#define CODEC_AMP_OFF_INITIAL 0x7F
-/** The amplifier's gain step size. */
-#define CODEC_AMP_STEP_SIZE 0x2
-
/* Output Amplifier capabilities (7.3.4.10) */
#define CODEC_MAKE_F00_12 CODEC_MAKE_F00_0D
@@ -279,7 +246,7 @@
#define CODEC_F00_12_NUM_STEPS(f00_12) CODEC_F00_0D_NUM_STEPS(f00_12)
#define CODEC_F00_12_OFFSET(f00_12) CODEC_F00_0D_OFFSET(f00_12)
-/* Connection list lenght (7.3.4.11). */
+/* Connection list lenght (7.3.4.11) */
#define CODEC_MAKE_F00_0E(long_form, length) \
( (((long_form) & 0x1) << 7) \
| ((length) & 0x7F))
@@ -304,25 +271,25 @@
#define CODEC_F00_10_NUM(f00_10) (((f00_10) & (0xFF << 8)) >> 8)
#define CODEC_F00_10_BENING(f00_10) ((f00_10) & 0x1)
-/* GPIO count (7.3.4.14). */
+/* CP/IO Count (7.3.4.14) */
#define CODEC_MAKE_F00_11(wake, unsol, numgpi, numgpo, numgpio) \
- ( (((wake) & UINT32_C(0x1)) << 31) \
- | (((unsol) & UINT32_C(0x1)) << 30) \
+ ( (((wake) & UINT32_C(0x01)) << 31) \
+ | (((unsol) & UINT32_C(0x01)) << 30) \
| (((numgpi) & UINT32_C(0xFF)) << 16) \
- | (((numgpo) & UINT32_C(0xFF)) << 8) \
- | ((numgpio) & UINT32_C(0xFF)))
+ | (((numgpo) & UINT32_C(0xFF)) << 8) \
+ | ((numgpio) & UINT32_C(0xFF)) )
-/* Processing States (7.3.3.4). */
+/* Processing States (7.3.3.4) */
#define CODEC_F03_OFF (0)
#define CODEC_F03_ON RT_BIT(0)
#define CODEC_F03_BENING RT_BIT(1)
-/* Power States (7.3.3.10). */
-#define CODEC_MAKE_F05(reset, stopok, error, act, set) \
- ( (((reset) & 0x1) << 10) \
- | (((stopok) & 0x1) << 9) \
- | (((error) & 0x1) << 8) \
- | (((act) & 0xF) << 4) \
- | ((set) & 0xF))
+/* Power States (7.3.3.10) */
+#define CODEC_MAKE_F05(reset, stopok, error, act, set) \
+ ( (((reset) & 0x1) << 10) \
+ | (((stopok) & 0x1) << 9) \
+ | (((error) & 0x1) << 8) \
+ | (((act) & 0x7) << 4) \
+ | ((set) & 0x7))
#define CODEC_F05_D3COLD (4)
#define CODEC_F05_D3 (3)
#define CODEC_F05_D2 (2)
@@ -332,20 +299,13 @@
#define CODEC_F05_IS_RESET(value) (((value) & RT_BIT(10)) != 0)
#define CODEC_F05_IS_STOPOK(value) (((value) & RT_BIT(9)) != 0)
#define CODEC_F05_IS_ERROR(value) (((value) & RT_BIT(8)) != 0)
-#define CODEC_F05_ACT(value) (((value) & 0xF0) >> 4)
-#define CODEC_F05_SET(value) (((value) & 0xF))
+#define CODEC_F05_ACT(value) (((value) & 0x7) >> 4)
+#define CODEC_F05_SET(value) (((value) & 0x7))
#define CODEC_F05_GE(p0, p1) ((p0) <= (p1))
#define CODEC_F05_LE(p0, p1) ((p0) >= (p1))
-/* Converter Stream, Channel (7.3.3.11). */
-#define CODEC_MAKE_F06(stream, channel) \
- ( (((stream) & 0xF) << 4) \
- | ((channel) & 0xF))
-#define CODEC_F06_STREAM(value) ((value) & 0xF0)
-#define CODEC_F06_CHANNEL(value) ((value) & 0xF)
-
-/* Pin Widged Control (7.3.3.13). */
+/* Pin Widged Control (7.3.3.13) */
#define CODEC_F07_VREF_HIZ (0)
#define CODEC_F07_VREF_50 (0x1)
#define CODEC_F07_VREF_GROUND (0x2)
@@ -355,33 +315,57 @@
#define CODEC_F07_OUT_ENABLE RT_BIT(6)
#define CODEC_F07_OUT_H_ENABLE RT_BIT(7)
-/* Volume Knob Control (7.3.3.29). */
-#define CODEC_F0F_IS_DIRECT RT_BIT(7)
-#define CODEC_F0F_VOLUME (0x7F)
-
-/* Unsolicited enabled (7.3.3.14). */
+/* Unsolicited enabled (7.3.3.14) */
#define CODEC_MAKE_F08(enable, tag) ((((enable) & 1) << 7) | ((tag) & 0x3F))
-/* Converter formats (7.3.3.8) and (3.7.1). */
-/* This is the same format as SDnFMT. */
-#define CODEC_MAKE_A HDA_SDFMT_MAKE
-
-#define CODEC_A_TYPE HDA_SDFMT_TYPE
-#define CODEC_A_TYPE_PCM HDA_SDFMT_TYPE_PCM
-#define CODEC_A_TYPE_NON_PCM HDA_SDFMT_TYPE_NON_PCM
-
-#define CODEC_A_BASE HDA_SDFMT_BASE
-#define CODEC_A_BASE_48KHZ HDA_SDFMT_BASE_48KHZ
-#define CODEC_A_BASE_44KHZ HDA_SDFMT_BASE_44KHZ
-
-/* Pin Sense (7.3.3.15). */
-#define CODEC_MAKE_F09_ANALOG(fPresent, impedance) \
-( (((fPresent) & 0x1) << 31) \
- | (((impedance) & UINT32_C(0x7FFFFFFF))))
-#define CODEC_F09_ANALOG_NA UINT32_C(0x7FFFFFFF)
+/* Converter formats (7.3.3.8) and (3.7.1) */
+#define CODEC_MAKE_A(fNonPCM, f44_1BaseRate, mult, div, bits, chan) \
+ ( (((fNonPCM) & 0x1) << 15) \
+ | (((f44_1BaseRate) & 0x1) << 14) \
+ | (((mult) & 0x7) << 11) \
+ | (((div) & 0x7) << 8) \
+ | (((bits) & 0x7) << 4) \
+ | ((chan) & 0xF))
+
+#define CODEC_A_TYPE RT_BIT(15)
+#define CODEC_A_TYPE_PCM (0)
+#define CODEC_A_TYPE_NON_PCM (1)
+
+#define CODEC_A_BASE RT_BIT(14)
+#define CODEC_A_BASE_48KHZ (0)
+#define CODEC_A_BASE_44KHZ (1)
+
+#define CODEC_A_MULT_1X (0)
+#define CODEC_A_MULT_2X (1)
+#define CODEC_A_MULT_3X (2)
+#define CODEC_A_MULT_4X (3)
+
+#define CODEC_A_DIV_1X (0)
+#define CODEC_A_DIV_2X (1)
+#define CODEC_A_DIV_3X (2)
+#define CODEC_A_DIV_4X (3)
+#define CODEC_A_DIV_5X (4)
+#define CODEC_A_DIV_6X (5)
+#define CODEC_A_DIV_7X (6)
+#define CODEC_A_DIV_8X (7)
+
+#define CODEC_A_8_BIT (0)
+#define CODEC_A_16_BIT (1)
+#define CODEC_A_20_BIT (2)
+#define CODEC_A_24_BIT (3)
+#define CODEC_A_32_BIT (4)
+
+#define CODEC_A_CHAN_MONO (0)
+#define CODEC_A_CHAN_STEREO (1)
+
+/* Pin Sense (7.3.3.15) */
+#define CODEC_MAKE_F09_ANALOG(fPresent, impedance) \
+ ( (((fPresent) & UINT32_C(0x00000001)) << 31) \
+ | ((impedance) & UINT32_C(0x7FFFFFFF)) )
+#define CODEC_F09_ANALOG_NA 0x7FFFFFFF
#define CODEC_MAKE_F09_DIGITAL(fPresent, fELDValid) \
-( (((fPresent) & UINT32_C(0x1)) << 31) \
- | (((fELDValid) & UINT32_C(0x1)) << 30))
+ ( (((fPresent) & UINT32_C(0x1)) << 31) \
+ | (((fELDValid) & UINT32_C(0x1)) << 30))
#define CODEC_MAKE_F0C(lrswap, eapd, btl) ((((lrswap) & 1) << 2) | (((eapd) & 1) << 1) | ((btl) & 1))
#define CODEC_FOC_IS_LRSWAP(f0c) RT_BOOL((f0c) & RT_BIT(2))
@@ -492,17 +476,16 @@
/* Configuration's misc */
#define CODEC_F1C_MISC_MASK (0xF)
#define CODEC_F1C_MISC_SHIFT (8)
-#define CODEC_F1C_MISC_NONE 0
-#define CODEC_F1C_MISC_JACK_NO_PRESENCE_DETECT RT_BIT(0)
-#define CODEC_F1C_MISC_RESERVED_0 RT_BIT(1)
-#define CODEC_F1C_MISC_RESERVED_1 RT_BIT(2)
-#define CODEC_F1C_MISC_RESERVED_2 RT_BIT(3)
+#define CODEC_F1C_MISC_JACK_DETECT (0)
+#define CODEC_F1C_MISC_RESERVED_0 (1)
+#define CODEC_F1C_MISC_RESERVED_1 (2)
+#define CODEC_F1C_MISC_RESERVED_2 (3)
/* Configuration default: Association */
#define CODEC_F1C_ASSOCIATION_MASK (0xF)
#define CODEC_F1C_ASSOCIATION_SHIFT (4)
-/** Reserved; don't use. */
+/* Reserved; don't use. */
#define CODEC_F1C_ASSOCIATION_INVALID 0x0
#define CODEC_F1C_ASSOCIATION_GROUP_0 0x1
#define CODEC_F1C_ASSOCIATION_GROUP_1 0x2
@@ -514,27 +497,27 @@
#define CODEC_F1C_ASSOCIATION_GROUP_7 0x8
#define CODEC_F1C_ASSOCIATION_GROUP_15 0xF
-/* Configuration default: Association Sequence. */
+/* Configuration default: Association Sequence */
#define CODEC_F1C_SEQ_MASK (0xF)
#define CODEC_F1C_SEQ_SHIFT (0)
-/* Implementation identification (7.3.3.30). */
+/* Implementation identification (7.3.3.30) */
#define CODEC_MAKE_F20(bmid, bsku, aid) \
( (((bmid) & 0xFFFF) << 16) \
| (((bsku) & 0xFF) << 8) \
| (((aid) & 0xFF)) \
)
-/* Macro definition helping in filling the configuration registers. */
+/* macro definition helping in filling the configuration registers. */
#define CODEC_MAKE_F1C(port_connectivity, location, device, connection_type, color, misc, association, sequence) \
- ( (((port_connectivity) & 0xF) << CODEC_F1C_PORT_SHIFT) \
- | (((location) & 0xF) << CODEC_F1C_LOCATION_SHIFT) \
- | (((device) & 0xF) << CODEC_F1C_DEVICE_SHIFT) \
- | (((connection_type) & 0xF) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \
- | (((color) & 0xF) << CODEC_F1C_COLOR_SHIFT) \
- | (((misc) & 0xF) << CODEC_F1C_MISC_SHIFT) \
- | (((association) & 0xF) << CODEC_F1C_ASSOCIATION_SHIFT) \
- | (((sequence) & 0xF)))
+ ( ((port_connectivity) << CODEC_F1C_PORT_SHIFT) \
+ | ((location) << CODEC_F1C_LOCATION_SHIFT) \
+ | ((device) << CODEC_F1C_DEVICE_SHIFT) \
+ | ((connection_type) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \
+ | ((color) << CODEC_F1C_COLOR_SHIFT) \
+ | ((misc) << CODEC_F1C_MISC_SHIFT) \
+ | ((association) << CODEC_F1C_ASSOCIATION_SHIFT) \
+ | ((sequence)))
/*********************************************************************************************************************************
@@ -550,16 +533,10 @@
*/
typedef struct CODECCOMMONNODE
{
- /** The node's ID. */
- uint8_t uID;
- /** The node's name. */
+ /** Node id - 7 bit format */
+ uint8_t id;
+ /** The node name. */
char const *pszName;
- /** The SDn ID this node is assigned to.
- * 0 means not assigned, 1 is SDn0. */
- uint8_t uSD;
- /** The SDn's channel to use.
- * Only valid if a valid SDn ID is set. */
- uint8_t uChannel;
/* PRM 5.3.6 */
uint32_t au32F00_param[CODECNODE_F00_PARAM_LENGTH];
uint32_t au32F02_param[CODECNODE_F02_PARAM_LENGTH];
@@ -607,13 +584,13 @@ AssertNodeSize(DACNODE, 6 + 60);
typedef struct ADCNODE
{
CODECCOMMONNODE node;
- uint32_t u32F01_param;
uint32_t u32F03_param;
uint32_t u32F05_param;
uint32_t u32F06_param;
uint32_t u32F09_param;
uint32_t u32A_param;
+ uint32_t u32F01_param;
AMPLIFIER B_params;
} ADCNODE, *PADCNODE;
AssertNodeSize(DACNODE, 6 + 60);
@@ -649,18 +626,18 @@ typedef struct AFGCODECNODE
CODECCOMMONNODE node;
uint32_t u32F05_param;
uint32_t u32F08_param;
- uint32_t u32F17_param;
uint32_t u32F20_param;
+ uint32_t u32F17_param;
} AFGCODECNODE, *PAFGCODECNODE;
AssertNodeSize(AFGCODECNODE, 4);
typedef struct PORTNODE
{
CODECCOMMONNODE node;
- uint32_t u32F01_param;
uint32_t u32F07_param;
uint32_t u32F08_param;
uint32_t u32F09_param;
+ uint32_t u32F01_param;
uint32_t u32F1c_param;
AMPLIFIER B_params;
} PORTNODE, *PPORTNODE;
@@ -670,13 +647,12 @@ typedef struct DIGOUTNODE
{
CODECCOMMONNODE node;
uint32_t u32F01_param;
- uint32_t u32F05_param;
- uint32_t u32F07_param;
uint32_t u32F08_param;
+ uint32_t u32F07_param;
uint32_t u32F09_param;
uint32_t u32F1c_param;
} DIGOUTNODE, *PDIGOUTNODE;
-AssertNodeSize(DIGOUTNODE, 6);
+AssertNodeSize(DIGOUTNODE, 5);
typedef struct DIGINNODE
{
@@ -746,10 +722,8 @@ typedef struct RESNODE
uint32_t u32F06_param;
uint32_t u32F07_param;
uint32_t u32F1c_param;
-
- uint32_t u32A_param;
} RESNODE, *PRESNODE;
-AssertNodeSize(RESNODE, 5);
+AssertNodeSize(RESNODE, 4);
/**
* Used for the saved state.
@@ -798,17 +772,13 @@ AssertNodeSize(CODECNODE, 60 + 6);
#define STAC9220_NID_ADC1 0x7 /* In */
#define STAC9220_NID_SPDIF_OUT 0x8 /* Out */
#define STAC9220_NID_SPDIF_IN 0x9 /* In */
-/** Also known as PIN_A. */
#define STAC9220_NID_PIN_HEADPHONE0 0xA /* In, Out */
#define STAC9220_NID_PIN_B 0xB /* In, Out */
#define STAC9220_NID_PIN_C 0xC /* In, Out */
-/** Also known as PIN D. */
#define STAC9220_NID_PIN_HEADPHONE1 0xD /* In, Out */
#define STAC9220_NID_PIN_E 0xE /* In */
#define STAC9220_NID_PIN_F 0xF /* In, Out */
-/** Also known as DIGOUT0. */
#define STAC9220_NID_PIN_SPDIF_OUT 0x10 /* Out */
-/** Also known as DIGIN. */
#define STAC9220_NID_PIN_SPDIF_IN 0x11 /* In */
#define STAC9220_NID_ADC0_MUX 0x12 /* In */
#define STAC9220_NID_ADC1_MUX 0x13 /* In */
@@ -817,35 +787,48 @@ AssertNodeSize(CODECNODE, 60 + 6);
#define STAC9220_NID_VOL_KNOB 0x16
#define STAC9220_NID_AMP_ADC0 0x17 /* In */
#define STAC9220_NID_AMP_ADC1 0x18 /* In */
-/* Only for STAC9221. */
+/* STAC9221. */
#define STAC9221_NID_ADAT_OUT 0x19 /* Out */
#define STAC9221_NID_I2S_OUT 0x1A /* Out */
#define STAC9221_NID_PIN_I2S_OUT 0x1B /* Out */
-/** Number of total nodes emulated. */
-#define STAC9221_NUM_NODES 0x1C
-
-/* STAC9220 - Referenced through STAC9220WIDGET in the constructor below. */
-static uint8_t const g_abStac9220Ports[] = { STAC9220_NID_PIN_HEADPHONE0, STAC9220_NID_PIN_B, STAC9220_NID_PIN_C, STAC9220_NID_PIN_HEADPHONE1, STAC9220_NID_PIN_E, STAC9220_NID_PIN_F, 0 };
-static uint8_t const g_abStac9220Dacs[] = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0 };
-static uint8_t const g_abStac9220Adcs[] = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0 };
+#if 1
+/* STAC9220 - Referenced thru STAC9220WIDGET in the constructor below. */
+static uint8_t const g_abStac9220Ports[] = { 0x0A, 0xB, 0xC, 0xD, 0xE, 0xF, 0};
+static uint8_t const g_abStac9220Dacs[] = { 0x02, 0x3, 0x4, 0x5, 0};
+static uint8_t const g_abStac9220Adcs[] = { 0x06, 0x7, 0};
+static uint8_t const g_abStac9220SpdifOuts[] = { 0x08, 0 };
+static uint8_t const g_abStac9220SpdifIns[] = { 0x09, 0 };
+static uint8_t const g_abStac9220DigOutPins[] = { 0x10, 0 };
+static uint8_t const g_abStac9220DigInPins[] = { 0x11, 0 };
+static uint8_t const g_abStac9220AdcVols[] = { 0x17, 0x18, 0};
+static uint8_t const g_abStac9220AdcMuxs[] = { 0x12, 0x13, 0};
+static uint8_t const g_abStac9220Pcbeeps[] = { 0x14, 0 };
+static uint8_t const g_abStac9220Cds[] = { 0x15, 0 };
+static uint8_t const g_abStac9220VolKnobs[] = { 0x16, 0 };
+static uint8_t const g_abStac9220Reserveds[] = { 0x09, 0x19, 0x1a, 0x1b, 0 };
+#else /** @todo Enable this after 5.0 -- needs more testing first. */
+static uint8_t const g_abStac9220Ports[] = { STAC9220_NID_PIN_HEADPHONE0, STAC9220_NID_PIN_B, STAC9220_NID_PIN_C, STAC9220_NID_PIN_HEADPHONE1, STAC9220_NID_PIN_E, STAC9220_NID_PIN_F, 0};
+static uint8_t const g_abStac9220Dacs[] = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0};
+static uint8_t const g_abStac9220Adcs[] = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0};
static uint8_t const g_abStac9220SpdifOuts[] = { STAC9220_NID_SPDIF_OUT, 0 };
static uint8_t const g_abStac9220SpdifIns[] = { STAC9220_NID_SPDIF_IN, 0 };
static uint8_t const g_abStac9220DigOutPins[] = { STAC9220_NID_PIN_SPDIF_OUT, 0 };
static uint8_t const g_abStac9220DigInPins[] = { STAC9220_NID_PIN_SPDIF_IN, 0 };
-static uint8_t const g_abStac9220AdcVols[] = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0 };
-static uint8_t const g_abStac9220AdcMuxs[] = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0 };
+static uint8_t const g_abStac9220AdcVols[] = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0};
+static uint8_t const g_abStac9220AdcMuxs[] = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0};
static uint8_t const g_abStac9220Pcbeeps[] = { STAC9220_NID_PCBEEP, 0 };
static uint8_t const g_abStac9220Cds[] = { STAC9220_NID_PIN_CD, 0 };
static uint8_t const g_abStac9220VolKnobs[] = { STAC9220_NID_VOL_KNOB, 0 };
/* STAC 9221. */
/** @todo Is STAC9220_NID_SPDIF_IN really correct for reserved nodes? */
static uint8_t const g_abStac9220Reserveds[] = { STAC9220_NID_SPDIF_IN, STAC9221_NID_ADAT_OUT, STAC9221_NID_I2S_OUT, STAC9221_NID_PIN_I2S_OUT, 0 };
+#endif
/** SSM description of a CODECNODE. */
static SSMFIELD const g_aCodecNodeFields[] =
{
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.uID),
+ SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id),
SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3),
SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
@@ -856,7 +839,7 @@ static SSMFIELD const g_aCodecNodeFields[] =
/** Backward compatibility with v1 of the CODECNODE. */
static SSMFIELD const g_aCodecNodeFieldsV1[] =
{
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.uID),
+ SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id),
SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7),
SSMFIELD_ENTRY_OLD_HCPTR(Core.name),
SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
@@ -867,11 +850,11 @@ static SSMFIELD const g_aCodecNodeFieldsV1[] =
-#if 0 /* unused */
+
static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
RT_NOREF(pszArgs);
- for (uint8_t i = 1; i < pThis->cTotalNodes; i++)
+ for (int i = 1; i < 12; i++)
{
PCODECNODE pNode = &pThis->paNodes[i];
AMPLIFIER *pAmp = &pNode->dac.B_params;
@@ -882,595 +865,365 @@ static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp,
pHlp->pfnPrintf(pHlp, "0x%x: lVol=%RU8, rVol=%RU8\n", i, lVol, rVol);
}
}
-#endif
-
-static DECLCALLBACK(int) stac9220ResetNode(PHDACODEC pThis, uint8_t uNID, PCODECNODE pNode)
-{
- LogFlowFunc(("NID=0x%x (%RU8)\n", uNID, uNID));
-
- if ( !pThis->fInReset
- && ( uNID != STAC9220_NID_ROOT
- && uNID != STAC9220_NID_AFG)
- )
- {
- RT_ZERO(pNode->node);
- }
- /* Set common parameters across all nodes. */
- pNode->node.uID = uNID;
- pNode->node.uSD = 0;
- switch (uNID)
+static DECLCALLBACK(int) stac9220ResetNode(PHDACODEC pThis, uint8_t nodenum, PCODECNODE pNode)
+{
+ pNode->node.id = nodenum;
+ pNode->node.au32F00_param[0xF] = 0; /* Power statest Supported: are the same as AFG reports */
+ switch (nodenum)
{
- /* Root node. */
- case STAC9220_NID_ROOT:
- {
- /* Set the revision ID. */
- pNode->root.node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x3, 0x4, 0x0, 0x1);
+ /* Root Node*/
+ case 0:
+ pNode->node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x34, 0x1); /* rev id */
break;
- }
-
- /*
- * AFG (Audio Function Group).
- */
- case STAC9220_NID_AFG:
- {
- pNode->afg.node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
- /* We set the AFG's PCM capabitilies fixed to 44.1kHz, 16-bit signed. */
- pNode->afg.node.au32F00_param[0x0A] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
- pNode->afg.node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
- pNode->afg.node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_BALANCED_IO
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENCE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
- | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;
-
- /* Default input amplifier capabilities. */
- pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(CODEC_AMP_CAP_MUTE,
- CODEC_AMP_STEP_SIZE,
- CODEC_AMP_NUM_STEPS,
- CODEC_AMP_OFF_INITIAL);
- /* Default output amplifier capabilities. */
- pNode->node.au32F00_param[0x12] = CODEC_MAKE_F00_12(CODEC_AMP_CAP_MUTE,
- CODEC_AMP_STEP_SIZE,
- CODEC_AMP_NUM_STEPS,
- CODEC_AMP_OFF_INITIAL);
-
- pNode->afg.node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);
- pNode->afg.node.au32F00_param[0x0F] = CODEC_F00_0F_D3
- | CODEC_F00_0F_D2
- | CODEC_F00_0F_D1
- | CODEC_F00_0F_D0;
-
- pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2); /* PS-Act: D2, PS->Set D2. */
+ case 1:
+ pNode->node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
+ pNode->node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
+ | CODEC_F00_0C_CAP_BALANCED_IO
+ | CODEC_F00_0C_CAP_INPUT
+ | CODEC_F00_0C_CAP_PRESENSE_DETECT
+ | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+ | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//(17 << 8)|RT_BIT(6)|RT_BIT(5)|RT_BIT(2)|RT_BIT(1)|RT_BIT(0);
+ pNode->node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
+ pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(1, 0x5, 0xE, 0);//RT_BIT(31)|(0x5 << 16)|(0xE)<<8;
+ pNode->node.au32F00_param[0x12] = RT_BIT(31)|(0x2 << 16)|(0x7f << 8)|0x7f;
+ pNode->node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);//0xc0000004;
+ pNode->node.au32F00_param[0x0F] = CODEC_F00_0F_D3|CODEC_F00_0F_D2|CODEC_F00_0F_D1|CODEC_F00_0F_D0;
+ pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2);//0x2 << 4| 0x2; /* PS-Act: D3, PS->Set D3 */
pNode->afg.u32F08_param = 0;
pNode->afg.u32F17_param = 0;
break;
- }
-
- /*
- * DACs.
- */
- case STAC9220_NID_DAC0: /* DAC0: Headphones 0 + 1 */
- case STAC9220_NID_DAC1: /* DAC1: PIN C */
- case STAC9220_NID_DAC2: /* DAC2: PIN B */
- case STAC9220_NID_DAC3: /* DAC3: PIN F */
- {
- pNode->dac.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
- HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
- HDA_SDFMT_CHAN_STEREO);
-
- /* 7.3.4.6: Audio widget capabilities. */
- pNode->dac.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 13, 0)
- | CODEC_F00_09_CAP_L_R_SWAP
- | CODEC_F00_09_CAP_POWER_CTRL
- | CODEC_F00_09_CAP_OUT_AMP_PRESENT
- | CODEC_F00_09_CAP_STEREO;
-
- /* Connection list; must be 0 if the only connection for the widget is
- * to the High Definition Audio Link. */
- pNode->dac.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 0 /* Entries */);
-
- pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);
-
- RT_ZERO(pNode->dac.B_params);
- AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ memset(pNode->dac.B_params, 0, AMPLIFIER_SIZE);
+ pNode->dac.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//RT_BIT(14)|(0x1 << 4)|0x1; /* 44100Hz/16bit/2ch */
+
+ AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
- break;
- }
- /*
- * ADCs.
- */
- case STAC9220_NID_ADC0: /* Analog input. */
- {
- pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC0;
+ pNode->dac.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0xD, 0)
+ | CODEC_F00_09_CAP_L_R_SWAP
+ | CODEC_F00_09_CAP_POWER_CTRL
+ | CODEC_F00_09_CAP_OUT_AMP_PRESENT
+ | CODEC_F00_09_CAP_LSB;//(0xD << 16) | RT_BIT(11) | RT_BIT(10) | RT_BIT(2) | RT_BIT(0);
+ pNode->dac.u32F0c_param = 0;
+ pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3, Set: D3 */
+ break;
+ case 6:
+ pNode->node.au32F02_param[0] = 0x17;
goto adc_init;
- }
-
- case STAC9220_NID_ADC1: /* Analog input (CD). */
- {
- pNode->node.au32F02_param[0] = STAC9220_NID_AMP_ADC1;
-
- /* Fall through is intentional. */
+ case 7:
+ pNode->node.au32F02_param[0] = 0x18;
adc_init:
-
- pNode->adc.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
- HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
- HDA_SDFMT_CHAN_STEREO);
-
+ pNode->adc.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//RT_BIT(14)|(0x1 << 3)|0x1; /* 44100Hz/16bit/2ch */
+ pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0);
pNode->adc.u32F03_param = RT_BIT(0);
- pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 Set: D3 */
-
- pNode->adc.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
- | CODEC_F00_09_CAP_POWER_CTRL
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_PROC_WIDGET
- | CODEC_F00_09_CAP_STEREO;
- /* Connection list entries. */
- pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
+ pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 Set: D3 */
+ pNode->adc.u32F06_param = 0;
+ pNode->adc.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
+ | CODEC_F00_09_CAP_POWER_CTRL
+ | CODEC_F00_09_CAP_CONNECTION_LIST
+ | CODEC_F00_09_CAP_PROC_WIDGET
+ | CODEC_F00_09_CAP_LSB;//RT_BIT(20)| (0xd << 16) | RT_BIT(10) | RT_BIT(8) | RT_BIT(6)| RT_BIT(0);
break;
- }
-
- /*
- * SP/DIF In/Out.
- */
- case STAC9220_NID_SPDIF_OUT:
- {
- pNode->spdifout.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
- HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
- HDA_SDFMT_CHAN_STEREO);
+ case 8:
+ pNode->spdifout.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//(1<<14)|(0x1<<4) | 0x1;
+ pNode->spdifout.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x4, 0)
+ | CODEC_F00_09_CAP_DIGITAL
+ | CODEC_F00_09_CAP_FMT_OVERRIDE
+ | CODEC_F00_09_CAP_LSB;//(4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1;
+ pNode->node.au32F00_param[0xa] = pThis->paNodes[1].node.au32F00_param[0xA];
+ pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
pNode->spdifout.u32F06_param = 0;
pNode->spdifout.u32F0d_param = 0;
-
- pNode->spdifout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 4, 0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_FMT_OVERRIDE
- | CODEC_F00_09_CAP_STEREO;
-
- /* Use a fixed format from AFG. */
- pNode->spdifout.node.au32F00_param[0xA] = pThis->paNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
- pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
break;
- }
-
- case STAC9220_NID_SPDIF_IN:
- {
- pNode->spdifin.u32A_param = CODEC_MAKE_A(HDA_SDFMT_TYPE_PCM, HDA_SDFMT_BASE_44KHZ,
- HDA_SDFMT_MULT_1X, HDA_SDFMT_DIV_1X, HDA_SDFMT_16_BIT,
- HDA_SDFMT_CHAN_STEREO);
-
- pNode->spdifin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 4, 0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_FMT_OVERRIDE
- | CODEC_F00_09_CAP_STEREO;
-
- /* Use a fixed format from AFG. */
- pNode->spdifin.node.au32F00_param[0xA] = pThis->paNodes[STAC9220_NID_AFG].node.au32F00_param[0xA];
+ case 9:
+ pNode->spdifin.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//(0x1<<4) | 0x1;
+ pNode->spdifin.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0x4, 0)
+ | CODEC_F00_09_CAP_DIGITAL
+ | CODEC_F00_09_CAP_CONNECTION_LIST
+ | CODEC_F00_09_CAP_FMT_OVERRIDE
+ | CODEC_F00_09_CAP_LSB;//(0x1 << 20)|(4 << 16) | RT_BIT(9)| RT_BIT(8)|RT_BIT(4)|0x1;
+ pNode->node.au32F00_param[0xA] = pThis->paNodes[1].node.au32F00_param[0xA];
+ pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0);
+ pNode->node.au32F02_param[0] = 0x11;
pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
-
- /* Connection list entries. */
- pNode->spdifin.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
- pNode->spdifin.node.au32F02_param[0] = 0x11;
+ pNode->spdifin.u32F06_param = 0;
+ pNode->spdifin.u32F0d_param = 0;
break;
- }
-
- /*
- * PINs / Ports.
- */
- case STAC9220_NID_PIN_HEADPHONE0: /* Port A: Headphone in/out (front). */
- {
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0 /*fPresent*/, CODEC_F09_ANALOG_NA);
-
- pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_HEADPHONE_AMP
- | CODEC_F00_0C_CAP_PRESENCE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
-
- /* Connection list entry 0: Goes to DAC0. */
- pNode->port.node.au32F02_param[0] = STAC9220_NID_DAC0;
-
+ case 0xA:
+ pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
+ | CODEC_F00_0C_CAP_INPUT
+ | CODEC_F00_0C_CAP_OUTPUT
+ | CODEC_F00_0C_CAP_HP
+ | CODEC_F00_0C_CAP_PRESENSE_DETECT
+ | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+ | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x173f;
+ pNode->node.au32F02_param[0] = 0x2;
+ pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
+ | CODEC_F07_OUT_ENABLE;
+ pNode->port.u32F08_param = 0;
if (!pThis->fInReset)
pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
CODEC_F1C_LOCATION_FRONT,
CODEC_F1C_DEVICE_HP,
CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
CODEC_F1C_COLOR_GREEN,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_1, 0x0 /* Seq */);
+ CODEC_F1C_MISC_JACK_DETECT,
+ 0x2, 0);//RT_MAKE_U32_FROM_U8(0x20, 0x40, 0x21, 0x02);
+ pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
goto port_init;
- }
-
- case STAC9220_NID_PIN_B: /* Port B: Rear CLFE (Center / Subwoofer). */
- {
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
-
- pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENCE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
-
- /* Connection list entry 0: Goes to DAC2. */
- pNode->port.node.au32F02_param[0] = STAC9220_NID_DAC2;
-
+ case 0xB:
+ pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
+ | CODEC_F00_0C_CAP_INPUT
+ | CODEC_F00_0C_CAP_OUTPUT
+ | CODEC_F00_0C_CAP_PRESENSE_DETECT
+ | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+ | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
+ pNode->node.au32F02_param[0] = 0x4;
+ pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
if (!pThis->fInReset)
pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_REAR,
+ CODEC_F1C_LOCATION_INTERNAL|CODEC_F1C_LOCATION_REAR,
CODEC_F1C_DEVICE_SPEAKER,
CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
CODEC_F1C_COLOR_BLACK,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_0, 0x1 /* Seq */);
+ CODEC_F1C_MISC_JACK_DETECT,
+ 0x1, 0x1);//RT_MAKE_U32_FROM_U8(0x11, 0x60, 0x11, 0x01);
+ pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
goto port_init;
- }
-
- case STAC9220_NID_PIN_C: /* Rear Speaker. */
- {
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
-
- pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENCE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
-
- /* Connection list entry 0: Goes to DAC1. */
- pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC1;
-
+ case 0xC:
+ pNode->node.au32F02_param[0] = 0x3;
+ pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
+ | CODEC_F00_0C_CAP_INPUT
+ | CODEC_F00_0C_CAP_OUTPUT
+ | CODEC_F00_0C_CAP_PRESENSE_DETECT
+ | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+ | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
+ pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
if (!pThis->fInReset)
pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
CODEC_F1C_LOCATION_REAR,
CODEC_F1C_DEVICE_SPEAKER,
CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
CODEC_F1C_COLOR_GREEN,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_0, 0x0 /* Seq */);
+ 0x0, 0x1, 0x0);//RT_MAKE_U32_FROM_U8(0x10, 0x40, 0x11, 0x01);
+ pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
goto port_init;
- }
-
- case STAC9220_NID_PIN_HEADPHONE1: /* Also known as PIN_D. */
- {
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1 /*fPresent*/, CODEC_F09_ANALOG_NA);
-
- pNode->port.node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_HEADPHONE_AMP
- | CODEC_F00_0C_CAP_PRESENCE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED;
-
- /* Connection list entry 0: Goes to DAC1. */
- pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC0;
-
+ case 0xD:
+ pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
+ | CODEC_F00_0C_CAP_INPUT
+ | CODEC_F00_0C_CAP_OUTPUT
+ | CODEC_F00_0C_CAP_PRESENSE_DETECT
+ | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+ | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
+ pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
+ pNode->node.au32F02_param[0] = 0x2;
if (!pThis->fInReset)
pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
CODEC_F1C_LOCATION_FRONT,
CODEC_F1C_DEVICE_MIC,
CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
CODEC_F1C_COLOR_PINK,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_4, 0x0 /* Seq */);
- /* Fall through is intentional. */
-
+ 0x0, 0x5, 0x0);//RT_MAKE_U32_FROM_U8(0x50, 0x90, 0xA1, 0x02); /* Microphone */
+ pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
port_init:
-
- pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
- | CODEC_F07_OUT_ENABLE;
pNode->port.u32F08_param = 0;
-
- pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_UNSOL
- | CODEC_F00_09_CAP_STEREO;
- /* Connection list entries. */
- pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
+ pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0)
+ | CODEC_F00_09_CAP_CONNECTION_LIST
+ | CODEC_F00_09_CAP_UNSOL
+ | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0);
+ pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1;
break;
- }
-
- case STAC9220_NID_PIN_E:
- {
- pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
+ case 0xE:
+ pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0)
+ | CODEC_F00_09_CAP_UNSOL
+ | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(7)|RT_BIT(0);
pNode->port.u32F08_param = 0;
- /* If Line in is reported as enabled, OS X sees no speakers! Windows does
- * not care either way, although Linux does.
- */
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, 0);
-
- pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
- | CODEC_F00_09_CAP_UNSOL
- | CODEC_F00_09_CAP_STEREO;
-
- pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_PRESENCE_DETECT;
-
+ pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
+ | CODEC_F00_0C_CAP_OUTPUT
+ | CODEC_F00_0C_CAP_PRESENSE_DETECT;//0x34;
+ pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
+ pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
if (!pThis->fInReset)
pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
CODEC_F1C_LOCATION_REAR,
- CODEC_F1C_DEVICE_LINE_IN,
+ CODEC_F1C_DEVICE_LINE_OUT,
CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
CODEC_F1C_COLOR_BLUE,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_4, 0x1 /* Seq */);
+ 0x0, 0x4, 0x0);//0x01013040; /* Line Out */
break;
- }
-
- case STAC9220_NID_PIN_F:
- {
- pNode->port.u32F07_param = CODEC_F07_IN_ENABLE | CODEC_F07_OUT_ENABLE;
+ case 0xF:
+ pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0)
+ | CODEC_F00_09_CAP_CONNECTION_LIST
+ | CODEC_F00_09_CAP_UNSOL
+ | CODEC_F00_09_CAP_OUT_AMP_PRESENT
+ | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(2)|RT_BIT(0);
+ pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
+ | CODEC_F00_0C_CAP_OUTPUT
+ | CODEC_F00_0C_CAP_PRESENSE_DETECT
+ /* | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
+ | CODEC_F00_0C_CAP_IMPENDANCE_SENSE */;//0x37;
+ pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1;
pNode->port.u32F08_param = 0;
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(true /* fPresent */, CODEC_F09_ANALOG_NA);
-
- pNode->port.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_UNSOL
- | CODEC_F00_09_CAP_OUT_AMP_PRESENT
- | CODEC_F00_09_CAP_STEREO;
-
- pNode->port.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT;
-
- /* Connection list entry 0: Goes to DAC3. */
- pNode->port.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
- pNode->port.node.au32F02_param[0x0] = STAC9220_NID_DAC3;
-
+ pNode->port.u32F07_param = CODEC_F07_OUT_ENABLE
+ | CODEC_F07_IN_ENABLE;
if (!pThis->fInReset)
pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
CODEC_F1C_LOCATION_INTERNAL,
CODEC_F1C_DEVICE_SPEAKER,
CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
CODEC_F1C_COLOR_ORANGE,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_0, 0x2 /* Seq */);
+ 0x0, 0x1, 0x2);//RT_MAKE_U32_FROM_U8(0x12, 0x60, 0x11, 0x01);
+ pNode->node.au32F02_param[0] = 0x5;
+ pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
break;
- }
-
- case STAC9220_NID_PIN_SPDIF_OUT: /* Rear SPDIF Out. */
- {
- pNode->digout.u32F07_param = CODEC_F07_OUT_ENABLE;
- pNode->digout.u32F09_param = 0;
-
- pNode->digout.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_STEREO;
- pNode->digout.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENCE_DETECT;
-
- /* Connection list entries. */
- pNode->digout.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 3 /* Entries */);
- pNode->digout.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_SPDIF_OUT,
- STAC9220_NID_AMP_ADC0, STAC9221_NID_ADAT_OUT, 0);
+ case 0x10:
+ pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0)
+ | CODEC_F00_09_CAP_DIGITAL
+ | CODEC_F00_09_CAP_CONNECTION_LIST
+ | CODEC_F00_09_CAP_LSB;//(4<<20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
+ pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//RT_BIT(4);
+ pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x3);
+ pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x08, 0x17, 0x19, 0);
if (!pThis->fInReset)
pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
CODEC_F1C_LOCATION_REAR,
CODEC_F1C_DEVICE_SPDIF_OUT,
CODEC_F1C_CONNECTION_TYPE_DIN,
CODEC_F1C_COLOR_BLACK,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_2, 0x0 /* Seq */);
+ 0x0, 0x3, 0x0);//RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01);
break;
- }
-
- case STAC9220_NID_PIN_SPDIF_IN:
- {
- pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3); /* PS-Act: D3 -> D3 */
- pNode->digin.u32F07_param = CODEC_F07_IN_ENABLE;
+ case 0x11:
+ pNode->node.au32F00_param[9] = (4 << 20) | (3 << 16) | RT_BIT(10) | RT_BIT(9) | RT_BIT(7) | RT_BIT(0);
+ pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
+ | CODEC_F00_0C_CAP_INPUT
+ | CODEC_F00_0C_CAP_PRESENSE_DETECT;//RT_BIT(16)| RT_BIT(5)|RT_BIT(2);
+ pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 -> D3 */
+ pNode->digin.u32F07_param = 0;
pNode->digin.u32F08_param = 0;
pNode->digin.u32F09_param = CODEC_MAKE_F09_DIGITAL(0, 0);
pNode->digin.u32F0c_param = 0;
-
- pNode->digin.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 3, 0)
- | CODEC_F00_09_CAP_POWER_CTRL
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_UNSOL
- | CODEC_F00_09_CAP_STEREO;
-
- pNode->digin.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_PRESENCE_DETECT;
if (!pThis->fInReset)
pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
CODEC_F1C_LOCATION_REAR,
CODEC_F1C_DEVICE_SPDIF_IN,
CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL,
CODEC_F1C_COLOR_BLACK,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_5, 0x0 /* Seq */);
+ 0x0, 0x6, 0x0);//(0x1 << 24) | (0xc5 << 16) | (0x10 << 8) | 0x60;
break;
- }
-
- case STAC9220_NID_ADC0_MUX:
- {
- pNode->adcmux.u32F01_param = 0; /* Connection select control index (STAC9220_NID_PIN_E). */
+ case 0x12:
+ pNode->adcmux.u32F01_param = 0;
goto adcmux_init;
- }
-
- case STAC9220_NID_ADC1_MUX:
- {
- pNode->adcmux.u32F01_param = 1; /* Connection select control index (STAC9220_NID_PIN_CD). */
- /* Fall through is intentional. */
-
- adcmux_init:
-
- pNode->adcmux.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
- | CODEC_F00_09_CAP_OUT_AMP_PRESENT
- | CODEC_F00_09_CAP_STEREO;
-
- pNode->adcmux.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 27, 4, 0);
-
- /* Connection list entries. */
- pNode->adcmux.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 7 /* Entries */);
- pNode->adcmux.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_E,
- STAC9220_NID_PIN_CD,
- STAC9220_NID_PIN_F,
- STAC9220_NID_PIN_B);
- pNode->adcmux.node.au32F02_param[0x4] = RT_MAKE_U32_FROM_U8(STAC9220_NID_PIN_C,
- STAC9220_NID_PIN_HEADPHONE1,
- STAC9220_NID_PIN_HEADPHONE0,
- 0x0 /* Unused */);
-
- /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplifiers initialized with 0. */
- RT_ZERO(pNode->adcmux.B_params);
+ case 0x13:
+ pNode->adcmux.u32F01_param = 1;
+ adcmux_init:
+ pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0x0, 0)
+ | CODEC_F00_09_CAP_CONNECTION_LIST
+ | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
+ | CODEC_F00_09_CAP_OUT_AMP_PRESENT
+ | CODEC_F00_09_CAP_LSB;//(3<<20)|RT_BIT(8)|RT_BIT(3)|RT_BIT(2)|RT_BIT(0);
+ pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x7);
+ pNode->node.au32F00_param[0x12] = (0x27 << 16)|(0x4 << 8);
+ /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplefiers inited with 0*/
+ memset(pNode->adcmux.B_params, 0, AMPLIFIER_SIZE);
+ pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0xe, 0x15, 0xf, 0xb);
+ pNode->node.au32F02_param[4] = RT_MAKE_U32_FROM_U8(0xc, 0xd, 0xa, 0x0);
break;
- }
-
- case STAC9220_NID_PCBEEP:
- {
+ case 0x14:
+ pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
+ | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
+ | CODEC_F00_09_CAP_OUT_AMP_PRESENT;//(7 << 20) | RT_BIT(3) | RT_BIT(2);
+ pNode->node.au32F00_param[0x12] = (0x17 << 16)|(0x3 << 8)| 0x3;
pNode->pcbeep.u32F0a_param = 0;
-
- pNode->pcbeep.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
- | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
- | CODEC_F00_09_CAP_OUT_AMP_PRESENT;
- pNode->pcbeep.node.au32F00_param[0xD] = CODEC_MAKE_F00_0D(0, 17, 3, 3);
-
- RT_ZERO(pNode->pcbeep.B_params);
+ memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE);
break;
- }
-
- case STAC9220_NID_PIN_CD:
- {
- pNode->cdnode.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
- | CODEC_F00_09_CAP_STEREO;
- pNode->cdnode.node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT;
-
+ case 0x15:
+ pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
+ | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(0);
+ pNode->node.au32F00_param[0xc] = CODEC_F00_0C_CAP_INPUT;//RT_BIT(5);
if (!pThis->fInReset)
pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED,
CODEC_F1C_LOCATION_INTERNAL,
CODEC_F1C_DEVICE_CD,
CODEC_F1C_CONNECTION_TYPE_ATAPI,
CODEC_F1C_COLOR_UNKNOWN,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_4, 0x2 /* Seq */);
+ 0x0, 0x7, 0x0);//RT_MAKE_U32_FROM_U8(0x70, 0x0, 0x33, 0x90);
break;
- }
-
- case STAC9220_NID_VOL_KNOB:
- {
+ case 0x16:
+ pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0x0, 0x0);//(0x6 << 20);
+ pNode->node.au32F00_param[0x13] = RT_BIT(7)| 0x7F;
+ pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x4);
+ pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x2, 0x3, 0x4, 0x5);
pNode->volumeKnob.u32F08_param = 0;
pNode->volumeKnob.u32F0f_param = 0x7f;
-
- pNode->volumeKnob.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0, 0);
- pNode->volumeKnob.node.au32F00_param[0xD] = RT_BIT(7) | 0x7F;
-
- /* Connection list entries. */
- pNode->volumeKnob.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 4 /* Entries */);
- pNode->volumeKnob.node.au32F02_param[0x0] = RT_MAKE_U32_FROM_U8(STAC9220_NID_DAC0,
- STAC9220_NID_DAC1,
- STAC9220_NID_DAC2,
- STAC9220_NID_DAC3);
break;
- }
-
- case STAC9220_NID_AMP_ADC0: /* ADC0Vol */
- {
- pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC0_MUX;
+ case 0x17:
+ pNode->node.au32F02_param[0] = 0x12;
goto adcvol_init;
- }
-
- case STAC9220_NID_AMP_ADC1: /* ADC1Vol */
- {
- pNode->adcvol.node.au32F02_param[0] = STAC9220_NID_ADC1_MUX;
- /* Fall through is intentional. */
-
+ case 0x18:
+ pNode->node.au32F02_param[0] = 0x13;
adcvol_init:
+ memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE);
- pNode->adcvol.node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
- | CODEC_F00_09_CAP_L_R_SWAP
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_IN_AMP_PRESENT
- | CODEC_F00_09_CAP_STEREO;
-
-
- pNode->adcvol.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
-
- RT_ZERO(pNode->adcvol.B_params);
- AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
+ pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
+ | CODEC_F00_09_CAP_L_R_SWAP
+ | CODEC_F00_09_CAP_CONNECTION_LIST
+ | CODEC_F00_09_CAP_IN_AMP_PRESENT
+ | CODEC_F00_09_CAP_LSB;//(0x3 << 20)|RT_BIT(11)|RT_BIT(8)|RT_BIT(1)|RT_BIT(0);
+ pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x1);
+ AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7);
+ pNode->adcvol.u32F0c_param = 0;
break;
- }
-
- /*
- * STAC9221 nodes.
- */
-
- case STAC9221_NID_ADAT_OUT:
- {
- pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 3, 0)
+ case 0x19:
+ pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 0x3, 0)
| CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_STEREO;
+ | CODEC_F00_09_CAP_LSB;//(0xF << 20)|(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
break;
- }
-
- case STAC9221_NID_I2S_OUT:
- {
- pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 3, 0)
+ case 0x1A:
+ pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x3, 0)
| CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_STEREO;
+ | CODEC_F00_09_CAP_LSB;//(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
break;
- }
-
- case STAC9221_NID_PIN_I2S_OUT:
- {
+ case 0x1B:
pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
| CODEC_F00_09_CAP_DIGITAL
| CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_STEREO;
-
- pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;
-
- /* Connection list entries. */
- pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(CODEC_F00_0E_LIST_NID_SHORT, 1 /* Entries */);
- pNode->node.au32F02_param[0] = STAC9221_NID_I2S_OUT;
-
- if (!pThis->fInReset)
- pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
- CODEC_F1C_LOCATION_NA,
- CODEC_F1C_DEVICE_LINE_OUT,
- CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
- CODEC_F1C_COLOR_UNKNOWN,
- CODEC_F1C_MISC_NONE,
- CODEC_F1C_ASSOCIATION_GROUP_15, 0xB /* Seq */);
+ | CODEC_F00_09_CAP_LSB;//(0x4 << 20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
+ pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x1);
+ pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//0x10;
+ pNode->node.au32F02_param[0] = 0x1a;
+ pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
+ CODEC_F1C_LOCATION_NA,
+ CODEC_F1C_DEVICE_LINE_OUT,
+ CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
+ CODEC_F1C_COLOR_UNKNOWN,
+ 0x0, 0x0, 0xf);//0x4000000f;
break;
- }
-
default:
- AssertMsgFailed(("Node %RU8 not implemented\n", uNID));
- break;
+ break;
}
-
return VINF_SUCCESS;
}
+
static int stac9220Construct(PHDACODEC pThis)
{
- unconst(pThis->cTotalNodes) = STAC9221_NUM_NODES;
-
+ unconst(pThis->cTotalNodes) = 0x1C;
pThis->pfnCodecNodeReset = stac9220ResetNode;
-
- pThis->u16VendorId = 0x8384; /* SigmaTel */
- /*
- * Note: The Linux kernel uses "patch_stac922x" for the fixups,
- * which in turn uses "ref922x_pin_configs" for the configuration
- * defaults tweaking in sound/pci/hda/patch_sigmatel.c.
- */
- pThis->u16DeviceId = 0x7680; /* STAC9221 A1 */
- pThis->u8BSKU = 0x76;
+ pThis->pfnDbgListNodes = stac9220DbgNodes;
+ pThis->u16VendorId = 0x8384;
+ pThis->u16DeviceId = 0x7680;
+ pThis->u8BSKU = 0x76;
pThis->u8AssemblyId = 0x80;
-
pThis->paNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * pThis->cTotalNodes);
if (!pThis->paNodes)
return VERR_NO_MEMORY;
-
pThis->fInReset = false;
-
#define STAC9220WIDGET(type) pThis->au8##type##s = g_abStac9220##type##s
STAC9220WIDGET(Port);
STAC9220WIDGET(Dac);
@@ -1486,9 +1239,8 @@ static int stac9220Construct(PHDACODEC pThis)
STAC9220WIDGET(VolKnob);
STAC9220WIDGET(Reserved);
#undef STAC9220WIDGET
-
- unconst(pThis->u8AdcVolsLineIn) = STAC9220_NID_AMP_ADC0;
- unconst(pThis->u8DacLineOut) = STAC9220_NID_DAC1;
+ unconst(pThis->u8AdcVolsLineIn) = 0x17;
+ unconst(pThis->u8DacLineOut) = 0x3;
return VINF_SUCCESS;
}
@@ -1498,14 +1250,14 @@ static int stac9220Construct(PHDACODEC pThis)
* Some generic predicate functions.
*/
-#define DECLISNODEOFTYPE(type) \
- DECLINLINE(bool) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
- { \
- Assert(pThis->au8##type##s); \
- for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \
- if (pThis->au8##type##s[i] == cNode) \
- return true; \
- return false; \
+#define DECLISNODEOFTYPE(type) \
+ DECLINLINE(int) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
+ { \
+ Assert(pThis->au8##type##s); \
+ for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \
+ if (pThis->au8##type##s[i] == cNode) \
+ return 1; \
+ return 0; \
}
/* hdaCodecIsPortNode */
DECLISNODEOFTYPE(Port)
@@ -1538,35 +1290,33 @@ DECLISNODEOFTYPE(Reserved)
/*
* Misc helpers.
*/
-static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL enmMixerCtl)
+static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL mt)
{
- uint8_t iDir;
- switch (enmMixerCtl)
+ uint32_t dir = AMPLIFIER_OUT;
+ ENMSOUNDSOURCE enmSrc;
+ switch (mt)
{
- case PDMAUDIOMIXERCTL_VOLUME_MASTER:
- case PDMAUDIOMIXERCTL_FRONT:
- iDir = AMPLIFIER_OUT;
+ case PDMAUDIOMIXERCTL_PCM:
+ enmSrc = PO_INDEX;
+ dir = AMPLIFIER_OUT;
break;
case PDMAUDIOMIXERCTL_LINE_IN:
- case PDMAUDIOMIXERCTL_MIC_IN:
- iDir = AMPLIFIER_IN;
+ enmSrc = PI_INDEX;
+ dir = AMPLIFIER_IN;
break;
default:
- AssertMsgFailedReturn(("Invalid mixer control %d\n", enmMixerCtl), VERR_INVALID_PARAMETER);
+ AssertMsgFailedReturn(("Invalid mixer control %ld\n", mt), VERR_INVALID_PARAMETER);
break;
}
- int iMute;
- iMute = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
- iMute |= AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
- iMute >>=7;
- iMute &= 0x1;
-
- uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_LEFT, 0) & 0x7f;
- uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, iDir, AMPLIFIER_RIGHT, 0) & 0x7f;
+ int mute = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
+ mute |= AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
+ mute >>=7;
+ mute &= 0x1;
+ uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & 0x7f;
+ uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & 0x7f;
- /*
- * The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
+ /* The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
* We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
* to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
* to 1 (rather than zero) internally.
@@ -1574,8 +1324,7 @@ static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCT
lVol = (lVol + 1) * (2 * 255) / 256;
rVol = (rVol + 1) * (2 * 255) / 256;
- PDMAUDIOVOLUME Vol = { RT_BOOL(iMute), lVol, rVol };
- return pThis->pfnMixerSetVolume(pThis->pHDAState, enmMixerCtl, &Vol);
+ return pThis->pfnSetVolume(pThis->pHDAState, enmSrc, RT_BOOL(mute), lVol, rVol);
}
DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
@@ -1599,17 +1348,17 @@ DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint
/*
* Verb processor functions.
*/
-#if 0 /* unused */
static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
RT_NOREF(pThis, cmd);
LogFlowFunc(("cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
- CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
+ CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
*pResp = 0;
return VINF_SUCCESS;
}
+#if 0 // unused
static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
int rc;
@@ -1617,17 +1366,22 @@ static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *p
*pResp |= CODEC_RESPONSE_UNSOLICITED;
return rc;
}
-
-#endif /* unused */
+#endif
/* B-- */
static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
/* HDA spec 7.3.3.7 Note A */
- /** @todo If index out of range response should be 0. */
- uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT ? 0 : CODEC_GET_AMP_INDEX(cmd);
+ /** @todo: if index out of range response should be 0 */
+ uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT? 0 : CODEC_GET_AMP_INDEX(cmd);
PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
@@ -1661,18 +1415,27 @@ static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint
CODEC_GET_AMP_SIDE(cmd),
u8Index);
else
- LogRel2(("HDA: Warning: Unhandled get amplifier command: 0x%x (NID=0x%x [%RU8])\n", cmd, CODEC_NID(cmd), CODEC_NID(cmd)));
-
+ AssertMsgFailedReturn(("access to fields of %x need to be implemented\n", CODEC_NID(cmd)), VINF_SUCCESS);
return VINF_SUCCESS;
}
/* 3-- */
static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ bool fIsLeft = false;
+ bool fIsRight = false;
+ bool fIsOut = false;
+ bool fIsIn = false;
+ uint8_t u8Index = 0;
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
- PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
- AMPLIFIER *pAmplifier = NULL;
+ PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
+ AMPLIFIER *pAmplifier;
if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
pAmplifier = &pNode->dac.B_params;
else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
@@ -1686,22 +1449,16 @@ static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint
else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
pAmplifier = &pNode->adc.B_params;
else
- LogRel2(("HDA: Warning: Unhandled set amplifier command: 0x%x (Payload=%RU16, NID=0x%x [%RU8])\n",
- cmd, CODEC_VERB_PAYLOAD16(cmd), CODEC_NID(cmd), CODEC_NID(cmd)));
-
- if (!pAmplifier)
- return VINF_SUCCESS;
-
- bool fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
- bool fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
- bool fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
- bool fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
- uint8_t u8Index = CODEC_SET_AMP_INDEX(cmd);
+ AssertFailedReturn(VINF_SUCCESS);
+ fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
+ fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
+ fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
+ fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
+ u8Index = CODEC_SET_AMP_INDEX(cmd);
if ( (!fIsLeft && !fIsRight)
|| (!fIsOut && !fIsIn))
return VINF_SUCCESS;
-
if (fIsIn)
{
if (fIsLeft)
@@ -1720,7 +1477,7 @@ static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint
hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
if (CODEC_NID(cmd) == pThis->u8DacLineOut)
- hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_FRONT);
+ hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_PCM);
}
return VINF_SUCCESS;
@@ -1728,15 +1485,18 @@ static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint
static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
{
- *pResp = 0;
-
LogFlowFunc(("invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
return VINF_SUCCESS;
}
-
*pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
return VINF_SUCCESS;
}
@@ -1744,8 +1504,14 @@ static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint
/* F01 */
static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
@@ -1756,18 +1522,20 @@ static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd,
*pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
- else
- LogRel2(("HDA: Warning: Unhandled get connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
return VINF_SUCCESS;
}
/* 701 */
static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
- uint32_t *pu32Reg = NULL;
+ uint32_t *pu32Reg;
if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
@@ -1779,19 +1547,22 @@ static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd,
else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
else
- LogRel2(("HDA: Warning: Unhandled set connection select control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
+ AssertFailedReturn(VINF_SUCCESS);
+ hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
return VINF_SUCCESS;
}
/* F07 */
static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
@@ -1805,17 +1576,22 @@ static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64
else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
else
- LogRel2(("HDA: Warning: Unhandled get pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
+ AssertMsgFailed(("Unsupported"));
return VINF_SUCCESS;
}
/* 707 */
static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
- uint32_t *pu32Reg = NULL;
+ uint32_t *pu32Reg;
if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
@@ -1830,24 +1606,27 @@ static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64
&& CODEC_NID(cmd) == 0x1b)
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
else
- LogRel2(("HDA: Warning: Unhandled set pin control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
+ AssertFailedReturn(VINF_SUCCESS);
+ hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
return VINF_SUCCESS;
}
/* F08 */
static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
- else if ((cmd) == STAC9220_NID_AFG)
+ else if ((cmd) == 1 /* AFG */)
*pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
@@ -1856,22 +1635,27 @@ static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
else
- LogRel2(("HDA: Warning: Unhandled get unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
+ AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
return VINF_SUCCESS;
}
/* 708 */
static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
- uint32_t *pu32Reg = NULL;
+ uint32_t *pu32Reg;
if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
- else if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+ else if (CODEC_NID(cmd) == 1 /* AFG */)
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
@@ -1880,55 +1664,63 @@ static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t
else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
else
- LogRel2(("HDA: Warning: Unhandled set unsolicited enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
+ AssertMsgFailedReturn(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)), VINF_SUCCESS);
+ hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
return VINF_SUCCESS;
}
/* F09 */
static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
else
- {
- AssertFailed();
- LogRel2(("HDA: Warning: Unhandled get pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
- }
-
+ AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
return VINF_SUCCESS;
}
/* 709 */
static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
- uint32_t *pu32Reg = NULL;
+ uint32_t *pu32Reg;
if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
else
- LogRel2(("HDA: Warning: Unhandled set pin sense command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
+ AssertFailedReturn(VINF_SUCCESS);
+ hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
return VINF_SUCCESS;
}
static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
*pResp = 0;
-
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
{
@@ -1942,19 +1734,30 @@ static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t
/* F03 */
static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param;
-
return VINF_SUCCESS;
}
/* 703 */
static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
return VINF_SUCCESS;
@@ -1963,20 +1766,31 @@ static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd
/* F0D */
static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
-
return VINF_SUCCESS;
}
static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
@@ -2006,7 +1820,7 @@ static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, uint32_t cmd, uint64_t
LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
return VINF_SUCCESS;
}
- if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+ if (CODEC_NID(cmd) == 1 /* AFG */)
*pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
else
*pResp = 0;
@@ -2023,7 +1837,7 @@ static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
return VINF_SUCCESS;
}
uint32_t *pu32Reg;
- if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+ if (CODEC_NID(cmd) == 0x1 /* AFG */)
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
else
AssertFailedReturn(VINF_SUCCESS);
@@ -2062,23 +1876,20 @@ static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, uint32_t cmd, uint64_
static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) == STAC9220_NID_AFG);
-
- if ( CODEC_NID(cmd) == STAC9220_NID_AFG
+ Assert(CODEC_NID(cmd) == 1 /* AFG */);
+ if ( CODEC_NID(cmd) == 1 /* AFG */
&& pThis->pfnCodecNodeReset)
{
- LogFunc(("Entering reset ...\n"));
-
- pThis->fInReset = true;
-
- for (uint8_t i = 0; i < pThis->cTotalNodes; ++i)
+ uint8_t i;
+ LogFlowFunc(("enters reset\n"));
+ Assert(pThis->pfnCodecNodeReset);
+ for (i = 0; i < pThis->cTotalNodes; ++i)
+ {
pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
-
+ }
pThis->fInReset = false;
-
- LogFunc(("Exited reset\n"));
+ LogFlowFunc(("exits reset\n"));
}
-
*pResp = 0;
return VINF_SUCCESS;
}
@@ -2086,126 +1897,33 @@ static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *p
/* F05 */
static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
- if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+ if (CODEC_NID(cmd) == 1 /* AFG */)
*pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F05_param;
+ else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
+ *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
- else
- LogRel2(("HDA: Warning: Unhandled get power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- LogFunc(("[NID0x%02x]: fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
- CODEC_NID(cmd), CODEC_F05_IS_RESET(*pResp), CODEC_F05_IS_STOPOK(*pResp), CODEC_F05_ACT(*pResp), CODEC_F05_SET(*pResp)));
return VINF_SUCCESS;
}
/* 705 */
-#if 1
-static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
-
- uint32_t *pu32Reg = NULL;
- if (CODEC_NID(cmd) == STAC9220_NID_AFG)
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
- else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F05_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
- else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
- else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
- else
- {
- AssertFailed();
- LogRel2(("HDA: Warning: Unhandled set power state command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
- }
-
- if (!pu32Reg)
- return VINF_SUCCESS;
-
- uint8_t uPwrCmd = CODEC_F05_SET (cmd);
- bool fReset = CODEC_F05_IS_RESET (*pu32Reg);
- bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
-#ifdef LOG_ENABLED
- bool fError = CODEC_F05_IS_ERROR (*pu32Reg);
- uint8_t uPwrAct = CODEC_F05_ACT (*pu32Reg);
- uint8_t uPwrSet = CODEC_F05_SET (*pu32Reg);
- LogFunc(("[NID0x%02x] Cmd=D%RU8, fReset=%RTbool, fStopOk=%RTbool, fError=%RTbool, uPwrAct=D%RU8, uPwrSet=D%RU8\n",
- CODEC_NID(cmd), uPwrCmd, fReset, fStopOk, fError, uPwrAct, uPwrSet));
- LogFunc(("AFG: Act=D%RU8, Set=D%RU8\n",
- CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param),
- CODEC_F05_SET(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param)));
-#endif
-
- if (CODEC_NID(cmd) == STAC9220_NID_AFG)
- *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uPwrCmd /* PS-Act */, uPwrCmd /* PS-Set */);
-
- const uint8_t uAFGPwrAct = CODEC_F05_ACT(pThis->paNodes[STAC9220_NID_AFG].afg.u32F05_param);
- if (uAFGPwrAct == CODEC_F05_D0) /* Only propagate power state if AFG is on (D0). */
- {
- /* Propagate to all other nodes under this AFG. */
- LogFunc(("Propagating Act=D%RU8 (AFG), Set=D%RU8 to all AFG child nodes ...\n", uAFGPwrAct, uPwrCmd));
-
-#define PROPAGATE_PWR_STATE(_aList, _aMember) \
- { \
- const uint8_t *pu8NodeIndex = &_aList[0]; \
- while (*(++pu8NodeIndex)) \
- { \
- pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param = \
- CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd); \
- LogFunc(("\t[NID0x%02x]: Act=D%RU8, Set=D%RU8\n", *pu8NodeIndex, \
- CODEC_F05_ACT(pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param), \
- CODEC_F05_SET(pThis->paNodes[*pu8NodeIndex]._aMember.u32F05_param))); \
- } \
- }
-
- PROPAGATE_PWR_STATE(pThis->au8Dacs, dac);
- PROPAGATE_PWR_STATE(pThis->au8Adcs, adc);
- PROPAGATE_PWR_STATE(pThis->au8DigInPins, digin);
- PROPAGATE_PWR_STATE(pThis->au8DigOutPins, digout);
- PROPAGATE_PWR_STATE(pThis->au8SpdifIns, spdifin);
- PROPAGATE_PWR_STATE(pThis->au8SpdifOuts, spdifout);
- PROPAGATE_PWR_STATE(pThis->au8Reserveds, reserved);
-
-#undef PROPAGATE_PWR_STATE
- }
- /*
- * If this node is a reqular node (not the AFG one), adopt PS-Set of the AFG node
- * as PS-Set of this node. PS-Act always is one level under PS-Set here.
- */
- else
- {
- *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, uAFGPwrAct, uPwrCmd);
- }
- LogFunc(("[NID0x%02x] fReset=%RTbool, fStopOk=%RTbool, Act=D%RU8, Set=D%RU8\n",
- CODEC_NID(cmd),
- CODEC_F05_IS_RESET(*pu32Reg), CODEC_F05_IS_STOPOK(*pu32Reg), CODEC_F05_ACT(*pu32Reg), CODEC_F05_SET(*pu32Reg)));
-
- return VINF_SUCCESS;
-}
-#else
DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
{
Assert(pu32F05_param);
@@ -2282,12 +2000,17 @@ static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uin
}
return VINF_SUCCESS;
}
-#endif
static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
@@ -2296,94 +2019,48 @@ static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint6
*pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
- else if (CODEC_NID(cmd) == STAC9221_NID_I2S_OUT)
+ else if (CODEC_NID(cmd) == 0x1A)
*pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
- else
- LogRel2(("HDA: Warning: Unhandled get stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- LogFlowFunc(("[NID0x%02x] Stream ID=%RU8, channel=%RU8\n",
- CODEC_NID(cmd), CODEC_F00_06_GET_STREAM_ID(cmd), CODEC_F00_06_GET_CHANNEL_ID(cmd)));
-
return VINF_SUCCESS;
}
-/* F06 */
static DECLCALLBACK(int) vrbProcSetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
- *pResp = 0;
-
- PDMAUDIODIR enmDir;
-
- uint32_t *pu32Addr = NULL;
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
{
- pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
- enmDir = PDMAUDIODIR_OUT;
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
}
+ *pResp = 0;
+ uint32_t *pu32addr;
+ if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
+ pu32addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- {
- pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
- enmDir = PDMAUDIODIR_IN;
- }
+ pu32addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- {
- pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
- enmDir = PDMAUDIODIR_OUT;
- }
+ pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- {
- pu32Addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
- enmDir = PDMAUDIODIR_IN;
- }
+ pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
+ else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
+ pu32addr = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
else
- {
- enmDir = PDMAUDIODIR_UNKNOWN;
- LogRel2(("HDA: Warning: Unhandled set stream ID command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
- }
-
- /* Do we (re-)assign our input/output SDn (SDI/SDO) IDs? */
- if (enmDir != PDMAUDIODIR_UNKNOWN)
- {
- uint8_t uSD = CODEC_F00_06_GET_STREAM_ID(cmd);
- uint8_t uChannel = CODEC_F00_06_GET_CHANNEL_ID(cmd);
-
- LogFlowFunc(("[NID0x%02x] Setting to stream ID=%RU8, channel=%RU8, enmDir=%RU32\n",
- CODEC_NID(cmd), uSD, uChannel, enmDir));
-
- pThis->paNodes[CODEC_NID(cmd)].node.uSD = uSD;
- pThis->paNodes[CODEC_NID(cmd)].node.uChannel = uChannel;
-
- if (enmDir == PDMAUDIODIR_OUT)
- {
- /** @todo Check if non-interleaved streams need a different channel / SDn? */
-
- /* Propagate to the controller. */
- pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_FRONT, uSD, uChannel);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_CENTER_LFE, uSD, uChannel);
- pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_REAR, uSD, uChannel);
-#endif
- }
- else if (enmDir == PDMAUDIODIR_IN)
- {
- pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_LINE_IN, uSD, uChannel);
-#ifdef VBOX_WITH_HDA_MIC_IN
- pThis->pfnMixerSetStream(pThis->pHDAState, PDMAUDIOMIXERCTL_MIC_IN, uSD, uChannel);
-#endif
- }
- }
-
- if (pu32Addr)
- hdaCodecSetRegisterU8(pu32Addr, cmd, 0);
-
+ AssertFailedReturn(VINF_SUCCESS);
+ hdaCodecSetRegisterU8(pu32addr, cmd, 0);
return VINF_SUCCESS;
}
-/* A0 */
static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param;
else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
@@ -2392,19 +2069,19 @@ static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd
*pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param;
else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param;
- else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32A_param;
- else
- LogRel2(("HDA: Warning: Unhandled get converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
return VINF_SUCCESS;
}
-/* Also see section 3.7.1. */
static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
@@ -2413,35 +2090,42 @@ static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd
hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
- else
- LogRel2(("HDA: Warning: Unhandled set converter format command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
return VINF_SUCCESS;
}
/* F0C */
static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
- else
- LogRel2(("HDA: Warning: Unhandled get EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
return VINF_SUCCESS;
}
/* 70C */
static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
- *pResp = 0;
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
- uint32_t *pu32Reg = NULL;
+ *pResp = 0;
+ uint32_t *pu32Reg;
if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
@@ -2449,10 +2133,8 @@ static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd
else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
else
- LogRel2(("HDA: Warning: Unhandled set EAPD/BTL enabled command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
+ AssertFailedReturn(VINF_SUCCESS);
+ hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
return VINF_SUCCESS;
}
@@ -2460,101 +2142,87 @@ static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd
/* F0F */
static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
- else
- LogRel2(("HDA: Warning: Unhandled get volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
return VINF_SUCCESS;
}
/* 70F */
static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
- *pResp = 0;
-
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
uint32_t *pu32Reg = NULL;
+ *pResp = 0;
if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
- else
- LogRel2(("HDA: Warning: Unhandled set volume knob control command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
+ Assert(pu32Reg);
if (pu32Reg)
hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
- return VINF_SUCCESS;
-}
-
-/* F15 */
-static DECLCALLBACK(int) vrbProcGetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- RT_NOREF(pThis, cmd);
- *pResp = 0;
- return VINF_SUCCESS;
-}
-
-/* 715 */
-static DECLCALLBACK(int) vrbProcSetGPIOData(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- RT_NOREF(pThis, cmd);
- *pResp = 0;
- return VINF_SUCCESS;
-}
-
-/* F16 */
-static DECLCALLBACK(int) vrbProcGetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- RT_NOREF(pThis, cmd);
- *pResp = 0;
- return VINF_SUCCESS;
-}
-
-/* 716 */
-static DECLCALLBACK(int) vrbProcSetGPIOEnableMask(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- RT_NOREF(pThis, cmd);
- *pResp = 0;
return VINF_SUCCESS;
}
/* F17 */
static DECLCALLBACK(int) vrbProcGetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
- /* Note: this is true for ALC885. */
- if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+ /* note: this is true for ALC885 */
+ if (CODEC_NID(cmd) == 0x1 /* AFG */)
*pResp = pThis->paNodes[1].afg.u32F17_param;
- else
- LogRel2(("HDA: Warning: Unhandled get GPIO unsolisted command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
return VINF_SUCCESS;
}
/* 717 */
static DECLCALLBACK(int) vrbProcSetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
- *pResp = 0;
-
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
uint32_t *pu32Reg = NULL;
- if (CODEC_NID(cmd) == STAC9220_NID_AFG)
+ *pResp = 0;
+ if (CODEC_NID(cmd) == 1 /* AFG */)
pu32Reg = &pThis->paNodes[1].afg.u32F17_param;
- else
- LogRel2(("HDA: Warning: Unhandled set GPIO unsolisted command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
+ Assert(pu32Reg);
if (pu32Reg)
hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
return VINF_SUCCESS;
}
/* F1C */
static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
*pResp = 0;
-
if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
@@ -2567,14 +2235,18 @@ static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_
*pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
*pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
- else
- LogRel2(("HDA: Warning: Unhandled get config command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
return VINF_SUCCESS;
}
static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
+ if (CODEC_NID(cmd) >= pThis->cTotalNodes)
+ {
+ LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
+ return VINF_SUCCESS;
+ }
uint32_t *pu32Reg = NULL;
if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
@@ -2588,12 +2260,9 @@ static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
- else
- LogRel2(("HDA: Warning: Unhandled set config command (%RU8) for NID0x%02x: 0x%x\n", u8Offset, CODEC_NID(cmd), cmd));
-
+ Assert(pu32Reg);
if (pu32Reg)
hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
-
return VINF_SUCCESS;
}
@@ -2625,35 +2294,6 @@ static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, uint32_t cmd, uint64
return codecSetConfigX(pThis, cmd, 24);
}
-/* F04 */
-static DECLCALLBACK(int) vrbProcGetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
-
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F04_param;
- else
- LogRel2(("HDA: Warning: Unhandled get SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- return VINF_SUCCESS;
-}
-
-/* 704 */
-static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
-
- uint32_t *pu32Reg = NULL;
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F04_param;
- else
- LogRel2(("HDA: Warning: Unhandled set SDI select command for NID0x%02x: 0x%x\n", CODEC_NID(cmd), cmd));
-
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
- return VINF_SUCCESS;
-}
/**
* HDA codec verb map.
@@ -2661,56 +2301,48 @@ static DECLCALLBACK(int) vrbProcSetSDISelect(PHDACODEC pThis, uint32_t cmd, uint
*/
static const CODECVERB g_aCodecVerbs[] =
{
- /* Verb Verb mask Callback Name
- * ---------- --------------------- ----------------------------------------------------------
- */
- { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter , "GetParameter " },
- { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl , "GetConSelectCtrl " },
- { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl , "SetConSelectCtrl " },
- { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId , "GetStreamId " },
- { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId , "SetStreamId " },
- { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl , "GetPinCtrl " },
- { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl , "SetPinCtrl " },
- { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled , "GetUnsolicitedEnabled " },
- { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled , "SetUnsolicitedEnabled " },
- { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense , "GetPinSense " },
- { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense , "SetPinSense " },
- { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry , "GetConnectionListEntry" },
- { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState , "GetProcessingState " },
- { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState , "SetProcessingState " },
- { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter , "GetDigitalConverter " },
- { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 , "SetDigitalConverter1 " },
- { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 , "SetDigitalConverter2 " },
- { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId , "GetSubId " },
- { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 , "SetSubId0 " },
- { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 , "SetSubId1 " },
- { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 , "SetSubId2 " },
- { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 , "SetSubId3 " },
- { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset , "Reset " },
- { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState , "GetPowerState " },
- { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState , "SetPowerState " },
- { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled , "GetEAPD_BTLEnabled " },
- { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled , "SetEAPD_BTLEnabled " },
- { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl , "GetVolumeKnobCtrl " },
- { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl , "SetVolumeKnobCtrl " },
- { 0x000F1500, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOData , "GetGPIOData " },
- { 0x00071500, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOData , "SetGPIOData " },
- { 0x000F1600, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOEnableMask , "GetGPIOEnableMask " },
- { 0x00071600, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOEnableMask , "SetGPIOEnableMask " },
- { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted , "GetGPIOUnsolisted " },
- { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted , "SetGPIOUnsolisted " },
- { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig , "GetConfig " },
- { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 , "SetConfig0 " },
- { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 , "SetConfig1 " },
- { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 , "SetConfig2 " },
- { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 , "SetConfig3 " },
- { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat , "GetConverterFormat " },
- { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat , "SetConverterFormat " },
- { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier , "GetAmplifier " },
- { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier , "SetAmplifier " },
- { 0x000F0400, CODEC_VERB_8BIT_CMD , vrbProcGetSDISelect , "GetSDISelect " },
- { 0x00070400, CODEC_VERB_8BIT_CMD , vrbProcSetSDISelect , "SetSDISelect " }
- /** @todo Implement 0x7e7: IDT Set GPIO (STAC922x only). */
+/* verb | verb mask | callback */
+/* ----------- -------------------- ----------------------- */
+ { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter },
+ { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl },
+ { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl },
+ { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId },
+ { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId },
+ { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl },
+ { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl },
+ { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled },
+ { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled },
+ { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense },
+ { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense },
+ { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry },
+ { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState },
+ { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState },
+ { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter },
+ { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 },
+ { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 },
+ { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId },
+ { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 },
+ { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 },
+ { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 },
+ { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 },
+ { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset },
+ { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState },
+ { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState },
+ { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled },
+ { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled },
+ { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl },
+ { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl },
+ { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted },
+ { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted },
+ { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig },
+ { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 },
+ { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 },
+ { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 },
+ { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 },
+ { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat },
+ { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat },
+ { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier },
+ { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier },
};
#ifdef DEBUG
@@ -2766,7 +2398,6 @@ static void codecDbgPrintNodeRegF00(PCODECDBGINFO pInfo, uint32_t *paReg00)
codecDbgPrintf(pInfo, "Parameters (F00):\n");
CODECDBG_INDENT
- codecDbgPrintf(pInfo, "Connections: %RU8\n", CODEC_F00_0E_COUNT(paReg00[0xE]));
codecDbgPrintf(pInfo, "Amplifier Caps:\n");
uint32_t uReg = paReg00[0xD];
CODECDBG_INDENT
@@ -2781,7 +2412,7 @@ static void codecDbgPrintNodeRegF00(PCODECDBGINFO pInfo, uint32_t *paReg00)
CODEC_F00_12_NUM_STEPS(uReg),
CODEC_F00_12_STEP_SIZE(uReg),
CODEC_F00_12_OFFSET(uReg),
- RT_BOOL(CODEC_F00_12_IS_CAP_MUTE(uReg)));
+ RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
CODECDBG_UNINDENT
CODECDBG_UNINDENT
}
@@ -2803,7 +2434,7 @@ static void codecDbgPrintNodeAmp(PCODECDBGINFO pInfo, uint32_t *paReg, uint8_t u
#undef CODECDBG_AMP
}
-#if 0 /* unused */
+#if 0 // unused
static void codecDbgPrintNodeConnections(PCODECDBGINFO pInfo, PCODECNODE pNode)
{
if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
@@ -2814,15 +2445,15 @@ static void codecDbgPrintNodeConnections(PCODECDBGINFO pInfo, PCODECNODE pNode)
}
#endif
-static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecursive)
+static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode)
{
- codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.uID, pNode->node.uID);
+ codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.id, pNode->node.id);
- if (pNode->node.uID == STAC9220_NID_ROOT)
+ if (pNode->node.id == STAC9220_NID_ROOT)
{
CODECDBG_PRINT("ROOT\n");
}
- else if (pNode->node.uID == STAC9220_NID_AFG)
+ else if (pNode->node.id == STAC9220_NID_AFG)
{
CODECDBG_PRINT("AFG\n");
CODECDBG_INDENT
@@ -2830,11 +2461,11 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
CODECDBG_UNINDENT
}
- else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("PORT\n");
}
- else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("DAC\n");
CODECDBG_INDENT
@@ -2844,7 +2475,7 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
CODECDBG_UNINDENT
}
- else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("ADC VOLUME\n");
CODECDBG_INDENT
@@ -2853,7 +2484,7 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
CODECDBG_UNINDENT
}
- else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("ADC\n");
CODECDBG_INDENT
@@ -2863,7 +2494,7 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
CODECDBG_UNINDENT
}
- else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("ADC MUX\n");
CODECDBG_INDENT
@@ -2872,78 +2503,46 @@ static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode, bool fRecur
codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
CODECDBG_UNINDENT
}
- else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("PC BEEP\n");
}
- else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("SPDIF OUT\n");
}
- else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("SPDIF IN\n");
}
- else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("DIGITAL IN PIN\n");
}
- else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("DIGITAL OUT PIN\n");
}
- else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("CD\n");
}
- else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("VOLUME KNOB\n");
}
- else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.uID))
+ else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.id))
{
CODECDBG_PRINT("RESERVED\n");
}
else
- CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.uID);
-
- if (fRecursive)
- {
-#define CODECDBG_PRINT_CONLIST_ENTRY(_aNode, _aEntry) \
- if (cCnt >= _aEntry) \
- { \
- const uint8_t uID = RT_BYTE##_aEntry(_aNode->node.au32F02_param[0x0]); \
- if (pNode->node.uID == uID) \
- codecDbgPrintNode(pInfo, _aNode, false /* fRecursive */); \
- }
-
- /* Slow recursion, but this is debug stuff anyway. */
- for (uint8_t i = 0; i < pInfo->pThis->cTotalNodes; i++)
- {
- const PCODECNODE pSubNode = &pInfo->pThis->paNodes[i];
- if (pSubNode->node.uID == pNode->node.uID)
- continue;
-
- const uint8_t cCnt = CODEC_F00_0E_COUNT(pSubNode->node.au32F00_param[0xE]);
- if (cCnt == 0) /* No connections present? Skip. */
- continue;
-
- CODECDBG_INDENT
- CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 1)
- CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 2)
- CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 3)
- CODECDBG_PRINT_CONLIST_ENTRY(pSubNode, 4)
- CODECDBG_UNINDENT
- }
-
-#undef CODECDBG_PRINT_CONLIST_ENTRY
- }
+ CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.id);
}
static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
RT_NOREF(pszArgs);
- pHlp->pfnPrintf(pHlp, "HDA LINK / INPUTS\n");
+ pHlp->pfnPrintf(pHlp, "HDA LINK\n");
CODECDBGINFO dbgInfo;
dbgInfo.pHlp = pHlp;
@@ -2956,10 +2555,8 @@ static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp,
for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
{
PCODECNODE pNode = &pThis->paNodes[i];
-
- /* Start with all nodes which have connection entries set. */
- if (CODEC_F00_0E_COUNT(pNode->node.au32F00_param[0xE]))
- codecDbgPrintNode(&dbgInfo, pNode, true /* fRecursive */);
+ if (pNode->node.au32F00_param[0xE] == 0) /* Start with all nodes connected directly to the HDA (Azalia) link. */
+ codecDbgPrintNode(&dbgInfo, pNode);
}
CODECDBG_UNINDENT
}
@@ -2968,101 +2565,81 @@ static DECLCALLBACK(void) codecDbgSelector(PHDACODEC pThis, PCDBGFINFOHLP pHlp,
{
RT_NOREF(pThis, pHlp, pszArgs);
}
-#endif
-static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, uint64_t *puResp)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(puResp, VERR_INVALID_POINTER);
+#endif /* DEBUG */
- if (CODEC_CAD(cmd) != pThis->id)
- {
- *puResp = 0;
- AssertMsgFailed(("Unknown codec address 0x%x\n", CODEC_CAD(cmd)));
- return VERR_INVALID_PARAMETER;
- }
+static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, PPFNHDACODECVERBPROCESSOR pfn)
+{
+ Assert(CODEC_CAD(cmd) == pThis->id);
+ if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
+ LogFlowFunc(("cmd %x was addressed to reserved node\n", cmd));
if ( CODEC_VERBDATA(cmd) == 0
|| CODEC_NID(cmd) >= pThis->cTotalNodes)
{
- *puResp = 0;
- AssertMsgFailed(("[NID0x%02x] Unknown / invalid node or data (0x%x)\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
- return VERR_INVALID_PARAMETER;
+ *pfn = vrbProcUnimplemented;
+ /// @todo r=michaln: There needs to be a counter to avoid log flooding (see e.g. DevRTC.cpp)
+ LogFlowFunc(("cmd %x was ignored\n", cmd));
+ return VINF_SUCCESS;
}
- /** @todo r=andy Implement a binary search here. */
- for (size_t i = 0; i < pThis->cVerbs; i++)
+ for (int i = 0; i < pThis->cVerbs; ++i)
{
if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb)
{
- int rc2 = pThis->paVerbs[i].pfn(pThis, cmd, puResp);
- AssertRC(rc2);
- Log3Func(("[NID0x%02x] (0x%x) %s: 0x%x -> 0x%x\n",
- CODEC_NID(cmd), pThis->paVerbs[i].verb, pThis->paVerbs[i].pszName, CODEC_VERB_PAYLOAD8(cmd), *puResp));
- return rc2;
+ *pfn = pThis->paVerbs[i].pfn;
+ return VINF_SUCCESS;
}
}
- *puResp = 0;
- LogFunc(("[NID0x%02x] Callback for %x not found\n", CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
- return VERR_NOT_FOUND;
+ *pfn = vrbProcUnimplemented;
+ LogFlowFunc(("callback for %x wasn't found\n", CODEC_VERBDATA(cmd)));
+ return VINF_SUCCESS;
}
/*
* APIs exposed to DevHDA.
*/
-int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg)
+/**
+ *
+ * routines open one of the voices (IN, OUT) with corresponding parameters.
+ * this routine could be called from HDA on setting/resseting sound format.
+ *
+ * @todo Probably passed settings should be verified (if AFG's declared proposed
+ * format) before enabling.
+ */
+int hdaCodecOpenStream(PHDACODEC pThis, ENMSOUNDSOURCE enmSoundSource, PPDMAUDIOSTREAMCFG pCfg)
{
AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- int rc = VINF_SUCCESS;
- switch (enmMixerCtl)
+ int rc;
+ switch (enmSoundSource)
{
- case PDMAUDIOMIXERCTL_VOLUME_MASTER:
- case PDMAUDIOMIXERCTL_FRONT:
-#ifdef VBOX_WITH_HDA_51_SURROUND
- case PDMAUDIOMIXERCTL_CENTER_LFE:
- case PDMAUDIOMIXERCTL_REAR:
-#endif
- {
+ case PI_INDEX:
+ rc = pThis->pfnOpenIn(pThis->pHDAState, "hda.in", PDMAUDIORECSOURCE_LINE_IN, pCfg);
break;
- }
- case PDMAUDIOMIXERCTL_LINE_IN:
#ifdef VBOX_WITH_HDA_MIC_IN
- case PDMAUDIOMIXERCTL_MIC_IN:
+ case MC_INDEX:
+ rc = pThis->pfnOpenIn(pThis->pHDAState, "hda.mc", PDMAUDIORECSOURCE_MIC, pCfg);
+ break;
#endif
- {
+ case PO_INDEX:
+ rc = pThis->pfnOpenOut(pThis->pHDAState, "hda.out", pCfg);
break;
- }
+
default:
- AssertMsgFailed(("Mixer control %d not implemented\n", enmMixerCtl));
+ AssertMsgFailed(("Index %ld not implemented\n", enmSoundSource));
rc = VERR_NOT_IMPLEMENTED;
- break;
}
- if (RT_SUCCESS(rc))
- rc = pThis->pfnMixerAddStream(pThis->pHDAState, enmMixerCtl, pCfg);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- int rc = pThis->pfnMixerRemoveStream(pThis->pHDAState, enmMixerCtl);
-
LogFlowFuncLeaveRC(rc);
return rc;
}
int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM)
{
- AssertLogRelMsgReturn(pThis->cTotalNodes == STAC9221_NUM_NODES, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
+ AssertLogRelMsgReturn(pThis->cTotalNodes == 0x1c, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
VERR_INTERNAL_ERROR);
SSMR3PutU32(pSSM, pThis->cTotalNodes);
for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
@@ -3113,14 +2690,14 @@ int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
{
- uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.uID;
+ uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.id;
int rc = SSMR3GetStructEx(pSSM, &pThis->paNodes[idxNode].SavedState,
sizeof(pThis->paNodes[idxNode].SavedState),
fFlags, pFields, NULL);
if (RT_FAILURE(rc))
return rc;
- AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.uID,
- ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.uID, idOld),
+ AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.id,
+ ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.id, idOld),
VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
}
@@ -3128,171 +2705,78 @@ int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
* Update stuff after changing the state.
*/
if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
- hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_FRONT);
+ hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_PCM);
else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
- hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_FRONT);
+ hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_PCM);
hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
return VINF_SUCCESS;
}
-/**
- * Powers off the codec.
- *
- * @param pThis Codec to power off.
- */
-void hdaCodecPowerOff(PHDACODEC pThis)
-{
- if (!pThis)
- return;
-
- LogFlowFuncEnter();
-
- LogRel2(("HDA: Powering off codec ...\n"));
-
- int rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_FRONT);
- AssertRC(rc2);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE);
- AssertRC(rc2);
- rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_REAR);
- AssertRC(rc2);
-#endif
-
-#ifdef VBOX_WITH_HDA_MIC_IN
- rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_MIC_IN);
- AssertRC(rc2);
-#endif
- rc2 = hdaCodecRemoveStream(pThis, PDMAUDIOMIXERCTL_LINE_IN);
- AssertRC(rc2);
-}
-
-void hdaCodecDestruct(PHDACODEC pThis)
+int hdaCodecDestruct(PHDACODEC pThis)
{
- if (!pThis)
- return;
-
- LogFlowFuncEnter();
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
if (pThis->paNodes)
{
RTMemFree(pThis->paNodes);
pThis->paNodes = NULL;
}
+
+ return VINF_SUCCESS;
}
int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis,
uint16_t uLUN, PCFGMNODE pCfg)
{
AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+ AssertPtrReturn(pThis, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- pThis->id = uLUN;
- pThis->paVerbs = &g_aCodecVerbs[0];
- pThis->cVerbs = RT_ELEMENTS(g_aCodecVerbs);
+ pThis->id = uLUN;
+ pThis->paVerbs = &g_aCodecVerbs[0];
+ pThis->cVerbs = RT_ELEMENTS(g_aCodecVerbs);
+ pThis->pfnLookup = codecLookup;
#ifdef DEBUG
pThis->pfnDbgSelector = codecDbgSelector;
pThis->pfnDbgListNodes = codecDbgListNodes;
#endif
- pThis->pfnLookup = codecLookup;
-
int rc = stac9220Construct(pThis);
- AssertRCReturn(rc, rc);
-
- /* Common root node initializers. */
- pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
- pThis->paNodes[STAC9220_NID_ROOT].root.node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
-
- /* Common AFG node initializers. */
- pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
- pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0x5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
- pThis->paNodes[STAC9220_NID_AFG].afg.node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
- pThis->paNodes[STAC9220_NID_AFG].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
-
- do
- {
- /* Initialize the streams to some default values (44.1 kHz, 16-bit signed, 2 channels).
- * The codec's (fixed) delivery rate is 48kHz, so a frame will be delivered every 20.83us. */
- PDMAUDIOSTREAMCFG strmCfg;
- RT_ZERO(strmCfg);
- strmCfg.uHz = 44100;
- strmCfg.cChannels = 2;
- strmCfg.enmFormat = PDMAUDIOFMT_S16;
- strmCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- /* Note: Adding the default input/output streams is *not* critical for the overall
- * codec construction result. */
-
- /*
- * Output streams.
- */
- strmCfg.enmDir = PDMAUDIODIR_OUT;
-
- /* Front. */
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Front");
- strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_FRONT;
- int rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_FRONT, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add front output stream: %Rrc\n", rc2));
-
-#ifdef VBOX_WITH_HDA_51_SURROUND
- /* Center / LFE. */
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Center / LFE");
- strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_CENTER_LFE;
- /** @todo Handle mono channel if only center *or* LFE is available? */
- rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_CENTER_LFE, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add center/LFE output stream: %Rrc\n", rc2));
-
- /* Rear. */
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Rear");
- strmCfg.DestSource.Dest = PDMAUDIOPLAYBACKDEST_REAR;
- rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_REAR, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add rear output stream: %Rrc\n", rc2));
-#endif
-
- /*
- * Input streams.
- */
- strmCfg.enmDir = PDMAUDIODIR_IN;
-
+ AssertRC(rc);
+
+ /* common root node initializers */
+ pThis->paNodes[0].node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
+ pThis->paNodes[0].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
+ /* common AFG node initializers */
+ pThis->paNodes[1].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
+ pThis->paNodes[1].node.au32F00_param[5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
+ pThis->paNodes[1].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
+
+ /* This codec uses a fixed setting (44.1 kHz, 16-bit signed, 2 channels). */
+ pThis->strmCfg.uHz = 44100;
+ pThis->strmCfg.cChannels = 2;
+ pThis->strmCfg.enmFormat = AUD_FMT_S16;
+ pThis->strmCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
+
+ hdaCodecOpenStream(pThis, PI_INDEX, &pThis->strmCfg);
#ifdef VBOX_WITH_HDA_MIC_IN
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Microphone In");
- strmCfg.DestSource.Source = PDMAUDIORECSOURCE_MIC;
- rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_MIC_IN, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add microphone input stream: %Rrc\n", rc2));
+ hdaCodecOpenStream(pThis, MC_INDEX, &pThis->strmCfg);
#endif
- RTStrPrintf(strmCfg.szName, RT_ELEMENTS(strmCfg.szName), "Line In");
- strmCfg.DestSource.Source = PDMAUDIORECSOURCE_LINE;
- rc2 = hdaCodecAddStream(pThis, PDMAUDIOMIXERCTL_LINE_IN, &strmCfg);
- if (RT_FAILURE(rc2))
- LogRel2(("HDA: Failed to add line input stream: %Rrc\n", rc2));
+ hdaCodecOpenStream(pThis, PO_INDEX, &pThis->strmCfg);
- } while (0);
+ /* Initialize the AFG node with the fixed setting. */
+ pThis->paNodes[1].node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
- /*
- * Reset nodes.
- */
AssertPtr(pThis->paNodes);
AssertPtr(pThis->pfnCodecNodeReset);
for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
- /*
- * Set initial volume.
- */
- hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_FRONT);
+ hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_PCM);
hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
-#ifdef VBOX_WITH_HDA_MIC_IN
- #error "Implement mic-in support!"
-#endif
- LogFlowFuncLeaveRC(rc);
- return rc;
+ return VINF_SUCCESS;
}
diff --git a/src/VBox/Devices/Audio/HDACodec.h b/src/VBox/Devices/Audio/HDACodec.h
deleted file mode 100644
index 24e545f..0000000
--- a/src/VBox/Devices/Audio/HDACodec.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/* $Id: HDACodec.h $ */
-/** @file
- * DevIchHdaCodec - VBox ICH Intel HD Audio Codec.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef DEV_HDA_CODEC_H
-#define DEV_HDA_CODEC_H
-
-/** The ICH HDA (Intel) controller. */
-typedef struct HDASTATE *PHDASTATE;
-/** The ICH HDA (Intel) codec state. */
-typedef struct HDACODEC *PHDACODEC;
-/** The HDA host driver backend. */
-typedef struct HDADRIVER *PHDADRIVER;
-typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR;
-typedef struct PDMAUDIOGSTSTRMOUT *PPDMAUDIOGSTSTRMOUT;
-typedef struct PDMAUDIOGSTSTRMIN *PPDMAUDIOGSTSTRMIN;
-
-/**
- * Verb processor method.
- */
-typedef DECLCALLBACK(int) FNHDACODECVERBPROCESSOR(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp);
-typedef FNHDACODECVERBPROCESSOR *PFNHDACODECVERBPROCESSOR;
-typedef FNHDACODECVERBPROCESSOR **PPFNHDACODECVERBPROCESSOR;
-
-/* PRM 5.3.1 */
-#define CODEC_RESPONSE_UNSOLICITED RT_BIT_64(34)
-
-typedef struct CODECVERB
-{
- /** Verb. */
- uint32_t verb;
- /** Verb mask. */
- uint32_t mask;
- /** Function pointer for implementation callback. */
- PFNHDACODECVERBPROCESSOR pfn;
- /** Friendly name, for debugging. */
- const char *pszName;
-} CODECVERB;
-
-union CODECNODE;
-typedef union CODECNODE CODECNODE, *PCODECNODE;
-
-/**
- * Structure for keeping a HDA codec state.
- */
-typedef struct HDACODEC
-{
- uint16_t id;
- uint16_t u16VendorId;
- uint16_t u16DeviceId;
- uint8_t u8BSKU;
- uint8_t u8AssemblyId;
- /** List of assigned HDA drivers to this codec.
- * A driver only can be assigned to one codec at a time. */
- RTLISTANCHOR lstDrv;
-
- CODECVERB const *paVerbs;
- size_t cVerbs;
-
- PCODECNODE paNodes;
- /** Pointer to HDA state (controller) this
- * codec is assigned to. */
- PHDASTATE pHDAState;
- bool fInReset;
-
- const uint8_t cTotalNodes;
- const uint8_t *au8Ports;
- const uint8_t *au8Dacs;
- const uint8_t *au8AdcVols;
- const uint8_t *au8Adcs;
- const uint8_t *au8AdcMuxs;
- const uint8_t *au8Pcbeeps;
- const uint8_t *au8SpdifIns;
- const uint8_t *au8SpdifOuts;
- const uint8_t *au8DigInPins;
- const uint8_t *au8DigOutPins;
- const uint8_t *au8Cds;
- const uint8_t *au8VolKnobs;
- const uint8_t *au8Reserveds;
- const uint8_t u8AdcVolsLineIn;
- const uint8_t u8DacLineOut;
-
- /** Callbacks to the HDA controller, mostly used for multiplexing to the various host backends. */
- DECLR3CALLBACKMEMBER(int, pfnMixerAddStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg));
- DECLR3CALLBACKMEMBER(int, pfnMixerRemoveStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl));
- DECLR3CALLBACKMEMBER(int, pfnMixerSetStream, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, uint8_t uSD, uint8_t uChannel));
- DECLR3CALLBACKMEMBER(int, pfnMixerSetVolume, (PHDASTATE pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOVOLUME pVol));
- /** Callbacks by codec implementation. */
- DECLR3CALLBACKMEMBER(int, pfnLookup, (PHDACODEC pThis, uint32_t uVerb, uint64_t *puResp));
- DECLR3CALLBACKMEMBER(int, pfnReset, (PHDACODEC pThis));
- DECLR3CALLBACKMEMBER(int, pfnCodecNodeReset, (PHDACODEC pThis, uint8_t, PCODECNODE));
- /** These callbacks are set by codec implementation to answer debugger requests. */
- DECLR3CALLBACKMEMBER(void, pfnDbgListNodes, (PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs));
- DECLR3CALLBACKMEMBER(void, pfnDbgSelector, (PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs));
-} HDACODEC;
-
-int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis, uint16_t uLUN, PCFGMNODE pCfg);
-void hdaCodecDestruct(PHDACODEC pThis);
-void hdaCodecPowerOff(PHDACODEC pThis);
-int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM);
-int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion);
-int hdaCodecAddStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl, PPDMAUDIOSTREAMCFG pCfg);
-int hdaCodecRemoveStream(PHDACODEC pThis, PDMAUDIOMIXERCTL enmMixerCtl);
-
-#define HDA_SSM_VERSION 6
-/** Introduced dynamic number of streams + stream identifiers for serialization.
- * Bug: Did not save the BDLE states correctly.
- * Those will be skipped on load then. */
-#define HDA_SSM_VERSION_5 5
-/** Since this version the number of MMIO registers can be flexible. */
-#define HDA_SSM_VERSION_4 4
-#define HDA_SSM_VERSION_3 3
-#define HDA_SSM_VERSION_2 2
-#define HDA_SSM_VERSION_1 1
-
-#endif /* DEV_HDA_CODEC_H */
-
diff --git a/src/VBox/Devices/Audio/alsa_mangling.h b/src/VBox/Devices/Audio/alsa_mangling.h
index 8582956..fde5840 100644
--- a/src/VBox/Devices/Audio/alsa_mangling.h
+++ b/src/VBox/Devices/Audio/alsa_mangling.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2013-2016 Oracle Corporation
+ * Copyright (C) 2013-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,10 +21,6 @@
#define ALSA_MANGLER(symbol) VBox_##symbol
-#define snd_device_name_hint ALSA_MANGLER(snd_device_name_hint)
-#define snd_device_name_get_hint ALSA_MANGLER(snd_device_name_get_hint)
-#define snd_device_name_free_hint ALSA_MANGLER(snd_device_name_free_hint)
-
#define snd_pcm_hw_params_any ALSA_MANGLER(snd_pcm_hw_params_any)
#define snd_pcm_close ALSA_MANGLER(snd_pcm_close)
#define snd_pcm_avail_update ALSA_MANGLER(snd_pcm_avail_update)
@@ -55,6 +51,5 @@
#define snd_pcm_hw_params_set_format ALSA_MANGLER(snd_pcm_hw_params_set_format)
#define snd_pcm_sw_params_current ALSA_MANGLER(snd_pcm_sw_params_current)
#define snd_pcm_sw_params_set_start_threshold ALSA_MANGLER(snd_pcm_sw_params_set_start_threshold)
-#define snd_pcm_sw_params_set_avail_min ALSA_MANGLER(snd_pcm_sw_params_set_avail_min)
#endif /* !AUDIO_ALSA_MANGLING_H */
diff --git a/src/VBox/Devices/Audio/alsa_stubs.c b/src/VBox/Devices/Audio/alsa_stubs.c
index d59f2e7..cda485b 100644
--- a/src/VBox/Devices/Audio/alsa_stubs.c
+++ b/src/VBox/Devices/Audio/alsa_stubs.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -35,16 +35,6 @@
return pfn_ ## function shortsig; \
}
-PROXY_STUB(snd_device_name_hint, int,
- (int card, const char *iface, void ***hints),
- (card, iface, hints))
-PROXY_STUB(snd_device_name_free_hint, int,
- (void **hints),
- (hints))
-PROXY_STUB(snd_device_name_get_hint, char *,
- (const void *hint, const char *id),
- (hint, id))
-
PROXY_STUB(snd_pcm_hw_params_any, int,
(snd_pcm_t *pcm, snd_pcm_hw_params_t *params),
(pcm, params))
@@ -117,9 +107,6 @@ PROXY_STUB(snd_pcm_sw_params_current, int,
PROXY_STUB(snd_pcm_sw_params_set_start_threshold, int,
(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
(pcm, params, val))
-PROXY_STUB(snd_pcm_sw_params_set_avail_min, int,
- (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
- (pcm, params, val))
typedef struct
{
@@ -130,10 +117,6 @@ typedef struct
#define ELEMENT(function) { #function , (void (**)(void)) & pfn_ ## function }
static SHARED_FUNC SharedFuncs[] =
{
- ELEMENT(snd_device_name_hint),
- ELEMENT(snd_device_name_get_hint),
- ELEMENT(snd_device_name_free_hint),
-
ELEMENT(snd_pcm_hw_params_any),
ELEMENT(snd_pcm_close),
ELEMENT(snd_pcm_avail_update),
@@ -164,7 +147,6 @@ static SHARED_FUNC SharedFuncs[] =
ELEMENT(snd_pcm_hw_params_set_format),
ELEMENT(snd_pcm_sw_params_current),
ELEMENT(snd_pcm_sw_params_set_start_threshold),
- ELEMENT(snd_pcm_sw_params_set_avail_min)
};
#undef ELEMENT
diff --git a/src/VBox/Devices/Audio/alsa_stubs.h b/src/VBox/Devices/Audio/alsa_stubs.h
index 6464f7a..889add3 100644
--- a/src/VBox/Devices/Audio/alsa_stubs.h
+++ b/src/VBox/Devices/Audio/alsa_stubs.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Audio/pulse_mangling.h b/src/VBox/Devices/Audio/pulse_mangling.h
index 0069210..8b02ef3 100644
--- a/src/VBox/Devices/Audio/pulse_mangling.h
+++ b/src/VBox/Devices/Audio/pulse_mangling.h
@@ -5,7 +5,7 @@
*/
/*
- * Copyright (C) 2013-2016 Oracle Corporation
+ * Copyright (C) 2013-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -41,9 +41,6 @@
#define pa_stream_writable_size PULSE_MANGLER(pa_stream_writable_size)
#define pa_context_connect PULSE_MANGLER(pa_context_connect)
#define pa_context_disconnect PULSE_MANGLER(pa_context_disconnect)
-#define pa_context_get_server_info PULSE_MANGLER(pa_context_get_server_info)
-#define pa_context_get_sink_info_by_name PULSE_MANGLER(pa_context_get_sink_info_by_name)
-#define pa_context_get_source_info_by_name PULSE_MANGLER(pa_context_get_source_info_by_name)
#define pa_context_get_state PULSE_MANGLER(pa_context_get_state)
#define pa_context_unref PULSE_MANGLER(pa_context_unref)
#define pa_context_errno PULSE_MANGLER(pa_context_errno)
diff --git a/src/VBox/Devices/Audio/pulse_stubs.c b/src/VBox/Devices/Audio/pulse_stubs.c
index f4af6ab..c38c090 100644
--- a/src/VBox/Devices/Audio/pulse_stubs.c
+++ b/src/VBox/Devices/Audio/pulse_stubs.c
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -110,20 +110,12 @@ PROXY_STUB (pa_stream_writable_size, size_t,
(pa_stream *p),
(p))
PROXY_STUB (pa_context_connect, int,
- (pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api),
+ (pa_context *c, const char *server, pa_context_flags_t flags,
+ const pa_spawn_api *api),
(c, server, flags, api))
PROXY_STUB_VOID(pa_context_disconnect,
(pa_context *c),
(c))
-PROXY_STUB (pa_context_get_server_info, pa_operation*,
- (pa_context *c, pa_server_info_cb_t cb, void *userdata),
- (c, cb, userdata))
-PROXY_STUB (pa_context_get_sink_info_by_name, pa_operation*,
- (pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata),
- (c, name, cb, userdata))
-PROXY_STUB (pa_context_get_source_info_by_name, pa_operation*,
- (pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata),
- (c, name, cb, userdata))
PROXY_STUB (pa_context_get_state, pa_context_state_t,
(pa_context *c),
(c))
@@ -227,9 +219,6 @@ static SHARED_FUNC SharedFuncs[] =
ELEMENT(pa_stream_writable_size),
ELEMENT(pa_context_connect),
ELEMENT(pa_context_disconnect),
- ELEMENT(pa_context_get_server_info),
- ELEMENT(pa_context_get_sink_info_by_name),
- ELEMENT(pa_context_get_source_info_by_name),
ELEMENT(pa_context_get_state),
ELEMENT(pa_context_unref),
ELEMENT(pa_context_errno),
@@ -295,3 +284,4 @@ int audioLoadPulseLib(void)
isLibLoaded = YES;
return rc;
}
+
diff --git a/src/VBox/Devices/Audio/pulse_stubs.h b/src/VBox/Devices/Audio/pulse_stubs.h
index f63980f..af393d3 100644
--- a/src/VBox/Devices/Audio/pulse_stubs.h
+++ b/src/VBox/Devices/Audio/pulse_stubs.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2016 Oracle Corporation
+ * Copyright (C) 2006-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Devices/Audio_50/sys-queue.h b/src/VBox/Devices/Audio/sys-queue.h
similarity index 100%
rename from src/VBox/Devices/Audio_50/sys-queue.h
rename to src/VBox/Devices/Audio/sys-queue.h
diff --git a/src/VBox/Devices/Audio/testcase/Makefile.kmk b/src/VBox/Devices/Audio/testcase/Makefile.kmk
index 54e6351..5f4a4cd 100644
--- a/src/VBox/Devices/Audio/testcase/Makefile.kmk
+++ b/src/VBox/Devices/Audio/testcase/Makefile.kmk
@@ -4,7 +4,7 @@
#
#
-# Copyright (C) 2014-2016 Oracle Corporation
+# Copyright (C) 2014-2015 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
@@ -24,13 +24,12 @@ if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBO
TESTING += $(tstAudioMixBuffer_0_OUTDIR)/tstAudioMixBuffer.run
tstAudioMixBuffer_TEMPLATE = VBOXR3TSTEXE
- tstAudioMixBuffer_DEFS = TESTCASE
- tstAudioMixBuffer_DEFS.debug = VBOX_WITH_EF_WRAPS
- tstAudioMixBuffer_SOURCES = \
+ tstAudioMixBuffer_DEFS += TESTCASE
+ tstAudioMixBuffer_SOURCES = \
tstAudioMixBuffer.cpp \
../AudioMixBuffer.cpp \
../DrvAudioCommon.cpp
- tstAudioMixBuffer_LIBS = $(LIB_RUNTIME)
+ tstAudioMixBuffer_LIBS = $(LIB_RUNTIME)
$$(tstAudioMixBuffer_0_OUTDIR)/tstAudioMixBuffer.run: $$(tstAudioMixBuffer_1_STAGE_TARGET)
export VBOX_LOG_DEST=nofile; $(tstAudioMixBuffer_1_STAGE_TARGET) quiet
diff --git a/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp b/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
index 11859a7..b297c93 100644
--- a/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
+++ b/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2014-2016 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -42,17 +42,14 @@ static int tstSingle(RTTEST hTest)
PDMAUDIOSTREAMCFG config =
{
- "44100Hz, 2 Channels, S16",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 44100, /* Hz */
- 2 /* Channels */,
- PDMAUDIOFMT_S16 /* Format */,
+ 44100, /* Hz */
+ 2 /* Channels */,
+ AUD_FMT_S16 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
- PDMAUDIOPCMPROPS props;
+ PDMPCMPROPS props;
- int rc = DrvAudioHlpStreamCfgToProps(&config, &props);
+ int rc = DrvAudioStreamCfgToProps(&config, &props);
AssertRC(rc);
uint32_t cBufSize = _1K;
@@ -71,67 +68,64 @@ static int tstSingle(RTTEST hTest)
/*
* Absolute writes.
*/
- uint32_t cSamplesRead = 0, cSamplesWritten = 0, cSamplesWrittenAbs = 0;
+ uint32_t read = 0, written = 0, written_abs = 0;
int8_t samples8 [2] = { 0x12, 0x34 };
int16_t samples16[2] = { 0xAA, 0xBB };
int32_t samples32[2] = { 0xCC, 0xDD };
- /* int64_t samples64[2] = { 0xEE, 0xFF }; - unused */
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0, &samples8, sizeof(samples8), &cSamplesWritten));
- RTTESTI_CHECK(cSamplesWritten == 0 /* Samples */);
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0, &samples8, sizeof(samples8), &written));
+ RTTESTI_CHECK(written == 0 /* Samples */);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0, &samples16, sizeof(samples16), &cSamplesWritten));
- RTTESTI_CHECK(cSamplesWritten == 1 /* Samples */);
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0, &samples16, sizeof(samples16), &written));
+ RTTESTI_CHECK(written == 1 /* Samples */);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 2, &samples32, sizeof(samples32), &cSamplesWritten));
- RTTESTI_CHECK(cSamplesWritten == 2 /* Samples */);
- cSamplesWrittenAbs = 0;
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 2, &samples32, sizeof(samples32), &written));
+ RTTESTI_CHECK(written == 2 /* Samples */);
+ written_abs = 0;
/* Beyond buffer. */
RTTESTI_CHECK_RC(AudioMixBufWriteAt(&mb, AudioMixBufSize(&mb) + 1, &samples16, sizeof(samples16),
- &cSamplesWritten), VINF_BUFFER_OVERFLOW);
- /** @todo (bird): this was checking for VERR_BUFFER_OVERFLOW, which do you want
- * the function to actually return? */
+ &written), VERR_BUFFER_OVERFLOW);
/*
* Circular writes.
*/
- uint32_t cToWrite = AudioMixBufSize(&mb) - cSamplesWrittenAbs - 1; /* -1 as padding plus -2 samples for above. */
+ uint32_t cToWrite = AudioMixBufSize(&mb) - written_abs - 1; /* -1 as padding plus -2 samples for above. */
for (uint32_t i = 0; i < cToWrite; i++)
{
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &cSamplesWritten));
- RTTESTI_CHECK(cSamplesWritten == 1);
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &written));
+ RTTESTI_CHECK(written == 1);
}
RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
RTTESTI_CHECK(AudioMixBufFree(&mb) == 1);
RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, 1U));
- RTTESTI_CHECK(AudioMixBufUsed(&mb) == cToWrite + cSamplesWrittenAbs /* + last absolute write */);
+ RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cToWrite + written_abs /* + last absolute write */);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &cSamplesWritten));
- RTTESTI_CHECK(cSamplesWritten == 1);
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &written));
+ RTTESTI_CHECK(written == 1);
RTTESTI_CHECK(AudioMixBufFree(&mb) == 0);
- RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, 0U));
- RTTESTI_CHECK(AudioMixBufUsed(&mb) == cBufSize);
+ RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == (uint32_t)AUDIOMIXBUF_S2B(&mb, 0));
+ RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cBufSize);
/* Circular reads. */
- uint32_t cToRead = AudioMixBufSize(&mb) - cSamplesWrittenAbs - 1;
+ uint32_t cToRead = AudioMixBufSize(&mb) - written_abs - 1;
for (uint32_t i = 0; i < cToWrite; i++)
{
- RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &cSamplesRead));
- RTTESTI_CHECK(cSamplesRead == 1);
- AudioMixBufFinish(&mb, cSamplesRead);
+ RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &read));
+ RTTESTI_CHECK(read == 1);
+ AudioMixBufFinish(&mb, read);
}
RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
- RTTESTI_CHECK(AudioMixBufFree(&mb) == AudioMixBufSize(&mb) - cSamplesWrittenAbs - 1);
- RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - cSamplesWrittenAbs - 1));
- RTTESTI_CHECK(AudioMixBufUsed(&mb) == cBufSize - cToRead + cSamplesWrittenAbs);
+ RTTESTI_CHECK(AudioMixBufFree(&mb) == AudioMixBufSize(&mb) - written_abs - 1);
+ RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - written_abs - 1));
+ RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cBufSize - cToRead + written_abs);
- RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &cSamplesRead));
- RTTESTI_CHECK(cSamplesRead == 1);
- AudioMixBufFinish(&mb, cSamplesRead);
- RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize - cSamplesWrittenAbs);
- RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - cSamplesWrittenAbs));
- RTTESTI_CHECK(AudioMixBufUsed(&mb) == cSamplesWrittenAbs);
+ RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &read));
+ RTTESTI_CHECK(read == 1);
+ AudioMixBufFinish(&mb, read);
+ RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize - written_abs);
+ RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - written_abs));
+ RTTESTI_CHECK(AudioMixBufProcessed(&mb) == written_abs);
AudioMixBufDestroy(&mb);
@@ -140,22 +134,20 @@ static int tstSingle(RTTEST hTest)
static int tstParentChild(RTTEST hTest)
{
- uint32_t cSamples = 16;
- uint32_t cBufSize = RTRandU32Ex(cSamples /* Min */, 256 /* Max */);
+ RTTestSubF(hTest, "2 Children -> Parent");
+
+ uint32_t cBufSize = _1K;
PDMAUDIOSTREAMCFG cfg_p =
{
- "44100Hz, 2 Channels, S16",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 44100, /* Hz */
- 2 /* Channels */,
- PDMAUDIOFMT_S16 /* Format */,
+ 44100, /* Hz */
+ 2 /* Channels */,
+ AUD_FMT_S16 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
+ PDMPCMPROPS props;
- PDMAUDIOPCMPROPS props;
- int rc = DrvAudioHlpStreamCfgToProps(&cfg_p, &props);
+ int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
AssertRC(rc);
PDMAUDIOMIXBUF parent;
@@ -163,16 +155,13 @@ static int tstParentChild(RTTEST hTest)
PDMAUDIOSTREAMCFG cfg_c1 = /* Upmixing to parent */
{
- "22050Hz, 2 Channels, S16",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 22050, /* Hz */
- 2 /* Channels */,
- PDMAUDIOFMT_S16 /* Format */,
+ 22100, /* Hz */
+ 2 /* Channels */,
+ AUD_FMT_S16 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
- rc = DrvAudioHlpStreamCfgToProps(&cfg_c1, &props);
+ rc = DrvAudioStreamCfgToProps(&cfg_c1, &props);
AssertRC(rc);
PDMAUDIOMIXBUF child1;
@@ -181,16 +170,13 @@ static int tstParentChild(RTTEST hTest)
PDMAUDIOSTREAMCFG cfg_c2 = /* Downmixing to parent */
{
- "48000Hz, 2 Channels, S16",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 48000, /* Hz */
- 2 /* Channels */,
- PDMAUDIOFMT_S16 /* Format */,
+ 48000, /* Hz */
+ 2 /* Channels */,
+ AUD_FMT_S16 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
- rc = DrvAudioHlpStreamCfgToProps(&cfg_c2, &props);
+ rc = DrvAudioStreamCfgToProps(&cfg_c2, &props);
AssertRC(rc);
PDMAUDIOMIXBUF child2;
@@ -203,51 +189,49 @@ static int tstParentChild(RTTEST hTest)
uint32_t cbBuf = _1K;
char pvBuf[_1K];
int16_t samples[32] = { 0xAA, 0xBB };
- uint32_t cSamplesRead, cSamplesWritten, cSamplesMixed;
-
- uint32_t cSamplesChild1 = cSamples;
- uint32_t cSamplesChild2 = cSamples;
+ uint32_t read , written, mixed, temp;
- uint32_t t = RTRandU32() % 1024;
+ //unused//uint32_t cChild1Free = cBufSize;
+ //unused//uint32_t cChild1Mixed = 0;
+ //unused//uint32_t cSamplesParent1 = 16;
+ uint32_t cSamplesChild1 = 16;
- RTTestPrintf(hTest, RTTESTLVL_DEBUG, "%RU32 iterations total\n", t);
+ //unused//uint32_t cChild2Free = cBufSize;
+ //unused//uint32_t cChild2Mixed = 0;
+ //unused//uint32_t cSamplesParent2 = 16;
+ uint32_t cSamplesChild2 = 16;
- /*
- * Using AudioMixBufWriteAt for writing to children.
- */
- RTTestSubF(hTest, "2 Children -> Parent (AudioMixBufWriteAt)");
+ uint32_t t = RTRandU32() % 64;
for (uint32_t i = 0; i < t; i++)
{
RTTestPrintf(hTest, RTTESTLVL_DEBUG, "i=%RU32\n", i);
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child1, 0, &samples, sizeof(samples), &cSamplesWritten));
- RTTESTI_CHECK_MSG_BREAK(cSamplesWritten == cSamplesChild1, ("Child1: Expected %RU32 written samples, got %RU32\n", cSamplesChild1, cSamplesWritten));
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child1, cSamplesWritten, &cSamplesMixed));
- RTTESTI_CHECK_MSG_BREAK(AudioMixBufLive(&child1) == cSamplesMixed, ("Child1: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufLive(&child1), cSamplesMixed));
- RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child1) == AUDIOMIXBUF_S2S_RATIO(&parent, cSamplesMixed), ("Child1: Expected %RU32 used samples, got %RU32\n", AudioMixBufLive(&child1), AUDIOMIXBUF_S2S_RATIO(&parent, cSamplesMixed)));
- RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&parent) == 0, ("Parent: Expected 0 used samples, got %RU32\n", AudioMixBufUsed(&parent)));
-
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child2, 0, &samples, sizeof(samples), &cSamplesWritten));
- RTTESTI_CHECK_MSG_BREAK(cSamplesWritten == cSamplesChild2, ("Child2: Expected %RU32 written samples, got %RU32\n", cSamplesChild2, cSamplesWritten));
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child2, cSamplesWritten, &cSamplesMixed));
- RTTESTI_CHECK_MSG_BREAK(AudioMixBufLive(&child2) == cSamplesMixed, ("Child2: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufLive(&child2), AudioMixBufUsed(&parent)));
- RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child2) == AUDIOMIXBUF_S2S_RATIO(&parent, cSamplesMixed), ("Child2: Expected %RU32 used samples, got %RU32\n", AudioMixBufLive(&child2), AUDIOMIXBUF_S2S_RATIO(&parent, cSamplesMixed)));
- RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&parent) == 0, ("Parent2: Expected 0 used samples, got %RU32\n", AudioMixBufUsed(&parent)));
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child1, 0, &samples, sizeof(samples), &written));
+ RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild1, ("Child1: Expected %RU32 written samples, got %RU32\n", cSamplesChild1, written));
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child1, written, &mixed));
+ temp = AudioMixBufProcessed(&parent) - AudioMixBufMixed(&child2);
+ RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child1) == temp, ("Child1: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child1), temp));
+
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child2, 0, &samples, sizeof(samples), &written));
+ RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild2, ("Child2: Expected %RU32 written samples, got %RU32\n", cSamplesChild2, written));
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child2, written, &mixed));
+ temp = AudioMixBufProcessed(&parent) - AudioMixBufMixed(&child1);
+ RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child2) == temp, ("Child2: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child2), temp));
}
- RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufLive(&child1) + AudioMixBufLive(&child2));
+ RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child1) + AudioMixBufMixed(&child2));
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, pvBuf, cbBuf, &cSamplesRead));
- if (!cSamplesRead)
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, pvBuf, cbBuf, &read));
+ if (!read)
break;
- AudioMixBufFinish(&parent, cSamplesRead);
+ AudioMixBufFinish(&parent, read);
}
- RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
- RTTESTI_CHECK(AudioMixBufLive(&child1) == 0);
- RTTESTI_CHECK(AudioMixBufLive(&child2) == 0);
+ RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+ RTTESTI_CHECK(AudioMixBufMixed(&child1) == 0);
+ RTTESTI_CHECK(AudioMixBufMixed(&child2) == 0);
AudioMixBufDestroy(&parent);
AudioMixBufDestroy(&child1);
@@ -259,24 +243,22 @@ static int tstParentChild(RTTEST hTest)
/* Test 8-bit sample conversion (8-bit -> internal -> 8-bit). */
static int tstConversion8(RTTEST hTest)
{
- unsigned i;
- uint32_t cBufSize = 256;
- PDMAUDIOPCMPROPS props;
+ unsigned i;
+ uint32_t cBufSize = 256;
+ PDMPCMPROPS props;
- RTTestSubF(hTest, "Sample conversion (U8)");
+
+ RTTestSubF(hTest, "Sample conversion");
PDMAUDIOSTREAMCFG cfg_p =
{
- "44100Hz, 1 Channel, U8",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 44100, /* Hz */
- 1 /* Channels */,
- PDMAUDIOFMT_U8 /* Format */,
+ 44100, /* Hz */
+ 1 /* Channels */,
+ AUD_FMT_U8 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
- int rc = DrvAudioHlpStreamCfgToProps(&cfg_p, &props);
+ int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
AssertRC(rc);
PDMAUDIOMIXBUF parent;
@@ -291,16 +273,13 @@ static int tstConversion8(RTTEST hTest)
*/
PDMAUDIOSTREAMCFG cfg_c = /* Upmixing to parent */
{
- "22050Hz, 1 Channel, U8",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 22050, /* Hz */
- 1 /* Channels */,
- PDMAUDIOFMT_U8 /* Format */,
+ 22050, /* Hz */
+ 1 /* Channels */,
+ AUD_FMT_U8 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
- rc = DrvAudioHlpStreamCfgToProps(&cfg_c, &props);
+ rc = DrvAudioStreamCfgToProps(&cfg_c, &props);
AssertRC(rc);
PDMAUDIOMIXBUF child;
@@ -308,40 +287,41 @@ static int tstConversion8(RTTEST hTest)
RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
/* 8-bit unsigned samples. Often used with SB16 device. */
- uint8_t samples[16] = { 0xAA, 0xBB, 0, 1, 43, 125, 126, 127,
- 128, 129, 130, 131, 132, UINT8_MAX - 1, UINT8_MAX, 0 };
+ uint8_t samples[16] = { 0xAA, 0xBB, 0, 1, 43, 125, 126, 127,
+ 128, 129, 130, 131, 132, UINT8_MAX - 1, UINT8_MAX, 0 };
/*
* Writing + mixing from child -> parent, sequential.
*/
uint32_t cbBuf = 256;
char achBuf[256];
- uint32_t cSamplesRead, cSamplesWritten, cSamplesMixed;
+ uint32_t read, written, mixed, temp;
+ //unused//uint32_t cChildFree = cBufSize;
+ //unused//uint32_t cChildMixed = 0;
uint32_t cSamplesChild = 16;
uint32_t cSamplesParent = cSamplesChild * 2 - 2;
- uint32_t cSamplesTotalRead = 0;
+ uint32_t cSamplesRead = 0;
/**** 8-bit unsigned samples ****/
RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Conversion test %uHz %uch 8-bit\n", cfg_c.uHz, cfg_c.cChannels);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&child, &samples, sizeof(samples), &cSamplesWritten));
- RTTESTI_CHECK_MSG(cSamplesWritten == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, cSamplesWritten));
- RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, cSamplesWritten, &cSamplesMixed));
- uint32_t cSamples = AudioMixBufUsed(&parent);
- RTTESTI_CHECK_MSG(AudioMixBufLive(&child) == cSamples, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufLive(&child), cSamples));
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
+ RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
+ RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
+ temp = AudioMixBufProcessed(&parent);
+ RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
- RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufLive(&child));
+ RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child));
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &cSamplesRead));
- if (!cSamplesRead)
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
+ if (!read)
break;
- cSamplesTotalRead += cSamplesRead;
- AudioMixBufFinish(&parent, cSamplesRead);
+ cSamplesRead += read;
+ AudioMixBufFinish(&parent, read);
}
-
- RTTESTI_CHECK_MSG(cSamplesTotalRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesTotalRead));
+ RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
/* Check that the samples came out unharmed. Every other sample is interpolated and we ignore it. */
/* NB: This also checks that the default volume setting is 0dB attenuation. */
@@ -355,8 +335,8 @@ static int tstConversion8(RTTEST hTest)
pDst8 += 2;
}
- RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
- RTTESTI_CHECK(AudioMixBufLive(&child) == 0);
+ RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+ RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
AudioMixBufDestroy(&parent);
AudioMixBufDestroy(&child);
@@ -367,24 +347,22 @@ static int tstConversion8(RTTEST hTest)
/* Test 16-bit sample conversion (16-bit -> internal -> 16-bit). */
static int tstConversion16(RTTEST hTest)
{
- unsigned i;
- uint32_t cBufSize = 256;
- PDMAUDIOPCMPROPS props;
+ unsigned i;
+ uint32_t cBufSize = 256;
+ PDMPCMPROPS props;
- RTTestSubF(hTest, "Sample conversion (S16)");
+
+ RTTestSubF(hTest, "Sample conversion 16-bit");
PDMAUDIOSTREAMCFG cfg_p =
{
- "44100Hz, 1 Channel, S16",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 44100, /* Hz */
- 1 /* Channels */,
- PDMAUDIOFMT_S16 /* Format */,
+ 44100, /* Hz */
+ 1 /* Channels */,
+ AUD_FMT_S16 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
- int rc = DrvAudioHlpStreamCfgToProps(&cfg_p, &props);
+ int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
AssertRC(rc);
PDMAUDIOMIXBUF parent;
@@ -392,16 +370,13 @@ static int tstConversion16(RTTEST hTest)
PDMAUDIOSTREAMCFG cfg_c = /* Upmixing to parent */
{
- "22050Hz, 1 Channel, S16",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 22050, /* Hz */
- 1 /* Channels */,
- PDMAUDIOFMT_S16 /* Format */,
+ 22050, /* Hz */
+ 1 /* Channels */,
+ AUD_FMT_S16 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
- rc = DrvAudioHlpStreamCfgToProps(&cfg_c, &props);
+ rc = DrvAudioStreamCfgToProps(&cfg_c, &props);
AssertRC(rc);
PDMAUDIOMIXBUF child;
@@ -417,31 +392,33 @@ static int tstConversion16(RTTEST hTest)
*/
uint32_t cbBuf = 256;
char achBuf[256];
- uint32_t cSamplesRead, cSamplesWritten, cSamplesMixed;
+ uint32_t read, written, mixed, temp;
+ //unused//uint32_t cChildFree = cBufSize;
+ //unused//uint32_t cChildMixed = 0;
uint32_t cSamplesChild = 16;
uint32_t cSamplesParent = cSamplesChild * 2 - 2;
- uint32_t cSamplesTotalRead = 0;
+ uint32_t cSamplesRead = 0;
/**** 16-bit signed samples ****/
RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Conversion test %uHz %uch 16-bit\n", cfg_c.uHz, cfg_c.cChannels);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&child, &samples, sizeof(samples), &cSamplesWritten));
- RTTESTI_CHECK_MSG(cSamplesWritten == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, cSamplesWritten));
- RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, cSamplesWritten, &cSamplesMixed));
- uint32_t cSamples = AudioMixBufUsed(&parent);
- RTTESTI_CHECK_MSG(AudioMixBufLive(&child) == cSamples, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufLive(&child), cSamples));
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
+ RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
+ RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
+ temp = AudioMixBufProcessed(&parent);
+ RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
- RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufLive(&child));
+ RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child));
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &cSamplesRead));
- if (!cSamplesRead)
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
+ if (!read)
break;
- cSamplesTotalRead += cSamplesRead;
- AudioMixBufFinish(&parent, cSamplesRead);
+ cSamplesRead += read;
+ AudioMixBufFinish(&parent, read);
}
- RTTESTI_CHECK_MSG(cSamplesTotalRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesTotalRead));
+ RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
/* Check that the samples came out unharmed. Every other sample is interpolated and we ignore it. */
/* NB: This also checks that the default volume setting is 0dB attenuation. */
@@ -455,8 +432,8 @@ static int tstConversion16(RTTEST hTest)
pDst16 += 2;
}
- RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
- RTTESTI_CHECK(AudioMixBufLive(&child) == 0);
+ RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
+ RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
AudioMixBufDestroy(&parent);
AudioMixBufDestroy(&child);
@@ -467,25 +444,23 @@ static int tstConversion16(RTTEST hTest)
/* Test volume control. */
static int tstVolume(RTTEST hTest)
{
- unsigned i;
- uint32_t cBufSize = 256;
- PDMAUDIOPCMPROPS props;
+ unsigned i;
+ uint32_t cBufSize = 256;
+ PDMPCMPROPS props;
+
RTTestSubF(hTest, "Volume control");
/* Same for parent/child. */
PDMAUDIOSTREAMCFG cfg =
{
- "44100Hz, 2 Channels, S16",
- PDMAUDIODIR_OUT,
- { PDMAUDIOPLAYBACKDEST_UNKNOWN },
- 44100, /* Hz */
- 2 /* Channels */,
- PDMAUDIOFMT_S16 /* Format */,
+ 44100, /* Hz */
+ 2 /* Channels */,
+ AUD_FMT_S16 /* Format */,
PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
};
- int rc = DrvAudioHlpStreamCfgToProps(&cfg, &props);
+ int rc = DrvAudioStreamCfgToProps(&cfg, &props);
AssertRC(rc);
PDMAUDIOVOLUME vol = { false, 0, 0 }; /* Not muted. */
@@ -505,11 +480,13 @@ static int tstVolume(RTTEST hTest)
*/
uint32_t cbBuf = 256;
char achBuf[256];
- uint32_t cSamplesRead, cSamplesWritten, cSamplesMixed;
+ uint32_t read, written, mixed;
+ //unused//uint32_t cChildFree = cBufSize;
+ //unused//uint32_t cChildMixed = 0;
uint32_t cSamplesChild = 8;
uint32_t cSamplesParent = cSamplesChild;
- uint32_t cSamplesTotalRead;
+ uint32_t cSamplesRead;
int16_t *pSrc16;
int16_t *pDst16;
@@ -520,20 +497,20 @@ static int tstVolume(RTTEST hTest)
vol.uLeft = vol.uRight = 255;
AudioMixBufSetVolume(&child, &vol);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&child, &samples, sizeof(samples), &cSamplesWritten));
- RTTESTI_CHECK_MSG(cSamplesWritten == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, cSamplesWritten));
- RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, cSamplesWritten, &cSamplesMixed));
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
+ RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
+ RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
- cSamplesTotalRead = 0;
+ cSamplesRead = 0;
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &cSamplesRead));
- if (!cSamplesRead)
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
+ if (!read)
break;
- cSamplesTotalRead += cSamplesRead;
- AudioMixBufFinish(&parent, cSamplesRead);
+ cSamplesRead += read;
+ AudioMixBufFinish(&parent, read);
}
- RTTESTI_CHECK_MSG(cSamplesTotalRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesTotalRead));
+ RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
/* Check that at 0dB the samples came out unharmed. */
pSrc16 = &samples[0];
@@ -551,20 +528,20 @@ static int tstVolume(RTTEST hTest)
vol.uLeft = vol.uRight = 255 - 16;
AudioMixBufSetVolume(&child, &vol);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&child, &samples, sizeof(samples), &cSamplesWritten));
- RTTESTI_CHECK_MSG(cSamplesWritten == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, cSamplesWritten));
- RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, cSamplesWritten, &cSamplesMixed));
+ RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
+ RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
+ RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
- cSamplesTotalRead = 0;
+ cSamplesRead = 0;
for (;;)
{
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &cSamplesRead));
- if (!cSamplesRead)
+ RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
+ if (!read)
break;
- cSamplesTotalRead += cSamplesRead;
- AudioMixBufFinish(&parent, cSamplesRead);
+ cSamplesRead += read;
+ AudioMixBufFinish(&parent, read);
}
- RTTESTI_CHECK_MSG(cSamplesTotalRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesTotalRead));
+ RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
/* Check that at -6dB the sample values are halved. */
pSrc16 = &samples[0];
diff --git a/src/VBox/Devices/Audio_50/AudioMixBuffer.cpp b/src/VBox/Devices/Audio_50/AudioMixBuffer.cpp
deleted file mode 100644
index 0528dc2..0000000
--- a/src/VBox/Devices/Audio_50/AudioMixBuffer.cpp
+++ /dev/null
@@ -1,1756 +0,0 @@
-/* $Id: AudioMixBuffer.cpp $ */
-/** @file
- * VBox audio: Audio mixing buffer for converting reading/writing audio
- * samples.
- */
-
-/*
- * Copyright (C) 2014-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-#define LOG_GROUP LOG_GROUP_AUDIO_MIXER_BUFFER
-#include <VBox/log.h>
-
-/*
- * DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
- * to a file on the host. Be sure to adjust DEBUG_DUMP_PCM_DATA_PATH
- * to your needs before using this!
- */
-#if 0
-# define DEBUG_DUMP_PCM_DATA
-# ifdef RT_OS_WINDOWS
-# define DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
-# else
-# define DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
-# endif
-#endif
-
-#include <iprt/asm-math.h>
-#include <iprt/assert.h>
-#ifdef DEBUG_DUMP_PCM_DATA
-# include <iprt/file.h>
-#endif
-#include <iprt/mem.h>
-#include <iprt/string.h> /* For RT_BZERO. */
-
-#ifdef TESTCASE
-# define LOG_ENABLED
-# include <iprt/stream.h>
-#endif
-#include <VBox/err.h>
-
-#include "AudioMixBuffer.h"
-
-#if 0
-# define AUDMIXBUF_LOG(x) LogFlowFunc(x)
-#else
-# if defined(TESTCASE)
-# define AUDMIXBUF_LOG(x) LogFunc(x)
-# else
-# define AUDMIXBUF_LOG(x) do {} while (0)
-# endif
-#endif
-
-
-/*
- * Soft Volume Control
- *
- * The external code supplies an 8-bit volume (attenuation) value in the
- * 0 .. 255 range. This represents 0 to -96dB attenuation where an input
- * value of 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
- *
- * Each step thus correspons to 96 / 256 or 0.375dB. Every 6dB (16 steps)
- * represents doubling the sample value.
- *
- * For internal use, the volume control needs to be converted to a 16-bit
- * (sort of) exponential value between 1 and 65536. This is used with fixed
- * point arithmetic such that 65536 means 1.0 and 1 means 1/65536.
- *
- * For actual volume calculation, 33.31 fixed point is used. Maximum (or
- * unattenuated) volume is represented as 0x40000000; conveniently, this
- * value fits into a uint32_t.
- *
- * To enable fast processing, the maximum volume must be a power of two
- * and must not have a sign when converted to int32_t. While 0x80000000
- * violates these constraints, 0x40000000 does not.
- */
-
-
-/** Logarithmic/exponential volume conversion table. */
-static uint32_t s_aVolumeConv[256] = {
- 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
- 1, 2, 2, 2, 2, 2, 2, 2, /* 15 */
- 2, 2, 2, 2, 2, 3, 3, 3, /* 23 */
- 3, 3, 3, 3, 4, 4, 4, 4, /* 31 */
- 4, 4, 5, 5, 5, 5, 5, 6, /* 39 */
- 6, 6, 6, 7, 7, 7, 8, 8, /* 47 */
- 8, 9, 9, 10, 10, 10, 11, 11, /* 55 */
- 12, 12, 13, 13, 14, 15, 15, 16, /* 63 */
- 17, 17, 18, 19, 20, 21, 22, 23, /* 71 */
- 24, 25, 26, 27, 28, 29, 31, 32, /* 79 */
- 33, 35, 36, 38, 40, 41, 43, 45, /* 87 */
- 47, 49, 52, 54, 56, 59, 61, 64, /* 95 */
- 67, 70, 73, 76, 79, 83, 87, 91, /* 103 */
- 95, 99, 103, 108, 112, 117, 123, 128, /* 111 */
- 134, 140, 146, 152, 159, 166, 173, 181, /* 119 */
- 189, 197, 206, 215, 225, 235, 245, 256, /* 127 */
- 267, 279, 292, 304, 318, 332, 347, 362, /* 135 */
- 378, 395, 412, 431, 450, 470, 490, 512, /* 143 */
- 535, 558, 583, 609, 636, 664, 693, 724, /* 151 */
- 756, 790, 825, 861, 899, 939, 981, 1024, /* 159 */
- 1069, 1117, 1166, 1218, 1272, 1328, 1387, 1448, /* 167 */
- 1512, 1579, 1649, 1722, 1798, 1878, 1961, 2048, /* 175 */
- 2139, 2233, 2332, 2435, 2543, 2656, 2774, 2896, /* 183 */
- 3025, 3158, 3298, 3444, 3597, 3756, 3922, 4096, /* 191 */
- 4277, 4467, 4664, 4871, 5087, 5312, 5547, 5793, /* 199 */
- 6049, 6317, 6597, 6889, 7194, 7512, 7845, 8192, /* 207 */
- 8555, 8933, 9329, 9742, 10173, 10624, 11094, 11585, /* 215 */
- 12098, 12634, 13193, 13777, 14387, 15024, 15689, 16384, /* 223 */
- 17109, 17867, 18658, 19484, 20347, 21247, 22188, 23170, /* 231 */
- 24196, 25268, 26386, 27554, 28774, 30048, 31379, 32768, /* 239 */
- 34219, 35734, 37316, 38968, 40693, 42495, 44376, 46341, /* 247 */
- 48393, 50535, 52773, 55109, 57549, 60097, 62757, 65536, /* 255 */
-};
-
-/* Bit shift for fixed point conversion. */
-#define AUDIOMIXBUF_VOL_SHIFT 30
-
-/* Internal representation of 0dB volume (1.0 in fixed point). */
-#define AUDIOMIXBUF_VOL_0DB (1 << AUDIOMIXBUF_VOL_SHIFT)
-
-AssertCompile(AUDIOMIXBUF_VOL_0DB <= 0x40000000); /* Must always hold. */
-AssertCompile(AUDIOMIXBUF_VOL_0DB == 0x40000000); /* For now -- when only attenuation is used. */
-
-/**
- * Structure for holding sample conversion parameters for
- * the audioMixBufConvFromXXX / audioMixBufConvToXXX macros.
- */
-typedef struct AUDMIXBUF_CONVOPTS
-{
- /** Number of audio samples to convert. */
- uint32_t cSamples;
- /** Volume to apply during conversion. Pass 0
- * to convert the original values. May not apply to
- * all conversion functions. */
- PDMAUDIOVOLUME Volume;
-} AUDMIXBUF_CONVOPTS, *PAUDMIXBUF_CONVOPTS;
-
-/*
- * When running the audio testcases we want to verfiy
- * the macro-generated routines separately, so unmark them as being
- * inlined + static.
- */
-#ifdef TESTCASE
-# define AUDMIXBUF_MACRO_FN
-#else
-# define AUDMIXBUF_MACRO_FN static inline
-#endif
-
-#ifdef DEBUG
-static uint64_t s_cSamplesMixedTotal = 0;
-static inline void audioMixBufPrint(PPDMAUDIOMIXBUF pMixBuf);
-#endif
-
-typedef uint32_t (AUDMIXBUF_FN_CONVFROM) (PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, const PAUDMIXBUF_CONVOPTS pOpts);
-typedef AUDMIXBUF_FN_CONVFROM *PAUDMIXBUF_FN_CONVFROM;
-
-typedef void (AUDMIXBUF_FN_CONVTO) (void *pvDst, const PPDMAUDIOSAMPLE paSrc, const PAUDMIXBUF_CONVOPTS pOpts);
-typedef AUDMIXBUF_FN_CONVTO *PAUDMIXBUF_FN_CONVTO;
-
-/* Can return VINF_TRY_AGAIN for getting next pointer at beginning (circular) */
-
-/**
- * Acquires (reads) a mutable pointer to the mixing buffer's audio samples without
- * any conversion done.
- ** @todo Rename to AudioMixBufPeek(Mutable/Raw)?
- ** @todo Protect the buffer's data?
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to acquire audio samples from.
- * @param cSamplesToRead Number of audio samples to read.
- * @param ppvSamples Returns a mutable pointer to the buffer's audio sample data.
- * @param pcSamplesRead Number of audio samples read (acquired).
- *
- * @remark This function is not thread safe!
- */
-int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead,
- PPDMAUDIOSAMPLE *ppvSamples, uint32_t *pcSamplesRead)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(ppvSamples, VERR_INVALID_POINTER);
- AssertPtrReturn(pcSamplesRead, VERR_INVALID_POINTER);
-
- int rc;
-
- if (!cSamplesToRead)
- {
- *pcSamplesRead = 0;
- return VINF_SUCCESS;
- }
-
- uint32_t cSamplesRead;
- if (pMixBuf->offReadWrite + cSamplesToRead > pMixBuf->cSamples)
- {
- cSamplesRead = pMixBuf->cSamples - pMixBuf->offReadWrite;
- rc = VINF_TRY_AGAIN;
- }
- else
- {
- cSamplesRead = cSamplesToRead;
- rc = VINF_SUCCESS;
- }
-
- *ppvSamples = &pMixBuf->pSamples[pMixBuf->offReadWrite];
- AssertPtr(ppvSamples);
-
- pMixBuf->offReadWrite = (pMixBuf->offReadWrite + cSamplesRead) % pMixBuf->cSamples;
- Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
- pMixBuf->cProcessed -= RT_MIN(cSamplesRead, pMixBuf->cProcessed);
-
- *pcSamplesRead = cSamplesRead;
-
- return rc;
-}
-
-/**
- * Returns available number of samples for reading.
- *
- * @return uint32_t Number of samples available for reading.
- * @param pMixBuf Mixing buffer to return value for.
- */
-uint32_t AudioMixBufAvail(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturn(pMixBuf, true);
-
- uint32_t cAvail;
- if (pMixBuf->pParent) /* Child */
- cAvail = pMixBuf->cMixed;
- else
- cAvail = pMixBuf->cProcessed;
-
- Assert(cAvail <= pMixBuf->cSamples);
- return cAvail;
-}
-
-/**
- * Clears the entire sample buffer.
- *
- * @param pMixBuf Mixing buffer to clear.
- *
- */
-void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturnVoid(pMixBuf);
-
- if (pMixBuf->cSamples)
- RT_BZERO(pMixBuf->pSamples, pMixBuf->cSamples * sizeof(PDMAUDIOSAMPLE));
-}
-
-/**
- * Clears (zeroes) the buffer by a certain amount of (processed) samples and
- * keeps track to eventually assigned children buffers.
- *
- * @param pMixBuf Mixing buffer to clear.
- * @param cSamplesToClear Number of audio samples to clear.
- */
-void AudioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear)
-{
- AUDMIXBUF_LOG(("cSamples=%RU32\n", cSamplesToClear));
- AUDMIXBUF_LOG(("%s: offReadWrite=%RU32, cProcessed=%RU32\n",
- pMixBuf->pszName, pMixBuf->offReadWrite, pMixBuf->cProcessed));
-
- PPDMAUDIOMIXBUF pIter;
- RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
- {
- AUDMIXBUF_LOG(("\t%s: cMixed=%RU32 -> %RU32\n",
- pIter->pszName, pIter->cMixed, pIter->cMixed - cSamplesToClear));
-
- pIter->cMixed -= RT_MIN(pIter->cMixed, cSamplesToClear);
- pIter->offReadWrite = 0;
- }
-
- uint32_t cLeft = RT_MIN(cSamplesToClear, pMixBuf->cSamples);
- uint32_t offClear;
-
- if (cLeft > pMixBuf->offReadWrite) /* Zero end of buffer first (wrap-around). */
- {
- AUDMIXBUF_LOG(("Clearing1: %RU32 - %RU32\n",
- (pMixBuf->cSamples - (cLeft - pMixBuf->offReadWrite)),
- pMixBuf->cSamples));
-
- RT_BZERO(pMixBuf->pSamples + (pMixBuf->cSamples - (cLeft - pMixBuf->offReadWrite)),
- (cLeft - pMixBuf->offReadWrite) * sizeof(PDMAUDIOSAMPLE));
-
- cLeft -= cLeft - pMixBuf->offReadWrite;
- offClear = 0;
- }
- else
- offClear = pMixBuf->offReadWrite - cLeft;
-
- if (cLeft)
- {
- AUDMIXBUF_LOG(("Clearing2: %RU32 - %RU32\n",
- offClear, offClear + cLeft));
- RT_BZERO(pMixBuf->pSamples + offClear, cLeft * sizeof(PDMAUDIOSAMPLE));
- }
-}
-
-/**
- * Destroys (uninitializes) a mixing buffer.
- *
- * @param pMixBuf Mixing buffer to destroy.
- */
-void AudioMixBufDestroy(PPDMAUDIOMIXBUF pMixBuf)
-{
- if (!pMixBuf)
- return;
-
- AudioMixBufUnlink(pMixBuf);
-
- if (pMixBuf->pszName)
- {
- AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
-
- RTStrFree(pMixBuf->pszName);
- pMixBuf->pszName = NULL;
- }
-
- if (pMixBuf->pRate)
- {
- RTMemFree(pMixBuf->pRate);
- pMixBuf->pRate = NULL;
- }
-
- if (pMixBuf->pSamples)
- {
- Assert(pMixBuf->cSamples);
-
- RTMemFree(pMixBuf->pSamples);
- pMixBuf->pSamples = NULL;
- }
-
- pMixBuf->cSamples = 0;
-}
-
-/**
- * Returns the size (in audio samples) of free audio buffer space.
- *
- * @return uint32_t Size (in audio samples) of free audio buffer space.
- * @param pMixBuf Mixing buffer to return free size for.
- */
-uint32_t AudioMixBufFree(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturn(pMixBuf, 0);
-
- uint32_t cSamplesFree;
- if (pMixBuf->pParent)
- {
- /*
- * As a linked child buffer we want to know how many samples
- * already have been consumed by the parent.
- */
- Assert(pMixBuf->cMixed <= pMixBuf->pParent->cSamples);
- cSamplesFree = pMixBuf->pParent->cSamples - pMixBuf->cMixed;
- }
- else /* As a parent. */
- {
- Assert(pMixBuf->cSamples >= pMixBuf->cProcessed);
- cSamplesFree = pMixBuf->cSamples - pMixBuf->cProcessed;
- }
-
- AUDMIXBUF_LOG(("%s: cSamplesFree=%RU32\n", pMixBuf->pszName, cSamplesFree));
- return cSamplesFree;
-}
-
-/**
- * Returns the size (in bytes) of free audio buffer space.
- *
- * @return uint32_t Size (in bytes) of free audio buffer space.
- * @param pMixBuf Mixing buffer to return free size for.
- */
-uint32_t AudioMixBufFreeBytes(PPDMAUDIOMIXBUF pMixBuf)
-{
- return AUDIOMIXBUF_S2B(pMixBuf, AudioMixBufFree(pMixBuf));
-}
-
-/**
- * Allocates the internal audio sample buffer.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to allocate sample buffer for.
- * @param cSamples Number of audio samples to allocate.
- */
-static int audioMixBufAlloc(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertReturn(cSamples, VERR_INVALID_PARAMETER);
-
- AUDMIXBUF_LOG(("%s: cSamples=%RU32\n", pMixBuf->pszName, cSamples));
-
- size_t cbSamples = cSamples * sizeof(PDMAUDIOSAMPLE);
- if (!cbSamples)
- return VERR_INVALID_PARAMETER;
-
- pMixBuf->pSamples = (PPDMAUDIOSAMPLE)RTMemAllocZ(cbSamples);
- if (!pMixBuf->pSamples)
- return VERR_NO_MEMORY;
-
- pMixBuf->cSamples = cSamples;
-
- return VINF_SUCCESS;
-}
-
-/** Note: Enabling this will generate huge logs! */
-//#define DEBUG_MACROS
-
-#ifdef DEBUG_MACROS
-# define AUDMIXBUF_MACRO_LOG(x) AUDMIXBUF_LOG(x)
-#elif defined(TESTCASE)
-# define AUDMIXBUF_MACRO_LOG(x) RTPrintf x
-#else
-# define AUDMIXBUF_MACRO_LOG(x) do {} while (0)
-#endif
-
-/**
- * Macro for generating the conversion routines from/to different formats.
- * Be careful what to pass in/out, as most of the macros are optimized for speed and
- * thus don't do any bounds checking!
- *
- * Note: Currently does not handle any endianness conversion yet!
- */
-#define AUDMIXBUF_CONVERT(_aName, _aType, _aMin, _aMax, _aSigned, _aShift) \
- /* Clips a specific output value to a single sample value. */ \
- AUDMIXBUF_MACRO_FN int64_t audioMixBufClipFrom##_aName(_aType aVal) \
- { \
- if (_aSigned) \
- return ((int64_t) aVal) << (32 - _aShift); \
- return ((int64_t) aVal - ((_aMax >> 1) + 1)) << (32 - _aShift); \
- } \
- \
- /* Clips a single sample value to a specific output value. */ \
- AUDMIXBUF_MACRO_FN _aType audioMixBufClipTo##_aName(int64_t iVal) \
- { \
- if (iVal >= 0x7fffffff) \
- return _aMax; \
- else if (iVal < -INT64_C(0x80000000)) \
- return _aMin; \
- \
- if (_aSigned) \
- return (_aType) (iVal >> (32 - _aShift)); \
- return ((_aType) ((iVal >> (32 - _aShift)) + ((_aMax >> 1) + 1))); \
- } \
- \
- AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFrom##_aName##Stereo(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, \
- const PAUDMIXBUF_CONVOPTS pOpts) \
- { \
- _aType *pSrc = (_aType *)pvSrc; \
- uint32_t cSamples = (uint32_t)RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
- AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, sizeof(%zu), lVol=%RU32, rVol=%RU32\n", \
- pOpts->cSamples, sizeof(_aType), pOpts->Volume.uLeft, pOpts->Volume.uRight)); \
- for (uint32_t i = 0; i < cSamples; i++) \
- { \
- AUDMIXBUF_MACRO_LOG(("%p: l=%RI16, r=%RI16\n", paDst, *pSrc, *(pSrc + 1))); \
- paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
- paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
- AUDMIXBUF_MACRO_LOG(("\t-> l=%RI64, r=%RI64\n", paDst->i64LSample, paDst->i64RSample)); \
- paDst++; \
- } \
- \
- return cSamples; \
- } \
- \
- AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFrom##_aName##Mono(PPDMAUDIOSAMPLE paDst, const void *pvSrc, uint32_t cbSrc, \
- const PAUDMIXBUF_CONVOPTS pOpts) \
- { \
- _aType *pSrc = (_aType *)pvSrc; \
- uint32_t cSamples = (uint32_t)RT_MIN(pOpts->cSamples, cbSrc / sizeof(_aType)); \
- AUDMIXBUF_MACRO_LOG(("cSamples=%RU32, sizeof(%zu), lVol=%RU32, rVol=%RU32\n", \
- cSamples, sizeof(_aType), pOpts->Volume.uLeft, pOpts->Volume.uRight)); \
- for (uint32_t i = 0; i < cSamples; i++) \
- { \
- AUDMIXBUF_MACRO_LOG(("%p: s=%RI16\n", paDst, *pSrc)); \
- paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uLeft) >> AUDIOMIXBUF_VOL_SHIFT; \
- paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
- ++pSrc; \
- AUDMIXBUF_MACRO_LOG(("\t-> l=%RI64, r=%RI64\n", paDst->i64LSample, paDst->i64RSample)); \
- paDst++; \
- } \
- \
- return cSamples; \
- } \
- \
- AUDMIXBUF_MACRO_FN void audioMixBufConvTo##_aName##Stereo(void *pvDst, const PPDMAUDIOSAMPLE paSrc, \
- const PAUDMIXBUF_CONVOPTS pOpts) \
- { \
- PPDMAUDIOSAMPLE pSrc = paSrc; \
- _aType *pDst = (_aType *)pvDst; \
- _aType l, r; \
- uint32_t cSamples = pOpts->cSamples; \
- while (cSamples--) \
- { \
- AUDMIXBUF_MACRO_LOG(("%p: l=%RI64, r=%RI64\n", pSrc, pSrc->i64LSample, pSrc->i64RSample)); \
- l = audioMixBufClipTo##_aName(pSrc->i64LSample); \
- r = audioMixBufClipTo##_aName(pSrc->i64RSample); \
- AUDMIXBUF_MACRO_LOG(("\t-> l=%RI16, r=%RI16\n", l, r)); \
- *pDst++ = l; \
- *pDst++ = r; \
- pSrc++; \
- } \
- } \
- \
- AUDMIXBUF_MACRO_FN void audioMixBufConvTo##_aName##Mono(void *pvDst, const PPDMAUDIOSAMPLE paSrc, \
- const PAUDMIXBUF_CONVOPTS pOpts) \
- { \
- PPDMAUDIOSAMPLE pSrc = paSrc; \
- _aType *pDst = (_aType *)pvDst; \
- uint32_t cSamples = pOpts->cSamples; \
- while (cSamples--) \
- { \
- *pDst++ = audioMixBufClipTo##_aName((pSrc->i64LSample + pSrc->i64RSample) / 2); \
- pSrc++; \
- } \
- }
-
-/* audioMixBufConvXXXS8: 8 bit, signed. */
-AUDMIXBUF_CONVERT(S8 /* Name */, int8_t, INT8_MIN /* Min */, INT8_MAX /* Max */, true /* fSigned */, 8 /* cShift */)
-/* audioMixBufConvXXXU8: 8 bit, unsigned. */
-AUDMIXBUF_CONVERT(U8 /* Name */, uint8_t, 0 /* Min */, UINT8_MAX /* Max */, false /* fSigned */, 8 /* cShift */)
-/* audioMixBufConvXXXS16: 16 bit, signed. */
-AUDMIXBUF_CONVERT(S16 /* Name */, int16_t, INT16_MIN /* Min */, INT16_MAX /* Max */, true /* fSigned */, 16 /* cShift */)
-/* audioMixBufConvXXXU16: 16 bit, unsigned. */
-AUDMIXBUF_CONVERT(U16 /* Name */, uint16_t, 0 /* Min */, UINT16_MAX /* Max */, false /* fSigned */, 16 /* cShift */)
-/* audioMixBufConvXXXS32: 32 bit, signed. */
-AUDMIXBUF_CONVERT(S32 /* Name */, int32_t, INT32_MIN /* Min */, INT32_MAX /* Max */, true /* fSigned */, 32 /* cShift */)
-/* audioMixBufConvXXXU32: 32 bit, unsigned. */
-AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* Max */, false /* fSigned */, 32 /* cShift */)
-
-#undef AUDMIXBUF_CONVERT
-
-#define AUDMIXBUF_MIXOP(_aName, _aOp) \
- AUDMIXBUF_MACRO_FN void audioMixBufOp##_aName(PPDMAUDIOSAMPLE paDst, uint32_t cDstSamples, \
- PPDMAUDIOSAMPLE paSrc, uint32_t cSrcSamples, \
- PPDMAUDIOSTRMRATE pRate, \
- uint32_t *pcDstWritten, uint32_t *pcSrcRead) \
- { \
- AUDMIXBUF_MACRO_LOG(("cSrcSamples=%RU32, cDstSamples=%RU32\n", cSrcSamples, cDstSamples)); \
- AUDMIXBUF_MACRO_LOG(("pRate=%p: srcOffset=0x%RX32 (%RU32), dstOffset=0x%RX32 (%RU32), dstInc=0x%RX64 (%RU64)\n", \
- pRate, pRate->srcOffset, pRate->srcOffset, \
- (uint32_t)(pRate->dstOffset >> 32), (uint32_t)(pRate->dstOffset >> 32), \
- pRate->dstInc, pRate->dstInc)); \
- \
- if (pRate->dstInc == (UINT64_C(1) + UINT32_MAX)) /* No conversion needed? */ \
- { \
- uint32_t cSamples = RT_MIN(cSrcSamples, cDstSamples); \
- AUDMIXBUF_MACRO_LOG(("cSamples=%RU32\n", cSamples)); \
- for (uint32_t i = 0; i < cSamples; i++) \
- { \
- paDst[i].i64LSample _aOp paSrc[i].i64LSample; \
- paDst[i].i64RSample _aOp paSrc[i].i64RSample; \
- } \
- \
- if (pcDstWritten) \
- *pcDstWritten = cSamples; \
- if (pcSrcRead) \
- *pcSrcRead = cSamples; \
- return; \
- } \
- \
- PPDMAUDIOSAMPLE paSrcStart = paSrc; \
- PPDMAUDIOSAMPLE paSrcEnd = paSrc + cSrcSamples; \
- PPDMAUDIOSAMPLE paDstStart = paDst; \
- PPDMAUDIOSAMPLE paDstEnd = paDst + cDstSamples; \
- PDMAUDIOSAMPLE samCur = { 0 }; \
- PDMAUDIOSAMPLE samOut; \
- PDMAUDIOSAMPLE samLast = pRate->srcSampleLast; \
- uint64_t lDelta = 0; \
- \
- AUDMIXBUF_MACRO_LOG(("Start: paDstEnd=%p - paDstStart=%p -> %zu\n", paDstEnd, paDst, paDstEnd - paDstStart)); \
- AUDMIXBUF_MACRO_LOG(("Start: paSrcEnd=%p - paSrcStart=%p -> %zu\n", paSrcEnd, paSrc, paSrcEnd - paSrcStart)); \
- \
- while (paDst < paDstEnd) \
- { \
- Assert(paSrc <= paSrcEnd); \
- Assert(paDst <= paDstEnd); \
- if (paSrc == paSrcEnd) \
- break; \
- \
- lDelta = 0; \
- while (pRate->srcOffset <= (pRate->dstOffset >> 32)) \
- { \
- Assert(paSrc <= paSrcEnd); \
- samLast = *paSrc++; \
- pRate->srcOffset++; \
- lDelta++; \
- if (paSrc == paSrcEnd) \
- break; \
- } \
- \
- Assert(paSrc <= paSrcEnd); \
- if (paSrc == paSrcEnd) \
- break; \
- \
- samCur = *paSrc; \
- \
- /* Interpolate. */ \
- int64_t iDstOffInt = pRate->dstOffset & UINT32_MAX; \
- \
- samOut.i64LSample = (samLast.i64LSample * ((int64_t) (INT64_C(1) << 32) - iDstOffInt) + samCur.i64LSample * iDstOffInt) >> 32; \
- samOut.i64RSample = (samLast.i64RSample * ((int64_t) (INT64_C(1) << 32) - iDstOffInt) + samCur.i64RSample * iDstOffInt) >> 32; \
- \
- paDst->i64LSample _aOp samOut.i64LSample; \
- paDst->i64RSample _aOp samOut.i64RSample; \
- \
- AUDMIXBUF_MACRO_LOG(("\tlDelta=0x%RX64 (%RU64), iDstOffInt=0x%RX64 (%RI64), l=%RI64, r=%RI64 (cur l=%RI64, r=%RI64)\n", \
- lDelta, lDelta, iDstOffInt, iDstOffInt, \
- paDst->i64LSample, paDst->i64RSample, \
- samCur.i64LSample, samCur.i64RSample)); \
- \
- paDst++; \
- pRate->dstOffset += pRate->dstInc; \
- \
- AUDMIXBUF_MACRO_LOG(("\t\tpRate->dstOffset=0x%RX32 (%RU32)\n", pRate->dstOffset, pRate->dstOffset >> 32)); \
- \
- } \
- \
- AUDMIXBUF_MACRO_LOG(("End: paDst=%p - paDstStart=%p -> %zu\n", paDst, paDstStart, paDst - paDstStart)); \
- AUDMIXBUF_MACRO_LOG(("End: paSrc=%p - paSrcStart=%p -> %zu\n", paSrc, paSrcStart, paSrc - paSrcStart)); \
- \
- pRate->srcSampleLast = samLast; \
- \
- AUDMIXBUF_MACRO_LOG(("pRate->srcSampleLast l=%RI64, r=%RI64, lDelta=0x%RX64 (%RU64)\n", \
- pRate->srcSampleLast.i64LSample, pRate->srcSampleLast.i64RSample, lDelta, lDelta)); \
- \
- if (pcDstWritten) \
- *pcDstWritten = paDst - paDstStart; \
- if (pcSrcRead) \
- *pcSrcRead = paSrc - paSrcStart; \
- }
-
-#if 0 // unused
-/* audioMixBufOpAssign: Assigns values from source buffer to destination bufffer, overwriting the destination. */
-AUDMIXBUF_MIXOP(Assign /* Name */, = /* Operation */)
-#endif
-/* audioMixBufOpBlend: Blends together the values from both, the source and the destination buffer. */
-AUDMIXBUF_MIXOP(Blend /* Name */, += /* Operation */)
-
-#undef AUDMIXBUF_MIXOP
-#undef AUDMIXBUF_MACRO_LOG
-
-/** Dummy conversion used when the source is muted. */
-AUDMIXBUF_MACRO_FN uint32_t audioMixBufConvFromSilence(PPDMAUDIOSAMPLE paDst, const void *pvSrc,
- uint32_t cbSrc, const PAUDMIXBUF_CONVOPTS pOpts)
-{
- RT_NOREF(cbSrc, pvSrc);
- /* Internally zero always corresponds to silence. */
- memset(paDst, 0, pOpts->cSamples * sizeof(paDst[0]));
- return pOpts->cSamples;
-}
-
-/**
- * Looks up the matching conversion (macro) routine for converting
- * audio samples from a source format.
- *
- ** @todo Speed up the lookup by binding it to the actual stream state.
- *
- * @return PAUDMIXBUF_FN_CONVFROM Function pointer to conversion macro if found, NULL if not supported.
- * @param enmFmt Audio format to lookup conversion macro for.
- * @param fMuted Flag determining whether the source is muted.
- */
-static inline PAUDMIXBUF_FN_CONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enmFmt, bool fMuted)
-{
- if (fMuted)
- return audioMixBufConvFromSilence;
-
- if (AUDMIXBUF_FMT_SIGNED(enmFmt))
- {
- if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
- {
- switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
- {
- case 8: return audioMixBufConvFromS8Stereo;
- case 16: return audioMixBufConvFromS16Stereo;
- case 32: return audioMixBufConvFromS32Stereo;
- default: return NULL;
- }
- }
- else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
- {
- switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
- {
- case 8: return audioMixBufConvFromS8Mono;
- case 16: return audioMixBufConvFromS16Mono;
- case 32: return audioMixBufConvFromS32Mono;
- default: return NULL;
- }
- }
- }
- else /* Unsigned */
- {
- if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
- {
- switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
- {
- case 8: return audioMixBufConvFromU8Stereo;
- case 16: return audioMixBufConvFromU16Stereo;
- case 32: return audioMixBufConvFromU32Stereo;
- default: return NULL;
- }
- }
- else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
- {
- switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
- {
- case 8: return audioMixBufConvFromU8Mono;
- case 16: return audioMixBufConvFromU16Mono;
- case 32: return audioMixBufConvFromU32Mono;
- default: return NULL;
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * Looks up the matching conversion (macro) routine for converting
- * audio samples to a destination format.
- *
- ** @todo Speed up the lookup by binding it to the actual stream state.
- *
- * @return PAUDMIXBUF_FN_CONVTO Function pointer to conversion macro if found, NULL if not supported.
- * @param enmFmt Audio format to lookup conversion macro for.
- */
-static inline PAUDMIXBUF_FN_CONVTO audioMixBufConvToLookup(PDMAUDIOMIXBUFFMT enmFmt)
-{
- if (AUDMIXBUF_FMT_SIGNED(enmFmt))
- {
- if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
- {
- switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
- {
- case 8: return audioMixBufConvToS8Stereo;
- case 16: return audioMixBufConvToS16Stereo;
- case 32: return audioMixBufConvToS32Stereo;
- default: return NULL;
- }
- }
- else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
- {
- switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
- {
- case 8: return audioMixBufConvToS8Mono;
- case 16: return audioMixBufConvToS16Mono;
- case 32: return audioMixBufConvToS32Mono;
- default: return NULL;
- }
- }
- }
- else /* Unsigned */
- {
- if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
- {
- switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
- {
- case 8: return audioMixBufConvToU8Stereo;
- case 16: return audioMixBufConvToU16Stereo;
- case 32: return audioMixBufConvToU32Stereo;
- default: return NULL;
- }
- }
- else if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 1)
- {
- switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
- {
- case 8: return audioMixBufConvToU8Mono;
- case 16: return audioMixBufConvToU16Mono;
- case 32: return audioMixBufConvToU32Mono;
- default: return NULL;
- }
- }
- }
-
- return NULL;
-}
-
-/**
- * Initializes a mixing buffer.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to initialize.
- * @param pszName Name of mixing buffer for easier identification. Optional.
- * @param pProps PCM audio properties to use for the mixing buffer.
- * @param cSamples Maximum number of audio samples the mixing buffer can hold.
- */
-int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMPCMPROPS pProps, uint32_t cSamples)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pProps, VERR_INVALID_POINTER);
-
- pMixBuf->pParent = NULL;
- RTListInit(&pMixBuf->lstBuffers);
-
- pMixBuf->pSamples = NULL;
- pMixBuf->cSamples = 0;
-
- pMixBuf->offReadWrite = 0;
- pMixBuf->cMixed = 0;
- pMixBuf->cProcessed = 0;
-
- /* Set initial volume to max. */
- pMixBuf->Volume.fMuted = false;
- pMixBuf->Volume.uLeft = AUDIOMIXBUF_VOL_0DB;
- pMixBuf->Volume.uRight = AUDIOMIXBUF_VOL_0DB;
-
- /* Prevent division by zero.
- * Do a 1:1 conversion according to AUDIOMIXBUF_S2B_RATIO. */
- pMixBuf->iFreqRatio = 1 << 20;
-
- pMixBuf->pRate = NULL;
-
- pMixBuf->AudioFmt = AUDMIXBUF_AUDIO_FMT_MAKE(pProps->uHz,
- pProps->cChannels,
- pProps->cBits,
- pProps->fSigned);
- pMixBuf->cShift = pProps->cShift;
- pMixBuf->pszName = RTStrDup(pszName);
- if (!pMixBuf->pszName)
- return VERR_NO_MEMORY;
-
- AUDMIXBUF_LOG(("%s: uHz=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool\n",
- pMixBuf->pszName,
- AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt),
- AUDMIXBUF_FMT_CHANNELS(pMixBuf->AudioFmt),
- AUDMIXBUF_FMT_BITS_PER_SAMPLE(pMixBuf->AudioFmt),
- RT_BOOL(AUDMIXBUF_FMT_SIGNED(pMixBuf->AudioFmt))));
-
- return audioMixBufAlloc(pMixBuf, cSamples);
-}
-
-/**
- * Returns @true if there are any audio samples available for processing,
- * @false if not.
- *
- * @return bool @true if there are any audio samples available for processing, @false if not.
- * @param pMixBuf Mixing buffer to return value for.
- */
-bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturn(pMixBuf, true);
-
- if (pMixBuf->pParent)
- return (pMixBuf->cMixed == 0);
- return (pMixBuf->cProcessed == 0);
-}
-
-/**
- * Links an audio mixing buffer to a parent mixing buffer. A parent mixing
- * buffer can have multiple children mixing buffers [1:N], whereas a child only can
- * have one parent mixing buffer [N:1].
- *
- * The mixing direction always goes from the child/children buffer(s) to the
- * parent buffer.
- *
- * For guest audio output the host backend owns the parent mixing buffer, the
- * device emulation owns the child/children.
- *
- * The audio format of each mixing buffer can vary; the internal mixing code
- * then will autiomatically do the (needed) conversion.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to link parent to.
- * @param pParent Parent mixing buffer to use for linking.
- *
- * @remark Circular linking is not allowed.
- */
-int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(pParent, VERR_INVALID_POINTER);
-
- AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt),
- ("Parent sample frequency (Hz) not set\n"), VERR_INVALID_PARAMETER);
- AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt),
- ("Buffer sample frequency (Hz) not set\n"), VERR_INVALID_PARAMETER);
- AssertMsgReturn(pMixBuf != pParent,
- ("Circular linking not allowed\n"), VERR_INVALID_PARAMETER);
-
- if (pMixBuf->pParent) /* Already linked? */
- {
- AUDMIXBUF_LOG(("%s: Already linked to \"%s\"\n",
- pMixBuf->pszName, pMixBuf->pParent->pszName));
- return VERR_ACCESS_DENIED;
- }
-
- RTListAppend(&pParent->lstBuffers, &pMixBuf->Node);
- pMixBuf->pParent = pParent;
-
- /* Calculate the frequency ratio. */
- pMixBuf->iFreqRatio = ((int64_t)AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt) << 32)
- / AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt);
-
- if (pMixBuf->iFreqRatio == 0) /* Catch division by zero. */
- pMixBuf->iFreqRatio = 1 << 20; /* Do a 1:1 conversion instead. */
-
- uint32_t cSamples = (uint32_t)RT_MIN( ((uint64_t)pParent->cSamples << 32)
- / pMixBuf->iFreqRatio, _64K /* 64K samples max. */);
- if (!cSamples)
- cSamples = pParent->cSamples;
-
- int rc = VINF_SUCCESS;
-
- if (cSamples != pMixBuf->cSamples)
- {
- AUDMIXBUF_LOG(("%s: Reallocating samples %RU32 -> %RU32\n",
- pMixBuf->pszName, pMixBuf->cSamples, cSamples));
-
- uint32_t cbSamples = cSamples * sizeof(PDMAUDIOSAMPLE);
- Assert(cbSamples);
- pMixBuf->pSamples = (PPDMAUDIOSAMPLE)RTMemRealloc(pMixBuf->pSamples, cbSamples);
- if (!pMixBuf->pSamples)
- rc = VERR_NO_MEMORY;
-
- if (RT_SUCCESS(rc))
- {
- pMixBuf->cSamples = cSamples;
-
- /* Make sure to zero the reallocated buffer so that it can be
- * used properly when blending with another buffer later. */
- RT_BZERO(pMixBuf->pSamples, cbSamples);
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- if (!pMixBuf->pRate)
- {
- /* Create rate conversion. */
- pMixBuf->pRate = (PPDMAUDIOSTRMRATE)RTMemAllocZ(sizeof(PDMAUDIOSTRMRATE));
- if (!pMixBuf->pRate)
- return VERR_NO_MEMORY;
- }
- else
- RT_BZERO(pMixBuf->pRate, sizeof(PDMAUDIOSTRMRATE));
-
- pMixBuf->pRate->dstInc = ((uint64_t)AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt) << 32)
- / AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt);
-
- AUDMIXBUF_LOG(("uThisHz=%RU32, uParentHz=%RU32, iFreqRatio=0x%RX64 (%RI64), uRateInc=0x%RX64 (%RU64), cSamples=%RU32 (%RU32 parent)\n",
- AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt),
- AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt),
- pMixBuf->iFreqRatio, pMixBuf->iFreqRatio,
- pMixBuf->pRate->dstInc, pMixBuf->pRate->dstInc,
- pMixBuf->cSamples,
- pParent->cSamples));
- AUDMIXBUF_LOG(("%s (%RU32Hz) -> %s (%RU32Hz)\n",
- pMixBuf->pszName, AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->AudioFmt),
- pMixBuf->pParent->pszName, AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->AudioFmt)));
- }
-
- return rc;
-}
-
-/**
- * Returns the number of audio samples mixed (processed) by
- * the parent mixing buffer.
- *
- * @return uint32_t Number of audio samples mixed (processed).
- * @param pMixBuf Mixing buffer to return number from.
- */
-uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturn(pMixBuf, 0);
-
- AssertMsgReturn(VALID_PTR(pMixBuf->pParent),
- ("Buffer is not linked to a parent buffer\n"),
- 0);
-
- AUDMIXBUF_LOG(("%s: cMixed=%RU32\n", pMixBuf->pszName, pMixBuf->cMixed));
- return pMixBuf->cMixed;
-}
-
-/**
- * Mixes audio samples from a source mixing buffer to a destination mixing buffer.
- *
- * @return IPRT status code.
- * @param pDst Destination mixing buffer.
- * @param pSrc Source mixing buffer.
- * @param cSamples Number of source audio samples to mix.
- * @param pcProcessed Number of audio samples successfully mixed.
- */
-static int audioMixBufMixTo(PPDMAUDIOMIXBUF pDst, PPDMAUDIOMIXBUF pSrc, uint32_t cSamples, uint32_t *pcProcessed)
-{
- AssertPtrReturn(pDst, VERR_INVALID_POINTER);
- AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
- AssertReturn(cSamples, VERR_INVALID_PARAMETER);
- /* pcProcessed is optional. */
-
- /* Live samples indicate how many samples there are in the source buffer
- * which have not been processed yet by the destination buffer. */
- uint32_t cLive = pSrc->cMixed;
- if (cLive >= pDst->cSamples)
- AUDMIXBUF_LOG(("Destination buffer \"%s\" full (%RU32 samples max), live samples = %RU32\n",
- pDst->pszName, pDst->cSamples, cLive));
-
- /* Dead samples are the number of samples in the destination buffer which
- * will not be needed, that is, are not needed in order to process the live
- * samples of the source buffer. */
- uint32_t cDead = pDst->cSamples - cLive;
-
- uint32_t cToReadTotal = (uint32_t)RT_MIN(cSamples, AUDIOMIXBUF_S2S_RATIO(pSrc, cDead));
- uint32_t offRead = 0;
-
- uint32_t cReadTotal = 0;
- uint32_t cWrittenTotal = 0;
- uint32_t offWrite = (pDst->offReadWrite + cLive) % pDst->cSamples;
-
- AUDMIXBUF_LOG(("pSrc=%s (%RU32 samples), pDst=%s (%RU32 samples), cLive=%RU32, cDead=%RU32, cToReadTotal=%RU32, offWrite=%RU32\n",
- pSrc->pszName, pSrc->cSamples, pDst->pszName, pDst->cSamples, cLive, cDead, cToReadTotal, offWrite));
-
- uint32_t cToRead, cToWrite;
- uint32_t cWritten, cRead;
-
- while (cToReadTotal)
- {
- cDead = pDst->cSamples - cLive;
-
- cToRead = cToReadTotal;
- cToWrite = RT_MIN(cDead, pDst->cSamples - offWrite);
- if (!cToWrite)
- {
- AUDMIXBUF_LOG(("Warning: Destination buffer \"%s\" full\n", pDst->pszName));
- break;
- }
-
- Assert(offWrite + cToWrite <= pDst->cSamples);
- Assert(offRead + cToRead <= pSrc->cSamples);
-
- AUDMIXBUF_LOG(("\t%RU32Hz -> %RU32Hz\n", AUDMIXBUF_FMT_SAMPLE_FREQ(pSrc->AudioFmt), AUDMIXBUF_FMT_SAMPLE_FREQ(pDst->AudioFmt)));
- AUDMIXBUF_LOG(("\tcDead=%RU32, offWrite=%RU32, cToWrite=%RU32, offRead=%RU32, cToRead=%RU32\n",
- cDead, offWrite, cToWrite, offRead, cToRead));
-
- audioMixBufOpBlend(pDst->pSamples + offWrite, cToWrite,
- pSrc->pSamples + offRead, cToRead,
- pSrc->pRate, &cWritten, &cRead);
-
- AUDMIXBUF_LOG(("\t\tcWritten=%RU32, cRead=%RU32\n", cWritten, cRead));
-
- cReadTotal += cRead;
- cWrittenTotal += cWritten;
-
- offRead += cRead;
- Assert(cToReadTotal >= cRead);
- cToReadTotal -= cRead;
-
- offWrite = (offWrite + cWritten) % pDst->cSamples;
-
- cLive += cWritten;
- }
-
- pSrc->cMixed += cWrittenTotal;
- pDst->cProcessed += cWrittenTotal;
-#ifdef DEBUG
- s_cSamplesMixedTotal += cWrittenTotal;
- audioMixBufPrint(pDst);
-#endif
-
- if (pcProcessed)
- *pcProcessed = cReadTotal;
-
- AUDMIXBUF_LOG(("cReadTotal=%RU32 (pcProcessed), cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstProc=%RU32\n",
- cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cProcessed));
- return VINF_SUCCESS;
-}
-
-/**
- * Mixes (multiplexes) audio samples to all connected mixing buffer children.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to use.
- * @param cSamples Number of audio samples to mix to children.
- * @param pcProcessed Maximum number of audio samples successfully mixed
- * to all children. Optional.
- */
-int AudioMixBufMixToChildren(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples,
- uint32_t *pcProcessed)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
-
- if (!cSamples)
- {
- if (pcProcessed)
- *pcProcessed = 0;
- return VINF_SUCCESS;
- }
-
- int rc = VINF_SUCCESS;
-
- uint32_t cProcessed;
- uint32_t cProcessedMax = 0;
-
- PPDMAUDIOMIXBUF pIter;
- RTListForEach(&pMixBuf->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
- {
- rc = audioMixBufMixTo(pIter, pMixBuf, cSamples, &cProcessed);
- if (RT_FAILURE(rc))
- break;
-
- cProcessedMax = RT_MAX(cProcessedMax, cProcessed);
- }
-
- if (pcProcessed)
- *pcProcessed = cProcessedMax;
-
- return rc;
-}
-
-/**
- * Mixes audio samples down to the parent mixing buffer.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to mix samples down to parent.
- * @param cSamples Number of audio samples to mix down.
- * @param pcProcessed Number of audio samples successfully processed. Optional.
- */
-int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples,
- uint32_t *pcProcessed)
-{
- AssertMsgReturn(VALID_PTR(pMixBuf->pParent),
- ("Buffer is not linked to a parent buffer\n"),
- VERR_INVALID_PARAMETER);
-
- return audioMixBufMixTo(pMixBuf->pParent, pMixBuf, cSamples, pcProcessed);
-}
-
-#ifdef DEBUG
-/**
- * Prints statistics and status of a mixing buffer to the logger.
- * For debug versions only.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to print.
- */
-static inline void audioMixBufPrint(PPDMAUDIOMIXBUF pMixBuf)
-{
- PPDMAUDIOMIXBUF pParent = pMixBuf;
- if (pMixBuf->pParent)
- pParent = pMixBuf->pParent;
-
- AUDMIXBUF_LOG(("********************************************\n"));
- AUDMIXBUF_LOG(("%s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
- pParent->pszName,
- pParent->offReadWrite, pParent->cProcessed, pParent->cMixed,
- AUDIOMIXBUF_S2B(pParent, 1)));
-
- PPDMAUDIOMIXBUF pIter;
- RTListForEach(&pParent->lstBuffers, pIter, PDMAUDIOMIXBUF, Node)
- {
- AUDMIXBUF_LOG(("\t%s: offReadWrite=%RU32, cProcessed=%RU32, cMixed=%RU32 (BpS=%RU32)\n",
- pIter->pszName,
- pIter->offReadWrite, pIter->cProcessed, pIter->cMixed,
- AUDIOMIXBUF_S2B(pIter, 1)));
- }
- AUDMIXBUF_LOG(("Total samples mixed: %RU64\n", s_cSamplesMixedTotal));
- AUDMIXBUF_LOG(("********************************************\n"));
-}
-#endif
-
-/**
- * Returns the total number of samples processed.
- *
- * @return uint32_t
- * @param pMixBuf
- */
-uint32_t AudioMixBufProcessed(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturn(pMixBuf, 0);
-
- AUDMIXBUF_LOG(("%s: cProcessed=%RU32\n", pMixBuf->pszName, pMixBuf->cProcessed));
- return pMixBuf->cProcessed;
-}
-
-/**
- * Reads audio samples at a specific offset.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to read audio samples from.
- * @param offSamples Offset (in audio samples) to start reading from.
- * @param pvBuf Pointer to buffer to write output to.
- * @param cbBuf Size (in bytes) of buffer to write to.
- * @param pcbRead Size (in bytes) of data read. Optional.
- */
-int AudioMixBufReadAt(PPDMAUDIOMIXBUF pMixBuf,
- uint32_t offSamples,
- void *pvBuf, uint32_t cbBuf,
- uint32_t *pcbRead)
-{
- return AudioMixBufReadAtEx(pMixBuf, pMixBuf->AudioFmt,
- offSamples, pvBuf, cbBuf, pcbRead);
-}
-
-/**
- * Reads audio samples at a specific offset.
- * If the audio format of the mixing buffer and the requested audio format do
- * not match the output will be converted accordingly.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to read audio samples from.
- * @param enmFmt Audio format to use for output.
- * @param offSamples Offset (in audio samples) to start reading from.
- * @param pvBuf Pointer to buffer to write output to.
- * @param cbBuf Size (in bytes) of buffer to write to.
- * @param pcbRead Size (in bytes) of data read. Optional.
- */
-int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
- uint32_t offSamples,
- void *pvBuf, uint32_t cbBuf,
- uint32_t *pcbRead)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- /* pcbRead is optional. */
-
- uint32_t cDstSamples = pMixBuf->cSamples;
- uint32_t cLive = pMixBuf->cProcessed;
-
- uint32_t cDead = cDstSamples - cLive;
- uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_S2S_RATIO(pMixBuf, cDead);
- cToProcess = RT_MIN(cToProcess, AUDIOMIXBUF_B2S(pMixBuf, cbBuf));
-
- AUDMIXBUF_LOG(("%s: offSamples=%RU32, cLive=%RU32, cDead=%RU32, cToProcess=%RU32\n",
- pMixBuf->pszName, offSamples, cLive, cDead, cToProcess));
-
- int rc;
- if (cToProcess)
- {
- PAUDMIXBUF_FN_CONVTO pConv = audioMixBufConvToLookup(enmFmt);
- if (pConv)
- {
- AUDMIXBUF_CONVOPTS convOpts = { cToProcess, pMixBuf->Volume };
- pConv(pvBuf, pMixBuf->pSamples + offSamples, &convOpts);
-
- rc = VINF_SUCCESS;
- }
- else
- rc = VERR_INVALID_PARAMETER;
-
-#ifdef DEBUG
- audioMixBufPrint(pMixBuf);
-#endif
- }
- else
- rc = VINF_SUCCESS;
-
- if (RT_SUCCESS(rc))
- {
- if (pcbRead)
- *pcbRead = AUDIOMIXBUF_S2B(pMixBuf, cToProcess);
- }
-
- AUDMIXBUF_LOG(("cbRead=%RU32, rc=%Rrc\n", AUDIOMIXBUF_S2B(pMixBuf, cToProcess), rc));
- return rc;
-}
-
-/**
- * Reads audio samples. The audio format of the mixing buffer will be used.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to read audio samples from.
- * @param pvBuf Pointer to buffer to write output to.
- * @param cbBuf Size (in bytes) of buffer to write to.
- * @param pcRead Number of audio samples read. Optional.
- */
-int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf,
- void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
-{
- return AudioMixBufReadCircEx(pMixBuf, pMixBuf->AudioFmt,
- pvBuf, cbBuf, pcRead);
-}
-
-/**
- * Reads audio samples in a specific audio format.
- * If the audio format of the mixing buffer and the requested audio format do
- * not match the output will be converted accordingly.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to read audio samples from.
- * @param enmFmt Audio format to use for output.
- * @param pvBuf Pointer to buffer to write output to.
- * @param cbBuf Size (in bytes) of buffer to write to.
- * @param pcRead Number of audio samples read. Optional.
- */
-int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
- void *pvBuf, uint32_t cbBuf, uint32_t *pcRead)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- /* pcbRead is optional. */
-
- if (!cbBuf)
- return VINF_SUCCESS;
-
- uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2S(pMixBuf, cbBuf), pMixBuf->cProcessed);
-
- AUDMIXBUF_LOG(("%s: pvBuf=%p, cbBuf=%zu (%RU32 samples), cToRead=%RU32\n",
- pMixBuf->pszName, pvBuf, cbBuf, AUDIOMIXBUF_B2S(pMixBuf, cbBuf), cToRead));
-
- if (!cToRead)
- {
-#ifdef DEBUG
- audioMixBufPrint(pMixBuf);
-#endif
- if (pcRead)
- *pcRead = 0;
- return VINF_SUCCESS;
- }
-
- PAUDMIXBUF_FN_CONVTO pConv = audioMixBufConvToLookup(enmFmt);
- if (!pConv) /* Audio format not supported. */
- return VERR_NOT_SUPPORTED;
-
- PPDMAUDIOSAMPLE pSamplesSrc1 = pMixBuf->pSamples + pMixBuf->offReadWrite;
- uint32_t cLenSrc1 = cToRead;
-
- PPDMAUDIOSAMPLE pSamplesSrc2 = NULL;
- uint32_t cLenSrc2 = 0;
-
- uint32_t offRead = pMixBuf->offReadWrite + cToRead;
-
- /*
- * Do we need to wrap around to read all requested data, that is,
- * starting at the beginning of our circular buffer? This then will
- * be the optional second part to do.
- */
- if (offRead >= pMixBuf->cSamples)
- {
- Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
- cLenSrc1 = pMixBuf->cSamples - pMixBuf->offReadWrite;
-
- pSamplesSrc2 = pMixBuf->pSamples;
- Assert(cToRead >= cLenSrc1);
- cLenSrc2 = RT_MIN(cToRead - cLenSrc1, pMixBuf->cSamples);
-
- /* Save new read offset. */
- offRead = cLenSrc2;
- }
-
- AUDMIXBUF_CONVOPTS convOpts;
- convOpts.Volume = pMixBuf->Volume;
-
- /* Anything to do at all? */
- int rc = VINF_SUCCESS;
- if (cLenSrc1)
- {
- convOpts.cSamples = cLenSrc1;
-
- AUDMIXBUF_LOG(("P1: offRead=%RU32, cToRead=%RU32\n", pMixBuf->offReadWrite, cLenSrc1));
- pConv(pvBuf, pSamplesSrc1, &convOpts);
- }
-
- /* Second part present? */
- if ( RT_LIKELY(RT_SUCCESS(rc))
- && cLenSrc2)
- {
- AssertPtr(pSamplesSrc2);
-
- convOpts.cSamples = cLenSrc2;
-
- AUDMIXBUF_LOG(("P2: cToRead=%RU32, offWrite=%RU32 (%zu bytes)\n", cLenSrc2, cLenSrc1,
- AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1)));
- pConv((uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1), pSamplesSrc2, &convOpts);
- }
-
- if (RT_SUCCESS(rc))
- {
-#ifdef DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_readcirc.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- if (RT_SUCCESS(rc))
- {
- RTFileWrite(fh, pvBuf, AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1 + cLenSrc2), NULL);
- RTFileClose(fh);
- }
-#endif
- pMixBuf->offReadWrite = offRead % pMixBuf->cSamples;
- pMixBuf->cProcessed -= RT_MIN(cLenSrc1 + cLenSrc2, pMixBuf->cProcessed);
-
- if (pcRead)
- *pcRead = cLenSrc1 + cLenSrc2;
- }
-
-#ifdef DEBUG
- audioMixBufPrint(pMixBuf);
-#endif
-
- AUDMIXBUF_LOG(("cRead=%RU32 (%zu bytes), rc=%Rrc\n",
- cLenSrc1 + cLenSrc2,
- AUDIOMIXBUF_S2B(pMixBuf, cLenSrc1 + cLenSrc2), rc));
- return rc;
-}
-
-/**
- * Resets a mixing buffer.
- *
- * @param pMixBuf Mixing buffer to reset.
- */
-void AudioMixBufReset(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturnVoid(pMixBuf);
-
- AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
-
- pMixBuf->offReadWrite = 0;
- pMixBuf->cMixed = 0;
- pMixBuf->cProcessed = 0;
-
- AudioMixBufClear(pMixBuf);
-}
-
-/**
- * Sets the overall (master) volume.
- *
- * @param pMixBuf Mixing buffer to set volume for.
- * @param pVol Pointer to volume structure to set.
- */
-void AudioMixBufSetVolume(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOVOLUME pVol)
-{
- AssertPtrReturnVoid(pMixBuf);
- AssertPtrReturnVoid(pVol);
-
- LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight));
-
- pMixBuf->Volume.fMuted = pVol->fMuted;
- /** @todo Ensure that the input is in the correct range/initialized! */
- pMixBuf->Volume.uLeft = s_aVolumeConv[pVol->uLeft & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
- pMixBuf->Volume.uRight = s_aVolumeConv[pVol->uRight & 0xFF] * (AUDIOMIXBUF_VOL_0DB >> 16);
-
- LogFlowFunc(("\t-> lVol=%#RX32, rVol=%#RX32\n", pMixBuf->Volume.uLeft, pMixBuf->Volume.uRight));
-}
-
-/**
- * Returns the maximum amount of audio samples this buffer can hold.
- *
- * @return uint32_t Size (in audio samples) the mixing buffer can hold.
- * @param pMixBuf Mixing buffer to retrieve maximum for.
- */
-uint32_t AudioMixBufSize(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturn(pMixBuf, 0);
- return pMixBuf->cSamples;
-}
-
-/**
- * Returns the maximum amount of bytes this buffer can hold.
- *
- * @return uint32_t Size (in bytes) the mixing buffer can hold.
- * @param pMixBuf Mixing buffer to retrieve maximum for.
- */
-uint32_t AudioMixBufSizeBytes(PPDMAUDIOMIXBUF pMixBuf)
-{
- AssertPtrReturn(pMixBuf, 0);
- return AUDIOMIXBUF_S2B(pMixBuf, pMixBuf->cSamples);
-}
-
-/**
- * Unlinks a mixing buffer from its parent, if any.
- *
- * @return IPRT status code.
- * @param pMixBuf Mixing buffer to unlink from parent.
- */
-void AudioMixBufUnlink(PPDMAUDIOMIXBUF pMixBuf)
-{
- if (!pMixBuf || !pMixBuf->pszName)
- return;
-
- AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
-
- if (pMixBuf->pParent)
- {
- AUDMIXBUF_LOG(("%s: Unlinking from parent \"%s\"\n",
- pMixBuf->pszName, pMixBuf->pParent->pszName));
-
- RTListNodeRemove(&pMixBuf->Node);
-
- /* Make sure to reset the parent mixing buffer each time it gets linked
- * to a new child. */
- AudioMixBufReset(pMixBuf->pParent);
- pMixBuf->pParent = NULL;
- }
-
- PPDMAUDIOMIXBUF pIter;
- while (!RTListIsEmpty(&pMixBuf->lstBuffers))
- {
- pIter = RTListGetFirst(&pMixBuf->lstBuffers, PDMAUDIOMIXBUF, Node);
-
- AUDMIXBUF_LOG(("\tUnlinking \"%s\"\n", pIter->pszName));
-
- AudioMixBufReset(pIter->pParent);
- pIter->pParent = NULL;
-
- RTListNodeRemove(&pIter->Node);
- }
-
- if (pMixBuf->pRate)
- {
- pMixBuf->pRate->dstOffset = pMixBuf->pRate->srcOffset = 0;
- pMixBuf->pRate->dstInc = 0;
- }
-
- pMixBuf->iFreqRatio = 1; /* Prevent division by zero. */
-}
-
-/**
- * Writes audio samples at a specific offset.
- * The sample format being written must match the format of the mixing buffer.
- *
- * @return IPRT status code.
- * @param pMixBuf Pointer to mixing buffer to write to.
- * @param enmFmt Audio format supplied in the buffer.
- * @param offSamples Offset (in samples) starting to write at.
- * @param pvBuf Pointer to audio buffer to be written.
- * @param cbBuf Size (in bytes) of audio buffer.
- * @param pcWritten Returns number of audio samples written. Optional.
- */
-int AudioMixBufWriteAt(PPDMAUDIOMIXBUF pMixBuf,
- uint32_t offSamples,
- const void *pvBuf, uint32_t cbBuf,
- uint32_t *pcWritten)
-{
- return AudioMixBufWriteAtEx(pMixBuf, pMixBuf->AudioFmt,
- offSamples, pvBuf, cbBuf, pcWritten);
-}
-
-/**
- * Writes audio samples at a specific offset. The audio sample format
- * to be written can be different from the audio format the mixing buffer
- * operates on.
- *
- * @return IPRT status code.
- * @param pMixBuf Pointer to mixing buffer to write to.
- * @param enmFmt Audio format supplied in the buffer.
- * @param offSamples Offset (in samples) starting to write at.
- * @param pvBuf Pointer to audio buffer to be written.
- * @param cbBuf Size (in bytes) of audio buffer.
- * @param pcWritten Returns number of audio samples written. Optional.
- */
-int AudioMixBufWriteAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
- uint32_t offSamples,
- const void *pvBuf, uint32_t cbBuf,
- uint32_t *pcWritten)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- /* pcWritten is optional. */
-
- uint32_t cDstSamples = pMixBuf->pParent
- ? pMixBuf->pParent->cSamples : pMixBuf->cSamples;
- uint32_t cLive = pMixBuf->cProcessed;
-
- uint32_t cDead = cDstSamples - cLive;
- uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_S2S_RATIO(pMixBuf, cDead);
- cToProcess = RT_MIN(cToProcess, AUDIOMIXBUF_B2S(pMixBuf, cbBuf));
-
- AUDMIXBUF_LOG(("%s: offSamples=%RU32, cLive=%RU32, cDead=%RU32, cToProcess=%RU32\n",
- pMixBuf->pszName, offSamples, cLive, cDead, cToProcess));
-
- if (offSamples + cToProcess > pMixBuf->cSamples)
- return VERR_BUFFER_OVERFLOW;
-
- PAUDMIXBUF_FN_CONVFROM pConv = audioMixBufConvFromLookup(enmFmt, pMixBuf->Volume.fMuted);
- if (!pConv)
- return VERR_NOT_SUPPORTED;
-
- int rc;
- uint32_t cWritten;
-
-#ifdef DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeat.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- if (RT_SUCCESS(rc))
- {
- RTFileWrite(fh, pvBuf, cbBuf, NULL);
- RTFileClose(fh);
- }
-#endif
-
- if (cToProcess)
- {
- AUDMIXBUF_CONVOPTS convOpts = { cToProcess, pMixBuf->Volume };
-
- cWritten = pConv(pMixBuf->pSamples + offSamples, pvBuf, cbBuf, &convOpts);
-#ifdef DEBUG
- audioMixBufPrint(pMixBuf);
-#endif
- rc = cWritten ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Fudge! */
- }
- else
- {
- cWritten = 0;
- rc = VINF_SUCCESS;
- }
-
- if (RT_SUCCESS(rc))
- {
- if (pcWritten)
- *pcWritten = cWritten;
- }
-
- AUDMIXBUF_LOG(("cWritten=%RU32, rc=%Rrc\n", cWritten, rc));
- return rc;
-}
-
-/**
- * Writes audio samples. The sample format being written must match the
- * format of the mixing buffer.
- *
- * @return IPRT status code.
- * @param pMixBuf Pointer to mixing buffer to write to.
- * @param pvBuf Pointer to audio buffer to be written.
- * @param cbBuf Size (in bytes) of audio buffer.
- * @param pcWritten Returns number of audio samples written. Optional.
- */
-int AudioMixBufWriteCirc(PPDMAUDIOMIXBUF pMixBuf,
- const void *pvBuf, uint32_t cbBuf,
- uint32_t *pcWritten)
-{
- return AudioMixBufWriteCircEx(pMixBuf, pMixBuf->AudioFmt, pvBuf, cbBuf, pcWritten);
-}
-
-/**
- * Writes audio samples of a specific format.
- *
- * @return IPRT status code.
- * @param pMixBuf Pointer to mixing buffer to write to.
- * @param enmFmt Audio format supplied in the buffer.
- * @param pvBuf Pointer to audio buffer to be written.
- * @param cbBuf Size (in bytes) of audio buffer.
- * @param pcWritten Returns number of audio samples written. Optional.
- */
-int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
- const void *pvBuf, uint32_t cbBuf,
- uint32_t *pcWritten)
-{
- AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- /* pcbWritten is optional. */
-
- if (!cbBuf)
- {
- if (pcWritten)
- *pcWritten = 0;
- return VINF_SUCCESS;
- }
-
- PPDMAUDIOMIXBUF pParent = pMixBuf->pParent;
-
- AUDMIXBUF_LOG(("%s: enmFmt=%ld, pBuf=%p, cbBuf=%zu, pParent=%p (%RU32)\n",
- pMixBuf->pszName, enmFmt, pvBuf, cbBuf, pParent, pParent ? pParent->cSamples : 0));
-
- if ( pParent
- && pParent->cSamples <= pMixBuf->cMixed)
- {
- if (pcWritten)
- *pcWritten = 0;
-
- AUDMIXBUF_LOG(("%s: Parent buffer %s is full\n",
- pMixBuf->pszName, pMixBuf->pParent->pszName));
-
- return VINF_SUCCESS;
- }
-
- PAUDMIXBUF_FN_CONVFROM pConv = audioMixBufConvFromLookup(enmFmt, pMixBuf->Volume.fMuted);
- if (!pConv)
- return VERR_NOT_SUPPORTED;
-
- int rc = VINF_SUCCESS;
-
- uint32_t cToWrite = AUDIOMIXBUF_B2S(pMixBuf, cbBuf);
- AssertMsg(cToWrite, ("cToWrite is 0 (cbBuf=%zu)\n", cbBuf));
-
- PPDMAUDIOSAMPLE pSamplesDst1 = pMixBuf->pSamples + pMixBuf->offReadWrite;
- uint32_t cLenDst1 = cToWrite;
-
- PPDMAUDIOSAMPLE pSamplesDst2 = NULL;
- uint32_t cLenDst2 = 0;
-
- uint32_t offWrite = pMixBuf->offReadWrite + cToWrite;
-
- /*
- * Do we need to wrap around to write all requested data, that is,
- * starting at the beginning of our circular buffer? This then will
- * be the optional second part to do.
- */
- if (offWrite >= pMixBuf->cSamples)
- {
- Assert(pMixBuf->offReadWrite <= pMixBuf->cSamples);
- cLenDst1 = pMixBuf->cSamples - pMixBuf->offReadWrite;
-
- pSamplesDst2 = pMixBuf->pSamples;
- Assert(cToWrite >= cLenDst1);
- cLenDst2 = RT_MIN(cToWrite - cLenDst1, pMixBuf->cSamples);
-
- /* Save new read offset. */
- offWrite = cLenDst2;
- }
-
- uint32_t cWrittenTotal = 0;
-
- AUDMIXBUF_CONVOPTS convOpts;
- convOpts.Volume = pMixBuf->Volume;
-
- /* Anything to do at all? */
- if (cLenDst1)
- {
- convOpts.cSamples = cLenDst1;
- cWrittenTotal = pConv(pSamplesDst1, pvBuf, cbBuf, &convOpts);
- }
-
- /* Second part present? */
- if ( RT_LIKELY(RT_SUCCESS(rc))
- && cLenDst2)
- {
- AssertPtr(pSamplesDst2);
-
- convOpts.cSamples = cLenDst2;
- cWrittenTotal += pConv(pSamplesDst2, (uint8_t *)pvBuf + AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), cbBuf, &convOpts);
- }
-
-#ifdef DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeex.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- RTFileWrite(fh, pSamplesDst1, AUDIOMIXBUF_S2B(pMixBuf, cLenDst1), NULL);
- RTFileClose(fh);
-#endif
-
- AUDMIXBUF_LOG(("cLenDst1=%RU32, cLenDst2=%RU32, offWrite=%RU32\n",
- cLenDst1, cLenDst2, offWrite));
-
- if (RT_SUCCESS(rc))
- {
- pMixBuf->offReadWrite = offWrite % pMixBuf->cSamples;
- pMixBuf->cProcessed = RT_MIN(pMixBuf->cProcessed + cLenDst1 + cLenDst2,
- pMixBuf->cSamples /* Max */);
- if (pcWritten)
- *pcWritten = cLenDst1 + cLenDst2;
- }
-
-#ifdef DEBUG
- audioMixBufPrint(pMixBuf);
-#endif
-
- AUDMIXBUF_LOG(("cWritten=%RU32 (%zu bytes), rc=%Rrc\n",
- cLenDst1 + cLenDst2,
- AUDIOMIXBUF_S2B(pMixBuf, cLenDst1 + cLenDst2), rc));
- return rc;
-}
-
diff --git a/src/VBox/Devices/Audio_50/AudioMixBuffer.h b/src/VBox/Devices/Audio_50/AudioMixBuffer.h
deleted file mode 100644
index 11c5912..0000000
--- a/src/VBox/Devices/Audio_50/AudioMixBuffer.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* $Id: AudioMixBuffer.h $ */
-/** @file
- * VBox audio: Mixing buffer to convert audio samples to/from different
- * rates / formats.
- */
-
-/*
- * Copyright (C) 2014-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef AUDIO_MIXBUF_H
-#define AUDIO_MIXBUF_H
-
-#include <iprt/cdefs.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
-/** Constructs 32 bit value for given frequency, number of channels, bits per sample and signed bit.
- * Note: This currently matches 1:1 the VRDE encoding -- this might change in the future, so better don't rely on this fact! */
-#define AUDMIXBUF_AUDIO_FMT_MAKE(freq, c, bps, s) ((((s) & 0x1) << 28) + (((bps) & 0xFF) << 20) + (((c) & 0xF) << 16) + ((freq) & 0xFFFF))
-
-/** Decodes frequency (Hz). */
-#define AUDMIXBUF_FMT_SAMPLE_FREQ(a) ((a) & 0xFFFF)
-/** Decodes number of channels. */
-#define AUDMIXBUF_FMT_CHANNELS(a) (((a) >> 16) & 0xF)
-/** Decodes signed bit. */
-#define AUDMIXBUF_FMT_SIGNED(a) (((a) >> 28) & 0x1)
-/** Decodes number of bits per sample. */
-#define AUDMIXBUF_FMT_BITS_PER_SAMPLE(a) (((a) >> 20) & 0xFF)
-/** Decodes number of bytes per sample. */
-#define AUDMIXBUF_FMT_BYTES_PER_SAMPLE(a) ((AUDMIXBUF_AUDIO_FMT_BITS_PER_SAMPLE(a) + 7) / 8)
-
-/** Converts samples to bytes. */
-#define AUDIOMIXBUF_S2B(pBuf, samples) ((samples) << (pBuf)->cShift)
-/** Converts samples to bytes, respecting the conversion ratio to
- * a linked buffer. */
-#define AUDIOMIXBUF_S2B_RATIO(pBuf, samples) ((((int64_t) samples << 32) / (pBuf)->iFreqRatio) << (pBuf)->cShift)
-/** Converts bytes to samples, *not* taking the conversion ratio
- * into account. */
-#define AUDIOMIXBUF_B2S(pBuf, cb) (cb >> (pBuf)->cShift)
-/** Converts number of samples according to the buffer's ratio. */
-#define AUDIOMIXBUF_S2S_RATIO(pBuf, samples) (((int64_t) samples << 32) / (pBuf)->iFreqRatio)
-
-
-int AudioMixBufAcquire(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToRead, PPDMAUDIOSAMPLE *ppvSamples, uint32_t *pcSamplesRead);
-uint32_t AudioMixBufAvail(PPDMAUDIOMIXBUF pMixBuf);
-inline uint32_t AudioMixBufBytesToSamples(PPDMAUDIOMIXBUF pMixBuf);
-void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf);
-void AudioMixBufDestroy(PPDMAUDIOMIXBUF pMixBuf);
-void AudioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamplesToClear);
-uint32_t AudioMixBufFree(PPDMAUDIOMIXBUF pMixBuf);
-uint32_t AudioMixBufFreeBytes(PPDMAUDIOMIXBUF pMixBuf);
-int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMPCMPROPS pProps, uint32_t cSamples);
-bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf);
-int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent);
-uint32_t AudioMixBufMixed(PPDMAUDIOMIXBUF pMixBuf);
-int AudioMixBufMixToChildren(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
-int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSamples, uint32_t *pcProcessed);
-uint32_t AudioMixBufProcessed(PPDMAUDIOMIXBUF pMixBuf);
-int AudioMixBufReadAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
-int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, uint32_t offSamples, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead);
-int AudioMixBufReadCirc(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead);
-int AudioMixBufReadCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, uint32_t cbBuf, uint32_t *pcRead);
-void AudioMixBufReset(PPDMAUDIOMIXBUF pMixBuf);
-void AudioMixBufSetVolume(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOVOLUME pVol);
-uint32_t AudioMixBufSize(PPDMAUDIOMIXBUF pMixBuf);
-uint32_t AudioMixBufSizeBytes(PPDMAUDIOMIXBUF pMixBuf);
-void AudioMixBufUnlink(PPDMAUDIOMIXBUF pMixBuf);
-int AudioMixBufWriteAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offSamples, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
-int AudioMixBufWriteAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, uint32_t offSamples, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
-int AudioMixBufWriteCirc(PPDMAUDIOMIXBUF pMixBuf, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
-int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten);
-
-#endif /* !AUDIO_MIXBUF_H */
-
diff --git a/src/VBox/Devices/Audio_50/AudioMixer.cpp b/src/VBox/Devices/Audio_50/AudioMixer.cpp
deleted file mode 100644
index 83a082f..0000000
--- a/src/VBox/Devices/Audio_50/AudioMixer.cpp
+++ /dev/null
@@ -1,520 +0,0 @@
-/* $Id: AudioMixer.cpp $ */
-/** @file
- * VBox audio: Mixing routines, mainly used by the various audio device
- * emulations to achieve proper multiplexing from/to attached
- * devices LUNs.
- */
-
-/*
- * Copyright (C) 2014-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-#define LOG_GROUP LOG_GROUP_AUDIO_MIXER
-#include <VBox/log.h>
-#include "AudioMixer.h"
-#include "AudioMixBuffer.h"
-
-#include <VBox/vmm/pdm.h>
-#include <VBox/err.h>
-#include <VBox/vmm/mm.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
-#include <iprt/alloc.h>
-#include <iprt/asm-math.h>
-#include <iprt/assert.h>
-#include <iprt/string.h>
-
-static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster);
-
-
-int AudioMixerAddSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink)
-{
- AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- /** ppSink is optional. */
-
- int rc = VINF_SUCCESS;
-
- PAUDMIXSINK pSink = (PAUDMIXSINK)RTMemAllocZ(sizeof(AUDMIXSINK));
- if (pSink)
- {
- pSink->pszName = RTStrDup(pszName);
- if (!pSink->pszName)
- rc = VERR_NO_MEMORY;
-
- if (RT_SUCCESS(rc))
- {
- pSink->pParent = pMixer;
- pSink->cStreams = 0;
- pSink->enmDir = enmDir;
- RTListInit(&pSink->lstStreams);
-
- /* Set initial volume to max. */
- pSink->Volume.fMuted = false;
- pSink->Volume.uLeft = 0x7F;
- pSink->Volume.uRight = 0x7F;
-
- RTListAppend(&pMixer->lstSinks, &pSink->Node);
- pMixer->cSinks++;
-
- LogFlowFunc(("pMixer=%p, pSink=%p, cSinks=%RU8\n",
- pMixer, pSink, pMixer->cSinks));
-
- if (ppSink)
- *ppSink = pSink;
- }
- else
- RTMemFree(pSink);
- }
- else
- rc = VERR_NO_MEMORY;
-
- return rc;
-}
-
-int AudioMixerAddStreamIn(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMIN pStream,
- uint32_t uFlags, PAUDMIXSTREAM *ppStream)
-{
- RT_NOREF(uFlags);
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /** @todo Add flag validation. */
- /* ppStream is optional. */
-
- int rc;
-
- if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
- return VERR_TOO_MUCH_DATA;
-
- PAUDMIXSTREAM pMixStream = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
- if (pMixStream)
- {
- pMixStream->pConn = pConnector;
- pMixStream->pIn = pStream;
- /** @todo Process flags. */
-
- RTListAppend(&pSink->lstStreams, &pMixStream->Node);
- pSink->cStreams++;
-
- LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",
- pSink->pszName, pMixStream, pSink->cStreams));
-
- /* Increase the stream's reference count to let others know
- * we're reyling on it to be around now. */
- pStream->State.cRefs++;
-
- if (ppStream)
- *ppStream = pMixStream;
-
- rc = VINF_SUCCESS;
- }
- else
- rc = VERR_NO_MEMORY;
-
- return rc;
-}
-
-int AudioMixerAddStreamOut(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMOUT pStream,
- uint32_t uFlags, PAUDMIXSTREAM *ppStream)
-{
- RT_NOREF(uFlags);
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /** @todo Add flag validation. */
- /* ppStream is optional. */
-
- int rc;
-
- if (pSink->cStreams == UINT8_MAX) /* 255 streams per sink max. */
- return VERR_TOO_MUCH_DATA;
-
- PAUDMIXSTREAM pMixStream
- = (PAUDMIXSTREAM)RTMemAllocZ(sizeof(AUDMIXSTREAM));
- if (pMixStream)
- {
- pMixStream->pConn = pConnector;
- pMixStream->pOut = pStream;
- /** @todo Process flags. */
-
- RTListAppend(&pSink->lstStreams, &pMixStream->Node);
- pSink->cStreams++;
-
- LogFlowFunc(("%s: pStream=%p, cStreams=%RU8\n",
- pSink->pszName, pMixStream, pSink->cStreams));
-
- /* Increase the stream's reference count to let others know
- * we're reyling on it to be around now. */
- pStream->State.cRefs++;
-
- if (ppStream)
- *ppStream = pMixStream;
-
- rc = VINF_SUCCESS;
- }
- else
- rc = VERR_NO_MEMORY;
-
- return rc;
-}
-
-int AudioMixerControlStream(PAUDIOMIXER pMixer, PAUDMIXSTREAM pHandle)
-{
- RT_NOREF(pMixer, pHandle);
- return VERR_NOT_IMPLEMENTED;
-}
-
-int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer)
-{
- RT_NOREF(uFlags);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- /** @todo Add flag validation. */
- AssertPtrReturn(ppMixer, VERR_INVALID_POINTER);
-
- int rc = VINF_SUCCESS;
-
- PAUDIOMIXER pMixer = (PAUDIOMIXER)RTMemAllocZ(sizeof(AUDIOMIXER));
- if (pMixer)
- {
- pMixer->pszName = RTStrDup(pszName);
- if (!pMixer->pszName)
- rc = VERR_NO_MEMORY;
-
- if (RT_SUCCESS(rc))
- {
- pMixer->cSinks = 0;
- RTListInit(&pMixer->lstSinks);
-
- pMixer->VolMaster.fMuted = false;
- pMixer->VolMaster.uLeft = UINT32_MAX;
- pMixer->VolMaster.uRight = UINT32_MAX;
-
- LogFlowFunc(("Created %p ...\n", pMixer));
-
- *ppMixer = pMixer;
- }
- else
- RTMemFree(pMixer);
- }
- else
- rc = VERR_NO_MEMORY;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-void AudioMixerDestroy(PAUDIOMIXER pMixer)
-{
- if (!pMixer)
- return;
-
- LogFlowFunc(("Destroying %s ...\n", pMixer->pszName));
-
- PAUDMIXSINK pSink, pSinkNext;
- RTListForEachSafe(&pMixer->lstSinks, pSink, pSinkNext, AUDMIXSINK, Node)
- AudioMixerRemoveSink(pMixer, pSink);
-
- Assert(pMixer->cSinks == 0);
-
- if (pMixer->pszName)
- {
- RTStrFree(pMixer->pszName);
- pMixer->pszName = NULL;
- }
-
- RTMemFree(pMixer);
-}
-
-static void audioMixerDestroySink(PAUDMIXSINK pSink)
-{
- AssertPtrReturnVoid(pSink);
- if (!pSink)
- return;
-
- if (pSink->pszName)
- RTStrFree(pSink->pszName);
-
- RTMemFree(pSink);
-}
-
-static void audioMixerDestroyStream(PAUDMIXSTREAM pStream)
-{
- AssertPtrReturnVoid(pStream);
- if (!pStream)
- return;
-
- RTMemFree(pStream);
-}
-
-int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- /** @todo Perform a deep copy, if needed. */
- *pCfg = pMixer->devFmt;
-
- return VINF_SUCCESS;
-}
-
-uint32_t AudioMixerGetStreamCount(PAUDIOMIXER pMixer)
-{
- AssertPtrReturn(pMixer, 0);
-
- uint32_t cStreams = 0;
-
- PAUDMIXSINK pSink;
- RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
- cStreams += pSink->cStreams;
-
- return cStreams;
-}
-
-void AudioMixerInvalidate(PAUDIOMIXER pMixer)
-{
- AssertPtrReturnVoid(pMixer);
-
- LogFlowFunc(("%s: Invalidating ...\n", pMixer->pszName));
-
- /* Propagate new master volume to all connected sinks. */
- PAUDMIXSINK pSink;
- RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
- {
- int rc2 = audioMixerUpdateSinkVolume(pSink, &pMixer->VolMaster);
- AssertRC(rc2);
- }
-}
-
-int AudioMixerProcessSinkIn(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed)
-{
- RT_NOREF(enmOp);
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
- /* pcbProcessed is optional. */
-
- /** @todo Handle mixing operation enmOp! */
-
- uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbBuf);
- if (!pvMixBuf)
- return VERR_NO_MEMORY;
-
- int rc = VERR_NOT_FOUND;
- uint32_t cbProcessed = 0;
-
- LogFlowFunc(("%s: pvBuf=%p, cbBuf=%zu\n", pSink->pszName, pvBuf, cbBuf));
-
- PAUDMIXSTREAM pStream;
- RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
- {
- /** @todo Support output sinks as well! */
- if (!pStream->pConn->pfnIsActiveIn(pStream->pConn, pStream->pIn))
- continue;
-
- uint32_t cbTotalRead = 0;
- uint32_t cbToRead = cbBuf;
-
- while (cbToRead)
- {
- uint32_t cbRead;
- AssertPtr(pStream->pConn);
- rc = pStream->pConn->pfnRead(pStream->pConn, pStream->pIn,
- (uint8_t *)pvMixBuf + cbTotalRead, cbToRead, &cbRead);
- if ( RT_FAILURE(rc)
- || !cbRead)
- break;
-
- AssertBreakStmt(cbRead <= cbToRead, rc = VERR_BUFFER_OVERFLOW);
- cbToRead -= cbRead;
- cbTotalRead += cbRead;
- }
-
- if (RT_FAILURE(rc))
- continue;
-
- cbProcessed = RT_MAX(cbProcessed, cbTotalRead);
- }
-
- if (RT_SUCCESS(rc))
- {
- memcpy(pvBuf, pvMixBuf, cbProcessed); /* @todo Use an intermediate mixing buffer per sink! */
-
- if (pcbProcessed)
- *pcbProcessed = cbProcessed;
- }
-
- RTMemFree(pvMixBuf);
-
- LogFlowFunc(("cbProcessed=%RU32, rc=%Rrc\n", cbProcessed, rc));
- return rc;
-}
-
-int AudioMixerProcessSinkOut(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed)
-{
- RT_NOREF(pSink, enmOp, pvBuf, cbBuf, pcbProcessed);
- return VERR_NOT_IMPLEMENTED;
-}
-
-void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink)
-{
- AssertPtrReturnVoid(pMixer);
- if (!pSink)
- return;
-
- PAUDMIXSTREAM pStream, pStreamNext;
- RTListForEachSafe(&pSink->lstStreams, pStream, pStreamNext, AUDMIXSTREAM, Node)
- AudioMixerRemoveStream(pSink, pStream);
-
- Assert(pSink->cStreams == 0);
-
- RTListNodeRemove(&pSink->Node);
- Assert(pMixer->cSinks);
- pMixer->cSinks--;
-
- LogFlowFunc(("%s: pSink=%s, cSinks=%RU8\n",
- pMixer->pszName, pSink->pszName, pMixer->cSinks));
-
- audioMixerDestroySink(pSink);
-}
-
-void AudioMixerRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream)
-{
- AssertPtrReturnVoid(pSink);
- if (!pStream)
- return;
-
- Assert(pSink->cStreams);
- RTListNodeRemove(&pStream->Node);
- pSink->cStreams--;
-
-#ifdef DEBUG
- const char *pszStream = pSink->enmDir == AUDMIXSINKDIR_INPUT
- ? pStream->pIn->MixBuf.pszName : pStream->pOut->MixBuf.pszName;
-
- LogFlowFunc(("%s: pStream=%s, cStreams=%RU8\n",
- pSink->pszName, pszStream ? pszStream : "<Unnamed>", pSink->cStreams));
-#endif
-
- /* Decrease the reference count again. */
- switch (pSink->enmDir)
- {
- case AUDMIXSINKDIR_INPUT:
- {
- Assert(pStream->pIn->State.cRefs);
- pStream->pIn->State.cRefs--;
- break;
- }
-
- case AUDMIXSINKDIR_OUTPUT:
- {
- Assert(pStream->pOut->State.cRefs);
- pStream->pOut->State.cRefs--;
- break;
- }
-
- default:
- AssertMsgFailed(("Not implemented\n"));
- break;
- }
-
- audioMixerDestroyStream(pStream);
-}
-
-int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- /** @todo Perform a deep copy, if needed. */
- pMixer->devFmt = *pCfg;
-
- return VINF_SUCCESS;
-}
-
-static int audioMixerUpdateSinkVolume(PAUDMIXSINK pSink, const PPDMAUDIOVOLUME pVolMaster)
-{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pVolMaster, VERR_INVALID_POINTER);
-
- LogFlowFunc(("Master fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
- pVolMaster->fMuted, pVolMaster->uLeft, pVolMaster->uRight));
- LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
- pSink->pszName, pSink->Volume.fMuted, pSink->Volume.uLeft, pSink->Volume.uRight));
-
- /** @todo Very crude implementation for now -- needs more work! */
-
- PDMAUDIOVOLUME volSink;
- volSink.fMuted = pVolMaster->fMuted || pSink->Volume.fMuted;
- volSink.uLeft = (pSink->Volume.uLeft * pVolMaster->uLeft) / UINT8_MAX;
- volSink.uRight = (pSink->Volume.uRight * pVolMaster->uRight) / UINT8_MAX;
-
- LogFlowFunc(("\t-> fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
- volSink.fMuted, volSink.uLeft, volSink.uRight));
-
- bool fOut = pSink->enmDir == AUDMIXSINKDIR_OUTPUT;
-
- /* Propagate new sink volume to all streams in the sink. */
- PAUDMIXSTREAM pStream;
- RTListForEach(&pSink->lstStreams, pStream, AUDMIXSTREAM, Node)
- {
- if (fOut)
- AudioMixBufSetVolume(&pStream->pOut->MixBuf, &volSink);
- else
- AudioMixBufSetVolume(&pStream->pIn->MixBuf, &volSink);
- }
-
- return VINF_SUCCESS;
-}
-
-/** Set the master volume of the mixer. */
-int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol)
-{
- AssertPtrReturn(pMixer, VERR_INVALID_POINTER);
- AssertPtrReturn(pVol, VERR_INVALID_POINTER);
-
- pMixer->VolMaster = *pVol;
-
- LogFlowFunc(("%s: lVol=%RU32, rVol=%RU32 => fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n",
- pMixer->pszName, pVol->uLeft, pVol->uRight,
- pMixer->VolMaster.fMuted, pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight));
-
- AudioMixerInvalidate(pMixer);
- return VINF_SUCCESS;
-}
-
-/** Set the volume of an individual sink. */
-int AudioMixerSetSinkVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol)
-{
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- AssertPtrReturn(pVol, VERR_INVALID_POINTER);
- AssertPtr(pSink->pParent);
-
- LogFlowFunc(("%s: fMuted=%RTbool, lVol=%RU32, rVol=%RU32\n", pSink->pszName, pVol->fMuted, pVol->uLeft, pVol->uRight));
-
- pSink->Volume = *pVol;
-
- return audioMixerUpdateSinkVolume(pSink, &pSink->pParent->VolMaster);
-}
-
-void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- RT_NOREF(pszArgs);
- PAUDMIXSINK pSink;
- unsigned iSink = 0;
-
- pHlp->pfnPrintf(pHlp, "[Master] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", pMixer->pszName,
- pMixer->VolMaster.uLeft, pMixer->VolMaster.uRight, pMixer->VolMaster.fMuted);
-
- RTListForEach(&pMixer->lstSinks, pSink, AUDMIXSINK, Node)
- {
- pHlp->pfnPrintf(pHlp, "[Sink %u] %s: lVol=%u, rVol=%u, fMuted=%RTbool\n", iSink, pSink->pszName,
- pSink->Volume.uLeft, pSink->Volume.uRight, pSink->Volume.fMuted);
- ++iSink;
- }
-}
diff --git a/src/VBox/Devices/Audio_50/AudioMixer.h b/src/VBox/Devices/Audio_50/AudioMixer.h
deleted file mode 100644
index e22f475..0000000
--- a/src/VBox/Devices/Audio_50/AudioMixer.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* $Id: AudioMixer.h $ */
-/** @file
- * VBox audio: Mixing routines, mainly used by the various audio device
- * emulations to achieve proper multiplexing from/to attached
- * devices LUNs.
- */
-
-/*
- * Copyright (C) 2014-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef AUDIO_MIXER_H
-#define AUDIO_MIXER_H
-
-#include <iprt/cdefs.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
-typedef struct AUDIOMIXER
-{
- /** Mixer name. */
- char *pszName;
- /** Format the mixer should convert/output
- * data to so that the underlying device emulation
- * can work with it. */
- PDMAUDIOSTREAMCFG devFmt;
- /** The master volume of this mixer. */
- PDMAUDIOVOLUME VolMaster;
- /* List of audio mixer sinks. */
- RTLISTANCHOR lstSinks;
- /** Number of used audio sinks. */
- uint8_t cSinks;
-} AUDIOMIXER, *PAUDIOMIXER;
-
-typedef struct AUDMIXSTREAM
-{
- RTLISTNODE Node;
- PPDMIAUDIOCONNECTOR pConn;
- union
- {
- PPDMAUDIOGSTSTRMIN pIn;
- PPDMAUDIOGSTSTRMOUT pOut;
- };
-} AUDMIXSTREAM, *PAUDMIXSTREAM;
-
-typedef enum AUDMIXSINKDIR
-{
- AUDMIXSINKDIR_UNKNOWN = 0,
- AUDMIXSINKDIR_INPUT,
- AUDMIXSINKDIR_OUTPUT,
- /** The usual 32-bit hack. */
- AUDMIXSINKDIR_32BIT_HACK = 0x7fffffff
-} AUDMIXSINKDIR;
-
-typedef struct AUDMIXSINK
-{
- RTLISTNODE Node;
- /** Name of this sink. */
- char *pszName;
- /** The sink direction, that is,
- * if this sink handles input or output. */
- AUDMIXSINKDIR enmDir;
- /** Pointer to mixer object this sink is bound
- * to. */
- PAUDIOMIXER pParent;
- /** Number of streams assigned. */
- uint8_t cStreams;
- /** List of assigned streams. */
- RTLISTANCHOR lstStreams;
- /** This sink's mixing buffer. */
- PDMAUDIOMIXBUF MixBuf;
- /** The volume of this sink. The volume always will
- * be combined with the mixer's master volume. */
- PDMAUDIOVOLUME Volume;
-} AUDMIXSINK, *PAUDMIXSINK;
-
-typedef enum AUDMIXOP
-{
- AUDMIXOP_NONE = 0,
- AUDMIXOP_COPY,
- AUDMIXOP_BLEND,
- /** The usual 32-bit hack. */
- AUDMIXOP_32BIT_HACK = 0x7fffffff
-} AUDMIXOP;
-
-
-int AudioMixerAddSink(PAUDIOMIXER pMixer, const char *pszName, AUDMIXSINKDIR enmDir, PAUDMIXSINK *ppSink);
-int AudioMixerAddStreamIn(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMIN pStream, uint32_t uFlags, PAUDMIXSTREAM *ppStream);
-int AudioMixerAddStreamOut(PAUDMIXSINK pSink, PPDMIAUDIOCONNECTOR pConnector, PPDMAUDIOGSTSTRMOUT pStream, uint32_t uFlags, PAUDMIXSTREAM *ppStream);
-int AudioMixerControlStream(AUDMIXSTREAM pHandle); /** @todo Implement me. */
-int AudioMixerCreate(const char *pszName, uint32_t uFlags, PAUDIOMIXER *ppMixer);
-void AudioMixerDestroy(PAUDIOMIXER pMixer);
-int AudioMixerGetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg);
-uint32_t AudioMixerGetStreamCount(PAUDIOMIXER pMixer);
-void AudioMixerInvalidate(PAUDIOMIXER pMixer);
-int AudioMixerProcessSinkIn(PAUDMIXSINK pSink, AUDMIXOP enmOp, void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed);
-int AudioMixerProcessSinkOut(PAUDMIXSINK pSink, AUDMIXOP enmOp, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbProcessed);
-void AudioMixerRemoveSink(PAUDIOMIXER pMixer, PAUDMIXSINK pSink);
-void AudioMixerRemoveStream(PAUDMIXSINK pSink, PAUDMIXSTREAM pStream);
-int AudioMixerSetDeviceFormat(PAUDIOMIXER pMixer, PPDMAUDIOSTREAMCFG pCfg);
-int AudioMixerSetMasterVolume(PAUDIOMIXER pMixer, PPDMAUDIOVOLUME pVol);
-int AudioMixerSetSinkVolume(PAUDMIXSINK pSink, PPDMAUDIOVOLUME pVol);
-void AudioMixerDebug(PAUDIOMIXER pMixer, PCDBGFINFOHLP pHlp, const char *pszArgs);
-
-#endif /* AUDIO_MIXER_H */
-
diff --git a/src/VBox/Devices/Audio_50/DevHDA.cpp b/src/VBox/Devices/Audio_50/DevHDA.cpp
deleted file mode 100644
index 2c619d6..0000000
--- a/src/VBox/Devices/Audio_50/DevHDA.cpp
+++ /dev/null
@@ -1,5139 +0,0 @@
-/* $Id: DevHDA.cpp $ */
-/** @file
- * DevIchHda - VBox ICH Intel HD Audio Controller.
- *
- * Implemented against the specifications found in "High Definition Audio
- * Specification", Revision 1.0a June 17, 2010, and "Intel I/O Controller
- * HUB 6 (ICH6) Family, Datasheet", document number 301473-002.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DEV_HDA
-#include <VBox/log.h>
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/vmm/pdmaudioifs.h>
-#include <VBox/version.h>
-
-#include <iprt/assert.h>
-#include <iprt/asm.h>
-#include <iprt/asm-math.h>
-#include <iprt/list.h>
-#ifdef IN_RING3
-# include <iprt/mem.h>
-# include <iprt/semaphore.h>
-# include <iprt/string.h>
-# include <iprt/uuid.h>
-#endif
-
-#include "VBoxDD.h"
-
-#include "AudioMixBuffer.h"
-#include "AudioMixer.h"
-#include "DevIchHdaCodec.h"
-#include "DrvAudio.h"
-
-
-/*********************************************************************************************************************************
-* Defined Constants And Macros *
-*********************************************************************************************************************************/
-//#define HDA_AS_PCI_EXPRESS
-#define VBOX_WITH_INTEL_HDA
-
-#ifdef DEBUG_andy
-/* Enables experimental support for separate mic-in handling.
- Do not enable this yet for regular builds, as this needs more testing first! */
-//# define VBOX_WITH_HDA_MIC_IN
-#endif
-
-#if defined(VBOX_WITH_HP_HDA)
-/* HP Pavilion dv4t-1300 */
-# define HDA_PCI_VENDOR_ID 0x103c
-# define HDA_PCI_DEVICE_ID 0x30f7
-#elif defined(VBOX_WITH_INTEL_HDA)
-/* Intel HDA controller */
-# define HDA_PCI_VENDOR_ID 0x8086
-# define HDA_PCI_DEVICE_ID 0x2668
-#elif defined(VBOX_WITH_NVIDIA_HDA)
-/* nVidia HDA controller */
-# define HDA_PCI_VENDOR_ID 0x10de
-# define HDA_PCI_DEVICE_ID 0x0ac0
-#else
-# error "Please specify your HDA device vendor/device IDs"
-#endif
-
-/** @todo r=bird: Looking at what the linux driver (accidentally?) does when
- * updating CORBWP, I belive that the ICH6 datahsheet is wrong and that CORBRP
- * is read only except for bit 15 like the HDA spec states.
- *
- * Btw. the CORBRPRST implementation is incomplete according to both docs (sw
- * writes 1, hw sets it to 1 (after completion), sw reads 1, sw writes 0). */
-#define BIRD_THINKS_CORBRP_IS_MOSTLY_RO
-
-#define HDA_NREGS 114
-#define HDA_NREGS_SAVED 112
-
-/**
- * NB: Register values stored in memory (au32Regs[]) are indexed through
- * the HDA_RMX_xxx macros (also HDA_MEM_IND_NAME()). On the other hand, the
- * register descriptors in g_aHdaRegMap[] are indexed through the
- * HDA_REG_xxx macros (also HDA_REG_IND_NAME()).
- *
- * The au32Regs[] layout is kept unchanged for saved state
- * compatibility. */
-
-/* Registers */
-#define HDA_REG_IND_NAME(x) HDA_REG_##x
-#define HDA_MEM_IND_NAME(x) HDA_RMX_##x
-#define HDA_REG_FIELD_MASK(reg, x) HDA_##reg##_##x##_MASK
-#define HDA_REG_FIELD_FLAG_MASK(reg, x) RT_BIT(HDA_##reg##_##x##_SHIFT)
-#define HDA_REG_FIELD_SHIFT(reg, x) HDA_##reg##_##x##_SHIFT
-#define HDA_REG_IND(pThis, x) ((pThis)->au32Regs[g_aHdaRegMap[x].mem_idx])
-#define HDA_REG(pThis, x) (HDA_REG_IND((pThis), HDA_REG_IND_NAME(x)))
-#define HDA_REG_FLAG_VALUE(pThis, reg, val) (HDA_REG((pThis),reg) & (((HDA_REG_FIELD_FLAG_MASK(reg, val)))))
-
-
-#define HDA_REG_GCAP 0 /* range 0x00-0x01*/
-#define HDA_RMX_GCAP 0
-/* GCAP HDASpec 3.3.2 This macro encodes the following information about HDA in a compact manner:
- * oss (15:12) - number of output streams supported
- * iss (11:8) - number of input streams supported
- * bss (7:3) - number of bidirectional streams supported
- * bds (2:1) - number of serial data out signals supported
- * b64sup (0) - 64 bit addressing supported.
- */
-#define HDA_MAKE_GCAP(oss, iss, bss, bds, b64sup) \
- ( (((oss) & 0xF) << 12) \
- | (((iss) & 0xF) << 8) \
- | (((bss) & 0x1F) << 3) \
- | (((bds) & 0x3) << 2) \
- | ((b64sup) & 1))
-
-#define HDA_REG_VMIN 1 /* 0x02 */
-#define HDA_RMX_VMIN 1
-
-#define HDA_REG_VMAJ 2 /* 0x03 */
-#define HDA_RMX_VMAJ 2
-
-#define HDA_REG_OUTPAY 3 /* 0x04-0x05 */
-#define HDA_RMX_OUTPAY 3
-
-#define HDA_REG_INPAY 4 /* 0x06-0x07 */
-#define HDA_RMX_INPAY 4
-
-#define HDA_REG_GCTL 5 /* 0x08-0x0B */
-#define HDA_RMX_GCTL 5
-#define HDA_GCTL_RST_SHIFT 0
-#define HDA_GCTL_FSH_SHIFT 1
-#define HDA_GCTL_UR_SHIFT 8
-
-#define HDA_REG_WAKEEN 6 /* 0x0C */
-#define HDA_RMX_WAKEEN 6
-
-#define HDA_REG_STATESTS 7 /* 0x0E */
-#define HDA_RMX_STATESTS 7
-#define HDA_STATES_SCSF 0x7
-
-#define HDA_REG_GSTS 8 /* 0x10-0x11*/
-#define HDA_RMX_GSTS 8
-#define HDA_GSTS_FSH_SHIFT 1
-
-#define HDA_REG_OUTSTRMPAY 9 /* 0x18 */
-#define HDA_RMX_OUTSTRMPAY 112
-
-#define HDA_REG_INSTRMPAY 10 /* 0x1a */
-#define HDA_RMX_INSTRMPAY 113
-
-#define HDA_REG_INTCTL 11 /* 0x20 */
-#define HDA_RMX_INTCTL 9
-#define HDA_INTCTL_GIE_SHIFT 31
-#define HDA_INTCTL_CIE_SHIFT 30
-#define HDA_INTCTL_S0_SHIFT 0
-#define HDA_INTCTL_S1_SHIFT 1
-#define HDA_INTCTL_S2_SHIFT 2
-#define HDA_INTCTL_S3_SHIFT 3
-#define HDA_INTCTL_S4_SHIFT 4
-#define HDA_INTCTL_S5_SHIFT 5
-#define HDA_INTCTL_S6_SHIFT 6
-#define HDA_INTCTL_S7_SHIFT 7
-#define INTCTL_SX(pThis, X) (HDA_REG_FLAG_VALUE((pThis), INTCTL, S##X))
-
-#define HDA_REG_INTSTS 12 /* 0x24 */
-#define HDA_RMX_INTSTS 10
-#define HDA_INTSTS_GIS_SHIFT 31
-#define HDA_INTSTS_CIS_SHIFT 30
-#define HDA_INTSTS_S0_SHIFT 0
-#define HDA_INTSTS_S1_SHIFT 1
-#define HDA_INTSTS_S2_SHIFT 2
-#define HDA_INTSTS_S3_SHIFT 3
-#define HDA_INTSTS_S4_SHIFT 4
-#define HDA_INTSTS_S5_SHIFT 5
-#define HDA_INTSTS_S6_SHIFT 6
-#define HDA_INTSTS_S7_SHIFT 7
-#define HDA_INTSTS_S_MASK(num) RT_BIT(HDA_REG_FIELD_SHIFT(S##num))
-
-#define HDA_REG_WALCLK 13 /* 0x24 */
-#define HDA_RMX_WALCLK /* Not defined! */
-
-/* Note: The HDA specification defines a SSYNC register at offset 0x38. The
- * ICH6/ICH9 datahseet defines SSYNC at offset 0x34. The Linux HDA driver matches
- * the datasheet.
- */
-#define HDA_REG_SSYNC 14 /* 0x34 */
-#define HDA_RMX_SSYNC 12
-
-#define HDA_REG_CORBLBASE 15 /* 0x40 */
-#define HDA_RMX_CORBLBASE 13
-
-#define HDA_REG_CORBUBASE 16 /* 0x44 */
-#define HDA_RMX_CORBUBASE 14
-
-#define HDA_REG_CORBWP 17 /* 0x48 */
-#define HDA_RMX_CORBWP 15
-
-#define HDA_REG_CORBRP 18 /* 0x4A */
-#define HDA_RMX_CORBRP 16
-#define HDA_CORBRP_RST_SHIFT 15
-#define HDA_CORBRP_WP_SHIFT 0
-#define HDA_CORBRP_WP_MASK 0xFF
-
-#define HDA_REG_CORBCTL 19 /* 0x4C */
-#define HDA_RMX_CORBCTL 17
-#define HDA_CORBCTL_DMA_SHIFT 1
-#define HDA_CORBCTL_CMEIE_SHIFT 0
-
-#define HDA_REG_CORBSTS 20 /* 0x4D */
-#define HDA_RMX_CORBSTS 18
-#define HDA_CORBSTS_CMEI_SHIFT 0
-
-#define HDA_REG_CORBSIZE 21 /* 0x4E */
-#define HDA_RMX_CORBSIZE 19
-#define HDA_CORBSIZE_SZ_CAP 0xF0
-#define HDA_CORBSIZE_SZ 0x3
-/* till ich 10 sizes of CORB and RIRB are hardcoded to 256 in real hw */
-
-#define HDA_REG_RIRBLBASE 22 /* 0x50 */
-#define HDA_RMX_RIRBLBASE 20
-
-#define HDA_REG_RIRBUBASE 23 /* 0x54 */
-#define HDA_RMX_RIRBUBASE 21
-
-#define HDA_REG_RIRBWP 24 /* 0x58 */
-#define HDA_RMX_RIRBWP 22
-#define HDA_RIRBWP_RST_SHIFT 15
-#define HDA_RIRBWP_WP_MASK 0xFF
-
-#define HDA_REG_RINTCNT 25 /* 0x5A */
-#define HDA_RMX_RINTCNT 23
-#define RINTCNT_N(pThis) (HDA_REG(pThis, RINTCNT) & 0xff)
-
-#define HDA_REG_RIRBCTL 26 /* 0x5C */
-#define HDA_RMX_RIRBCTL 24
-#define HDA_RIRBCTL_RIC_SHIFT 0
-#define HDA_RIRBCTL_DMA_SHIFT 1
-#define HDA_ROI_DMA_SHIFT 2
-
-#define HDA_REG_RIRBSTS 27 /* 0x5D */
-#define HDA_RMX_RIRBSTS 25
-#define HDA_RIRBSTS_RINTFL_SHIFT 0
-#define HDA_RIRBSTS_RIRBOIS_SHIFT 2
-
-#define HDA_REG_RIRBSIZE 28 /* 0x5E */
-#define HDA_RMX_RIRBSIZE 26
-#define HDA_RIRBSIZE_SZ_CAP 0xF0
-#define HDA_RIRBSIZE_SZ 0x3
-
-#define RIRBSIZE_SZ(pThis) (HDA_REG(pThis, HDA_REG_RIRBSIZE) & HDA_RIRBSIZE_SZ)
-#define RIRBSIZE_SZ_CAP(pThis) (HDA_REG(pThis, HDA_REG_RIRBSIZE) & HDA_RIRBSIZE_SZ_CAP)
-
-
-#define HDA_REG_IC 29 /* 0x60 */
-#define HDA_RMX_IC 27
-
-#define HDA_REG_IR 30 /* 0x64 */
-#define HDA_RMX_IR 28
-
-#define HDA_REG_IRS 31 /* 0x68 */
-#define HDA_RMX_IRS 29
-#define HDA_IRS_ICB_SHIFT 0
-#define HDA_IRS_IRV_SHIFT 1
-
-#define HDA_REG_DPLBASE 32 /* 0x70 */
-#define HDA_RMX_DPLBASE 30
-#define DPLBASE(pThis) (HDA_REG((pThis), DPLBASE))
-
-#define HDA_REG_DPUBASE 33 /* 0x74 */
-#define HDA_RMX_DPUBASE 31
-#define DPUBASE(pThis) (HDA_REG((pThis), DPUBASE))
-
-#define DPBASE_ADDR_MASK (~(uint64_t)0x7f)
-
-#define HDA_STREAM_REG_DEF(name, num) (HDA_REG_SD##num##name)
-#define HDA_STREAM_RMX_DEF(name, num) (HDA_RMX_SD##num##name)
-/* Note: sdnum here _MUST_ be stream reg number [0,7]. */
-#define HDA_STREAM_REG(pThis, name, sdnum) (HDA_REG_IND((pThis), HDA_REG_SD0##name + (sdnum) * 10))
-
-#define HDA_SD_NUM_FROM_REG(pThis, func, reg) ((reg - HDA_STREAM_REG_DEF(func, 0)) / 10)
-
-#define HDA_REG_SD0CTL 34 /* 0x80 */
-#define HDA_REG_SD1CTL (HDA_STREAM_REG_DEF(CTL, 0) + 10) /* 0xA0 */
-#define HDA_REG_SD2CTL (HDA_STREAM_REG_DEF(CTL, 0) + 20) /* 0xC0 */
-#define HDA_REG_SD3CTL (HDA_STREAM_REG_DEF(CTL, 0) + 30) /* 0xE0 */
-#define HDA_REG_SD4CTL (HDA_STREAM_REG_DEF(CTL, 0) + 40) /* 0x100 */
-#define HDA_REG_SD5CTL (HDA_STREAM_REG_DEF(CTL, 0) + 50) /* 0x120 */
-#define HDA_REG_SD6CTL (HDA_STREAM_REG_DEF(CTL, 0) + 60) /* 0x140 */
-#define HDA_REG_SD7CTL (HDA_STREAM_REG_DEF(CTL, 0) + 70) /* 0x160 */
-#define HDA_RMX_SD0CTL 32
-#define HDA_RMX_SD1CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 10)
-#define HDA_RMX_SD2CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 20)
-#define HDA_RMX_SD3CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 30)
-#define HDA_RMX_SD4CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 40)
-#define HDA_RMX_SD5CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 50)
-#define HDA_RMX_SD6CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 60)
-#define HDA_RMX_SD7CTL (HDA_STREAM_RMX_DEF(CTL, 0) + 70)
-
-#define SD(func, num) SD##num##func
-
-#define HDA_SDCTL(pThis, num) HDA_REG((pThis), SD(CTL, num))
-#define HDA_SDCTL_NUM(pThis, num) ((HDA_SDCTL((pThis), num) & HDA_REG_FIELD_MASK(SDCTL,NUM)) >> HDA_REG_FIELD_SHIFT(SDCTL, NUM))
-#define HDA_SDCTL_NUM_MASK 0xF
-#define HDA_SDCTL_NUM_SHIFT 20
-#define HDA_SDCTL_DIR_SHIFT 19
-#define HDA_SDCTL_TP_SHIFT 18
-#define HDA_SDCTL_STRIPE_MASK 0x3
-#define HDA_SDCTL_STRIPE_SHIFT 16
-#define HDA_SDCTL_DEIE_SHIFT 4
-#define HDA_SDCTL_FEIE_SHIFT 3
-#define HDA_SDCTL_ICE_SHIFT 2
-#define HDA_SDCTL_RUN_SHIFT 1
-#define HDA_SDCTL_SRST_SHIFT 0
-
-#define HDA_REG_SD0STS 35 /* 0x83 */
-#define HDA_REG_SD1STS (HDA_STREAM_REG_DEF(STS, 0) + 10) /* 0xA3 */
-#define HDA_REG_SD2STS (HDA_STREAM_REG_DEF(STS, 0) + 20) /* 0xC3 */
-#define HDA_REG_SD3STS (HDA_STREAM_REG_DEF(STS, 0) + 30) /* 0xE3 */
-#define HDA_REG_SD4STS (HDA_STREAM_REG_DEF(STS, 0) + 40) /* 0x103 */
-#define HDA_REG_SD5STS (HDA_STREAM_REG_DEF(STS, 0) + 50) /* 0x123 */
-#define HDA_REG_SD6STS (HDA_STREAM_REG_DEF(STS, 0) + 60) /* 0x143 */
-#define HDA_REG_SD7STS (HDA_STREAM_REG_DEF(STS, 0) + 70) /* 0x163 */
-#define HDA_RMX_SD0STS 33
-#define HDA_RMX_SD1STS (HDA_STREAM_RMX_DEF(STS, 0) + 10)
-#define HDA_RMX_SD2STS (HDA_STREAM_RMX_DEF(STS, 0) + 20)
-#define HDA_RMX_SD3STS (HDA_STREAM_RMX_DEF(STS, 0) + 30)
-#define HDA_RMX_SD4STS (HDA_STREAM_RMX_DEF(STS, 0) + 40)
-#define HDA_RMX_SD5STS (HDA_STREAM_RMX_DEF(STS, 0) + 50)
-#define HDA_RMX_SD6STS (HDA_STREAM_RMX_DEF(STS, 0) + 60)
-#define HDA_RMX_SD7STS (HDA_STREAM_RMX_DEF(STS, 0) + 70)
-
-#define SDSTS(pThis, num) HDA_REG((pThis), SD(STS, num))
-#define HDA_SDSTS_FIFORDY_SHIFT 5
-#define HDA_SDSTS_DE_SHIFT 4
-#define HDA_SDSTS_FE_SHIFT 3
-#define HDA_SDSTS_BCIS_SHIFT 2
-
-#define HDA_REG_SD0LPIB 36 /* 0x84 */
-#define HDA_REG_SD1LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 10) /* 0xA4 */
-#define HDA_REG_SD2LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 20) /* 0xC4 */
-#define HDA_REG_SD3LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 30) /* 0xE4 */
-#define HDA_REG_SD4LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 40) /* 0x104 */
-#define HDA_REG_SD5LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 50) /* 0x124 */
-#define HDA_REG_SD6LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 60) /* 0x144 */
-#define HDA_REG_SD7LPIB (HDA_STREAM_REG_DEF(LPIB, 0) + 70) /* 0x164 */
-#define HDA_RMX_SD0LPIB 34
-#define HDA_RMX_SD1LPIB (HDA_STREAM_RMX_DEF(LPIB, 0) + 10)
-#define HDA_RMX_SD2LPIB (HDA_STREAM_RMX_DEF(LPIB, 0) + 20)
-#define HDA_RMX_SD3LPIB (HDA_STREAM_RMX_DEF(LPIB, 0) + 30)
-#define HDA_RMX_SD4LPIB (HDA_STREAM_RMX_DEF(LPIB, 0) + 40)
-#define HDA_RMX_SD5LPIB (HDA_STREAM_RMX_DEF(LPIB, 0) + 50)
-#define HDA_RMX_SD6LPIB (HDA_STREAM_RMX_DEF(LPIB, 0) + 60)
-#define HDA_RMX_SD7LPIB (HDA_STREAM_RMX_DEF(LPIB, 0) + 70)
-
-#define HDA_REG_SD0CBL 37 /* 0x88 */
-#define HDA_REG_SD1CBL (HDA_STREAM_REG_DEF(CBL, 0) + 10) /* 0xA8 */
-#define HDA_REG_SD2CBL (HDA_STREAM_REG_DEF(CBL, 0) + 20) /* 0xC8 */
-#define HDA_REG_SD3CBL (HDA_STREAM_REG_DEF(CBL, 0) + 30) /* 0xE8 */
-#define HDA_REG_SD4CBL (HDA_STREAM_REG_DEF(CBL, 0) + 40) /* 0x108 */
-#define HDA_REG_SD5CBL (HDA_STREAM_REG_DEF(CBL, 0) + 50) /* 0x128 */
-#define HDA_REG_SD6CBL (HDA_STREAM_REG_DEF(CBL, 0) + 60) /* 0x148 */
-#define HDA_REG_SD7CBL (HDA_STREAM_REG_DEF(CBL, 0) + 70) /* 0x168 */
-#define HDA_RMX_SD0CBL 35
-#define HDA_RMX_SD1CBL (HDA_STREAM_RMX_DEF(CBL, 0) + 10)
-#define HDA_RMX_SD2CBL (HDA_STREAM_RMX_DEF(CBL, 0) + 20)
-#define HDA_RMX_SD3CBL (HDA_STREAM_RMX_DEF(CBL, 0) + 30)
-#define HDA_RMX_SD4CBL (HDA_STREAM_RMX_DEF(CBL, 0) + 40)
-#define HDA_RMX_SD5CBL (HDA_STREAM_RMX_DEF(CBL, 0) + 50)
-#define HDA_RMX_SD6CBL (HDA_STREAM_RMX_DEF(CBL, 0) + 60)
-#define HDA_RMX_SD7CBL (HDA_STREAM_RMX_DEF(CBL, 0) + 70)
-
-#define HDA_REG_SD0LVI 38 /* 0x8C */
-#define HDA_REG_SD1LVI (HDA_STREAM_REG_DEF(LVI, 0) + 10) /* 0xAC */
-#define HDA_REG_SD2LVI (HDA_STREAM_REG_DEF(LVI, 0) + 20) /* 0xCC */
-#define HDA_REG_SD3LVI (HDA_STREAM_REG_DEF(LVI, 0) + 30) /* 0xEC */
-#define HDA_REG_SD4LVI (HDA_STREAM_REG_DEF(LVI, 0) + 40) /* 0x10C */
-#define HDA_REG_SD5LVI (HDA_STREAM_REG_DEF(LVI, 0) + 50) /* 0x12C */
-#define HDA_REG_SD6LVI (HDA_STREAM_REG_DEF(LVI, 0) + 60) /* 0x14C */
-#define HDA_REG_SD7LVI (HDA_STREAM_REG_DEF(LVI, 0) + 70) /* 0x16C */
-#define HDA_RMX_SD0LVI 36
-#define HDA_RMX_SD1LVI (HDA_STREAM_RMX_DEF(LVI, 0) + 10)
-#define HDA_RMX_SD2LVI (HDA_STREAM_RMX_DEF(LVI, 0) + 20)
-#define HDA_RMX_SD3LVI (HDA_STREAM_RMX_DEF(LVI, 0) + 30)
-#define HDA_RMX_SD4LVI (HDA_STREAM_RMX_DEF(LVI, 0) + 40)
-#define HDA_RMX_SD5LVI (HDA_STREAM_RMX_DEF(LVI, 0) + 50)
-#define HDA_RMX_SD6LVI (HDA_STREAM_RMX_DEF(LVI, 0) + 60)
-#define HDA_RMX_SD7LVI (HDA_STREAM_RMX_DEF(LVI, 0) + 70)
-
-#define HDA_REG_SD0FIFOW 39 /* 0x8E */
-#define HDA_REG_SD1FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 10) /* 0xAE */
-#define HDA_REG_SD2FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 20) /* 0xCE */
-#define HDA_REG_SD3FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 30) /* 0xEE */
-#define HDA_REG_SD4FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 40) /* 0x10E */
-#define HDA_REG_SD5FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 50) /* 0x12E */
-#define HDA_REG_SD6FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 60) /* 0x14E */
-#define HDA_REG_SD7FIFOW (HDA_STREAM_REG_DEF(FIFOW, 0) + 70) /* 0x16E */
-#define HDA_RMX_SD0FIFOW 37
-#define HDA_RMX_SD1FIFOW (HDA_STREAM_RMX_DEF(FIFOW, 0) + 10)
-#define HDA_RMX_SD2FIFOW (HDA_STREAM_RMX_DEF(FIFOW, 0) + 20)
-#define HDA_RMX_SD3FIFOW (HDA_STREAM_RMX_DEF(FIFOW, 0) + 30)
-#define HDA_RMX_SD4FIFOW (HDA_STREAM_RMX_DEF(FIFOW, 0) + 40)
-#define HDA_RMX_SD5FIFOW (HDA_STREAM_RMX_DEF(FIFOW, 0) + 50)
-#define HDA_RMX_SD6FIFOW (HDA_STREAM_RMX_DEF(FIFOW, 0) + 60)
-#define HDA_RMX_SD7FIFOW (HDA_STREAM_RMX_DEF(FIFOW, 0) + 70)
-
-/*
- * ICH6 datasheet defined limits for FIFOW values (18.2.38).
- */
-#define HDA_SDFIFOW_8B 0x2
-#define HDA_SDFIFOW_16B 0x3
-#define HDA_SDFIFOW_32B 0x4
-
-#define HDA_REG_SD0FIFOS 40 /* 0x90 */
-#define HDA_REG_SD1FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 10) /* 0xB0 */
-#define HDA_REG_SD2FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 20) /* 0xD0 */
-#define HDA_REG_SD3FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 30) /* 0xF0 */
-#define HDA_REG_SD4FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 40) /* 0x110 */
-#define HDA_REG_SD5FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 50) /* 0x130 */
-#define HDA_REG_SD6FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 60) /* 0x150 */
-#define HDA_REG_SD7FIFOS (HDA_STREAM_REG_DEF(FIFOS, 0) + 70) /* 0x170 */
-#define HDA_RMX_SD0FIFOS 38
-#define HDA_RMX_SD1FIFOS (HDA_STREAM_RMX_DEF(FIFOS, 0) + 10)
-#define HDA_RMX_SD2FIFOS (HDA_STREAM_RMX_DEF(FIFOS, 0) + 20)
-#define HDA_RMX_SD3FIFOS (HDA_STREAM_RMX_DEF(FIFOS, 0) + 30)
-#define HDA_RMX_SD4FIFOS (HDA_STREAM_RMX_DEF(FIFOS, 0) + 40)
-#define HDA_RMX_SD5FIFOS (HDA_STREAM_RMX_DEF(FIFOS, 0) + 50)
-#define HDA_RMX_SD6FIFOS (HDA_STREAM_RMX_DEF(FIFOS, 0) + 60)
-#define HDA_RMX_SD7FIFOS (HDA_STREAM_RMX_DEF(FIFOS, 0) + 70)
-
-/*
- * ICH6 datasheet defines limits for FIFOS registers (18.2.39)
- * formula: size - 1
- * Other values not listed are not supported.
- */
-#define HDA_SDINFIFO_120B 0x77 /* 8-, 16-, 20-, 24-, 32-bit Input Streams */
-#define HDA_SDINFIFO_160B 0x9F /* 20-, 24-bit Input Streams Streams */
-
-#define HDA_SDONFIFO_16B 0x0F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_32B 0x1F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_64B 0x3F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_128B 0x7F /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_192B 0xBF /* 8-, 16-, 20-, 24-, 32-bit Output Streams */
-#define HDA_SDONFIFO_256B 0xFF /* 20-, 24-bit Output Streams */
-#define SDFIFOS(pThis, num) HDA_REG((pThis), SD(FIFOS, num))
-
-#define HDA_REG_SD0FMT 41 /* 0x92 */
-#define HDA_REG_SD1FMT (HDA_STREAM_REG_DEF(FMT, 0) + 10) /* 0xB2 */
-#define HDA_REG_SD2FMT (HDA_STREAM_REG_DEF(FMT, 0) + 20) /* 0xD2 */
-#define HDA_REG_SD3FMT (HDA_STREAM_REG_DEF(FMT, 0) + 30) /* 0xF2 */
-#define HDA_REG_SD4FMT (HDA_STREAM_REG_DEF(FMT, 0) + 40) /* 0x112 */
-#define HDA_REG_SD5FMT (HDA_STREAM_REG_DEF(FMT, 0) + 50) /* 0x132 */
-#define HDA_REG_SD6FMT (HDA_STREAM_REG_DEF(FMT, 0) + 60) /* 0x152 */
-#define HDA_REG_SD7FMT (HDA_STREAM_REG_DEF(FMT, 0) + 70) /* 0x172 */
-#define HDA_RMX_SD0FMT 39
-#define HDA_RMX_SD1FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 10)
-#define HDA_RMX_SD2FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 20)
-#define HDA_RMX_SD3FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 30)
-#define HDA_RMX_SD4FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 40)
-#define HDA_RMX_SD5FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 50)
-#define HDA_RMX_SD6FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 60)
-#define HDA_RMX_SD7FMT (HDA_STREAM_RMX_DEF(FMT, 0) + 70)
-
-#define SDFMT(pThis, num) (HDA_REG((pThis), SD(FMT, num)))
-#define HDA_SDFMT_BASE_RATE_SHIFT 14
-#define HDA_SDFMT_MULT_SHIFT 11
-#define HDA_SDFMT_MULT_MASK 0x7
-#define HDA_SDFMT_DIV_SHIFT 8
-#define HDA_SDFMT_DIV_MASK 0x7
-#define HDA_SDFMT_BITS_SHIFT 4
-#define HDA_SDFMT_BITS_MASK 0x7
-#define SDFMT_BASE_RATE(pThis, num) ((SDFMT(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDFMT, BASE_RATE)) >> HDA_REG_FIELD_SHIFT(SDFMT, BASE_RATE))
-#define SDFMT_MULT(pThis, num) ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,MULT)) >> HDA_REG_FIELD_SHIFT(SDFMT, MULT))
-#define SDFMT_DIV(pThis, num) ((SDFMT((pThis), num) & HDA_REG_FIELD_MASK(SDFMT,DIV)) >> HDA_REG_FIELD_SHIFT(SDFMT, DIV))
-
-#define HDA_REG_SD0BDPL 42 /* 0x98 */
-#define HDA_REG_SD1BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 10) /* 0xB8 */
-#define HDA_REG_SD2BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 20) /* 0xD8 */
-#define HDA_REG_SD3BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 30) /* 0xF8 */
-#define HDA_REG_SD4BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 40) /* 0x118 */
-#define HDA_REG_SD5BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 50) /* 0x138 */
-#define HDA_REG_SD6BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 60) /* 0x158 */
-#define HDA_REG_SD7BDPL (HDA_STREAM_REG_DEF(BDPL, 0) + 70) /* 0x178 */
-#define HDA_RMX_SD0BDPL 40
-#define HDA_RMX_SD1BDPL (HDA_STREAM_RMX_DEF(BDPL, 0) + 10)
-#define HDA_RMX_SD2BDPL (HDA_STREAM_RMX_DEF(BDPL, 0) + 20)
-#define HDA_RMX_SD3BDPL (HDA_STREAM_RMX_DEF(BDPL, 0) + 30)
-#define HDA_RMX_SD4BDPL (HDA_STREAM_RMX_DEF(BDPL, 0) + 40)
-#define HDA_RMX_SD5BDPL (HDA_STREAM_RMX_DEF(BDPL, 0) + 50)
-#define HDA_RMX_SD6BDPL (HDA_STREAM_RMX_DEF(BDPL, 0) + 60)
-#define HDA_RMX_SD7BDPL (HDA_STREAM_RMX_DEF(BDPL, 0) + 70)
-
-#define HDA_REG_SD0BDPU 43 /* 0x9C */
-#define HDA_REG_SD1BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 10) /* 0xBC */
-#define HDA_REG_SD2BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 20) /* 0xDC */
-#define HDA_REG_SD3BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 30) /* 0xFC */
-#define HDA_REG_SD4BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 40) /* 0x11C */
-#define HDA_REG_SD5BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 50) /* 0x13C */
-#define HDA_REG_SD6BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 60) /* 0x15C */
-#define HDA_REG_SD7BDPU (HDA_STREAM_REG_DEF(BDPU, 0) + 70) /* 0x17C */
-#define HDA_RMX_SD0BDPU 41
-#define HDA_RMX_SD1BDPU (HDA_STREAM_RMX_DEF(BDPU, 0) + 10)
-#define HDA_RMX_SD2BDPU (HDA_STREAM_RMX_DEF(BDPU, 0) + 20)
-#define HDA_RMX_SD3BDPU (HDA_STREAM_RMX_DEF(BDPU, 0) + 30)
-#define HDA_RMX_SD4BDPU (HDA_STREAM_RMX_DEF(BDPU, 0) + 40)
-#define HDA_RMX_SD5BDPU (HDA_STREAM_RMX_DEF(BDPU, 0) + 50)
-#define HDA_RMX_SD6BDPU (HDA_STREAM_RMX_DEF(BDPU, 0) + 60)
-#define HDA_RMX_SD7BDPU (HDA_STREAM_RMX_DEF(BDPU, 0) + 70)
-
-#define HDA_CODEC_CAD_SHIFT 28
-/* Encodes the (required) LUN into a codec command. */
-#define HDA_CODEC_CMD(cmd, lun) ((cmd) | (lun << HDA_CODEC_CAD_SHIFT))
-
-
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
-
-/**
- * Internal state of a Buffer Descriptor List Entry (BDLE),
- * needed to keep track of the data needed for the actual device
- * emulation.
- */
-typedef struct HDABDLESTATE
-{
- /** Own index within the BDL (Buffer Descriptor List). */
- uint32_t u32BDLIndex;
- /** Number of bytes below the stream's FIFO watermark (SDFIFOW).
- * Used to check if we need fill up the FIFO again. */
- uint32_t cbBelowFIFOW;
- /** The buffer descriptor's internal DMA buffer. */
- uint8_t au8FIFO[HDA_SDONFIFO_256B + 1];
- /** Current offset in DMA buffer (in bytes).*/
- uint32_t u32BufOff;
- uint32_t Padding;
-} HDABDLESTATE, *PHDABDLESTATE;
-
-/**
- * Buffer Descriptor List Entry (BDLE) (3.6.3).
- *
- * Contains only register values which do *not* change until a
- * stream reset occurs.
- */
-typedef struct HDABDLE
-{
- /** Starting address of the actual buffer. Must be 128-bit aligned. */
- uint64_t u64BufAdr;
- /** Size of the actual buffer (in bytes). */
- uint32_t u32BufSize;
- /** Interrupt on completion; the controller will generate
- * an interrupt when the last byte of the buffer has been
- * fetched by the DMA engine. */
- bool fIntOnCompletion;
- /** Internal state of this BDLE.
- * Not part of the actual BDLE registers. */
- HDABDLESTATE State;
-} HDABDLE, *PHDABDLE;
-
-/**
- * Internal state of a HDA stream.
- */
-typedef struct HDASTREAMSTATE
-{
- /** Current BDLE to use. Wraps around to 0 if
- * maximum (cBDLE) is reached. */
- uint16_t uCurBDLE;
- /** Stop indicator. */
- volatile bool fDoStop;
- /** Flag indicating whether this stream is in an
- * active (operative) state or not. */
- volatile bool fActive;
- /** Flag indicating whether this stream currently is
- * in reset mode and therefore not acccessible by the guest. */
- volatile bool fInReset;
- /** Unused, padding. */
- bool fPadding;
- /** Event signalling that the stream's state has been changed. */
- RTSEMEVENT hStateChangedEvent;
- /** Current BDLE (Buffer Descriptor List Entry). */
- HDABDLE BDLE;
-} HDASTREAMSTATE, *PHDASTREAMSTATE;
-
-/**
- * Structure for keeping a HDA stream state.
- *
- * Contains only register values which do *not* change until a
- * stream reset occurs.
- */
-typedef struct HDASTREAM
-{
- /** Stream number (SDn). */
- uint8_t u8Strm;
- uint8_t Padding0[7];
- /** DMA base address (SDnBDPU - SDnBDPL). */
- uint64_t u64BDLBase;
- /** Cyclic Buffer Length (SDnCBL).
- * Represents the size of the ring buffer. */
- uint32_t u32CBL;
- /** Format (SDnFMT). */
- uint16_t u16FMT;
- /** FIFO Size (FIFOS).
- * Maximum number of bytes that may have been DMA'd into
- * memory but not yet transmitted on the link.
- *
- * Must be a power of two. */
- uint16_t u16FIFOS;
- /** Last Valid Index (SDnLVI). */
- uint16_t u16LVI;
- uint16_t Padding1[3];
- /** Internal state of this stream. */
- HDASTREAMSTATE State;
-} HDASTREAM, *PHDASTREAM;
-
-typedef struct HDAINPUTSTREAM
-{
- /** PCM line input stream. */
- R3PTRTYPE(PPDMAUDIOGSTSTRMIN) pStrmIn;
- /** Mixer handle for line input stream. */
- R3PTRTYPE(PAUDMIXSTREAM) phStrmIn;
-} HDAINPUTSTREAM, *PHDAINPUTSTREAM;
-
-typedef struct HDAOUTPUTSTREAM
-{
- /** PCM output stream. */
- R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
- /** Mixer handle for line output stream. */
- R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
-} HDAOUTPUTSTREAM, *PHDAOUTPUTSTREAM;
-
-/**
- * Struct for maintaining a host backend driver.
- * This driver must be associated to one, and only one,
- * HDA codec. The HDA controller does the actual multiplexing
- * of HDA codec data to various host backend drivers then.
- *
- * This HDA device uses a timer in order to synchronize all
- * read/write accesses across all attached LUNs / backends.
- */
-typedef struct HDADRIVER
-{
- /** Node for storing this driver in our device driver list of HDASTATE. */
- RTLISTNODER3 Node;
- /** Pointer to HDA controller (state). */
- R3PTRTYPE(PHDASTATE) pHDAState;
- /** Driver flags. */
- PDMAUDIODRVFLAGS Flags;
- uint8_t u32Padding0[2];
- /** LUN to which this driver has been assigned. */
- uint8_t uLUN;
- /** Whether this driver is in an attached state or not. */
- bool fAttached;
- /** Pointer to attached driver base interface. */
- R3PTRTYPE(PPDMIBASE) pDrvBase;
- /** Audio connector interface to the underlying host backend. */
- R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
- /** Stream for line input. */
- HDAINPUTSTREAM LineIn;
- /** Stream for mic input. */
- HDAINPUTSTREAM MicIn;
- /** Stream for output. */
- HDAOUTPUTSTREAM Out;
-} HDADRIVER;
-
-/**
- * ICH Intel HD Audio Controller state.
- */
-typedef struct HDASTATE
-{
- /** The PCI device structure. */
- PDMPCIDEV PciDev;
- /** R3 Pointer to the device instance. */
- PPDMDEVINSR3 pDevInsR3;
- /** R0 Pointer to the device instance. */
- PPDMDEVINSR0 pDevInsR0;
- /** R0 Pointer to the device instance. */
- PPDMDEVINSRC pDevInsRC;
- /** Padding for alignment. */
- uint32_t u32Padding;
- /** The base interface for LUN\#0. */
- PDMIBASE IBase;
- RTGCPHYS MMIOBaseAddr;
- /** The HDA's register set. */
- uint32_t au32Regs[HDA_NREGS];
- /** Stream state for line-in. */
- HDASTREAM StrmStLineIn;
- /** Stream state for microphone-in. */
- HDASTREAM StrmStMicIn;
- /** Stream state for output. */
- HDASTREAM StrmStOut;
- /** CORB buffer base address. */
- uint64_t u64CORBBase;
- /** RIRB buffer base address. */
- uint64_t u64RIRBBase;
- /** DMA base address.
- * Made out of DPLBASE + DPUBASE (3.3.32 + 3.3.33). */
- uint64_t u64DPBase;
- /** DMA position buffer enable bit. */
- bool fDMAPosition;
- /** Padding for alignment. */
- uint8_t u32Padding0[7];
- /** Pointer to CORB buffer. */
- R3PTRTYPE(uint32_t *) pu32CorbBuf;
- /** Size in bytes of CORB buffer. */
- uint32_t cbCorbBuf;
- /** Padding for alignment. */
- uint32_t u32Padding1;
- /** Pointer to RIRB buffer. */
- R3PTRTYPE(uint64_t *) pu64RirbBuf;
- /** Size in bytes of RIRB buffer. */
- uint32_t cbRirbBuf;
- /** Indicates if HDA is in reset. */
- bool fInReset;
- /** Flag whether the R0 part is enabled. */
- bool fR0Enabled;
- /** Flag whether the RC part is enabled. */
- bool fRCEnabled;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- /** The timer for pumping data thru the attached LUN drivers. */
- PTMTIMERR3 pTimer;
- /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
- uint64_t cTimerTicks;
- /** Timestamp of the last timer callback (hdaTimer).
- * Used to calculate the time actually elapsed between two timer callbacks. */
- uint64_t uTimerTS;
-#endif
-#ifdef VBOX_WITH_STATISTICS
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- STAMPROFILE StatTimer;
-# endif
- STAMCOUNTER StatBytesRead;
- STAMCOUNTER StatBytesWritten;
-#endif
- /** Pointer to HDA codec to use. */
- R3PTRTYPE(PHDACODEC) pCodec;
- /** List of associated LUN drivers (HDADRIVER). */
- RTLISTANCHORR3 lstDrv;
- /** The device' software mixer. */
- R3PTRTYPE(PAUDIOMIXER) pMixer;
- /** Audio sink for PCM output. */
- R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
- /** Audio mixer sink for line input. */
- R3PTRTYPE(PAUDMIXSINK) pSinkLineIn;
- /** Audio mixer sink for microphone input. */
- R3PTRTYPE(PAUDMIXSINK) pSinkMicIn;
- uint64_t u64BaseTS;
- /** Response Interrupt Count (RINTCNT). */
- uint8_t u8RespIntCnt;
- /** Padding for alignment. */
- uint8_t au8Padding2[7];
-} HDASTATE;
-/** Pointer to the ICH Intel HD Audio Controller state. */
-typedef HDASTATE *PHDASTATE;
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
-typedef struct HDACALLBACKCTX
-{
- PHDASTATE pThis;
- PHDADRIVER pDriver;
-} HDACALLBACKCTX, *PHDACALLBACKCTX;
-#endif
-
-/*********************************************************************************************************************************
-* Internal Functions *
-*********************************************************************************************************************************/
-#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-# ifdef IN_RING3
-static FNPDMDEVRESET hdaReset;
-#endif
-
-/*
- * Stubs.
- */
-static int hdaRegReadUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-
-/*
- * Global register set read/write functions.
- */
-static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegReadLPIB(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-
-/*
- * {IOB}SDn read/write functions.
- */
-static int hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-static int hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-inline bool hdaRegWriteSDIsAllowed(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
-
-/*
- * Generic register read/write functions.
- */
-static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-static int hdaRegReadU16(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
-static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t pu32Value);
-
-#ifdef IN_RING3
-static void hdaStreamDestroy(PHDASTREAM pStrmSt);
-//static int hdaStreamStart(PHDASTREAM pStrmSt);
-static int hdaStreamStop(PHDASTREAM pStrmSt);
-//static int hdaStreamWaitForStateChange(PHDASTREAM pStrmSt, RTMSINTERVAL msTimeout);
-static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbToProcess, uint32_t *pcbProcessed);
-#endif
-
-#ifdef IN_RING3
-static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry);
-DECLINLINE(void) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t u32LPIB);
-# ifdef LOG_ENABLED
-static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BaseDMA, uint16_t cBDLE);
-# endif
-#endif
-
-
-/*********************************************************************************************************************************
-* Global Variables *
-*********************************************************************************************************************************/
-
-/** Offset of the SD0 register map. */
-#define HDA_REG_DESC_SD0_BASE 0x80
-
-/** Turn a short global register name into an memory index and a stringized name. */
-#define HDA_REG_IDX(abbrev) HDA_MEM_IND_NAME(abbrev), #abbrev
-
-/** Turns a short stream register name into an memory index and a stringized name. */
-#define HDA_REG_IDX_STRM(reg, suff) HDA_MEM_IND_NAME(reg ## suff), #reg #suff
-
-/** Same as above for a register *not* stored in memory. */
-#define HDA_REG_IDX_LOCAL(abbrev) 0, #abbrev
-
-/** Emits a single audio stream register set (e.g. OSD0) at a specified offset. */
-#define HDA_REG_MAP_STRM(offset, name) \
- /* offset size read mask write mask read callback write callback index + abbrev description */ \
- /* ------- ------- ---------- ---------- -------------- ----------------- ------------------------------ ----------- */ \
- /* Offset 0x80 (SD0) */ \
- { offset, 0x00003, 0x00FF001F, 0x00F0001F, hdaRegReadU24 , hdaRegWriteSDCTL , HDA_REG_IDX_STRM(name, CTL) , #name " Stream Descriptor Control" }, \
- /* Offset 0x83 (SD0) */ \
- { offset + 0x3, 0x00001, 0x0000001C, 0x0000003C, hdaRegReadU8 , hdaRegWriteSDSTS , HDA_REG_IDX_STRM(name, STS) , #name " Status" }, \
- /* Offset 0x84 (SD0) */ \
- { offset + 0x4, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadLPIB, hdaRegWriteU32 , HDA_REG_IDX_STRM(name, LPIB) , #name " Link Position In Buffer" }, \
- /* Offset 0x88 (SD0) */ \
- { offset + 0x8, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32, hdaRegWriteSDCBL , HDA_REG_IDX_STRM(name, CBL) , #name " Cyclic Buffer Length" }, \
- /* Offset 0x8C (SD0) */ \
- { offset + 0xC, 0x00002, 0x0000FFFF, 0x0000FFFF, hdaRegReadU16, hdaRegWriteSDLVI , HDA_REG_IDX_STRM(name, LVI) , #name " Last Valid Index" }, \
- /* Reserved: FIFO Watermark. ** @todo Document this! */ \
- { offset + 0xE, 0x00002, 0x00000007, 0x00000007, hdaRegReadU16, hdaRegWriteSDFIFOW, HDA_REG_IDX_STRM(name, FIFOW), #name " FIFO Watermark" }, \
- /* Offset 0x90 (SD0) */ \
- { offset + 0x10, 0x00002, 0x000000FF, 0x00000000, hdaRegReadU16, hdaRegWriteSDFIFOS, HDA_REG_IDX_STRM(name, FIFOS), #name " FIFO Size" }, \
- /* Offset 0x92 (SD0) */ \
- { offset + 0x12, 0x00002, 0x00007F7F, 0x00007F7F, hdaRegReadU16, hdaRegWriteSDFMT , HDA_REG_IDX_STRM(name, FMT) , #name " Stream Format" }, \
- /* Reserved: 0x94 - 0x98. */ \
- /* Offset 0x98 (SD0) */ \
- { offset + 0x18, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32, hdaRegWriteSDBDPL , HDA_REG_IDX_STRM(name, BDPL) , #name " Buffer Descriptor List Pointer-Lower Base Address" }, \
- /* Offset 0x9C (SD0) */ \
- { offset + 0x1C, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32, hdaRegWriteSDBDPU , HDA_REG_IDX_STRM(name, BDPU) , #name " Buffer Descriptor List Pointer-Upper Base Address" }
-
-/** Defines a single audio stream register set (e.g. OSD0). */
-#define HDA_REG_MAP_DEF_STREAM(index, name) \
- HDA_REG_MAP_STRM(HDA_REG_DESC_SD0_BASE + (index * 32 /* 0x20 */), name)
-
-/* See 302349 p 6.2. */
-static const struct HDAREGDESC
-{
- /** Register offset in the register space. */
- uint32_t offset;
- /** Size in bytes. Registers of size > 4 are in fact tables. */
- uint32_t size;
- /** Readable bits. */
- uint32_t readable;
- /** Writable bits. */
- uint32_t writable;
- /** Read callback. */
- int (*pfnRead)(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value);
- /** Write callback. */
- int (*pfnWrite)(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value);
- /** Index into the register storage array. */
- uint32_t mem_idx;
- /** Abbreviated name. */
- const char *abbrev;
- /** Descripton. */
- const char *desc;
-} g_aHdaRegMap[HDA_NREGS] =
-
-{
- /* offset size read mask write mask read callback write callback index + abbrev */
- /*------- ------- ---------- ---------- ----------------------- ---------------------- ---------------- */
- { 0x00000, 0x00002, 0x0000FFFB, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(GCAP) }, /* Global Capabilities */
- { 0x00002, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimpl , HDA_REG_IDX(VMIN) }, /* Minor Version */
- { 0x00003, 0x00001, 0x000000FF, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimpl , HDA_REG_IDX(VMAJ) }, /* Major Version */
- { 0x00004, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(OUTPAY) }, /* Output Payload Capabilities */
- { 0x00006, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(INPAY) }, /* Input Payload Capabilities */
- { 0x00008, 0x00004, 0x00000103, 0x00000103, hdaRegReadU32 , hdaRegWriteGCTL , HDA_REG_IDX(GCTL) }, /* Global Control */
- { 0x0000c, 0x00002, 0x00007FFF, 0x00007FFF, hdaRegReadU16 , hdaRegWriteU16 , HDA_REG_IDX(WAKEEN) }, /* Wake Enable */
- { 0x0000e, 0x00002, 0x00000007, 0x00000007, hdaRegReadU8 , hdaRegWriteSTATESTS , HDA_REG_IDX(STATESTS) }, /* State Change Status */
- { 0x00010, 0x00002, 0xFFFFFFFF, 0x00000000, hdaRegReadUnimpl , hdaRegWriteUnimpl , HDA_REG_IDX(GSTS) }, /* Global Status */
- { 0x00018, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(OUTSTRMPAY) }, /* Output Stream Payload Capability */
- { 0x0001A, 0x00002, 0x0000FFFF, 0x00000000, hdaRegReadU16 , hdaRegWriteUnimpl , HDA_REG_IDX(INSTRMPAY) }, /* Input Stream Payload Capability */
- { 0x00020, 0x00004, 0xC00000FF, 0xC00000FF, hdaRegReadU32 , hdaRegWriteU32 , HDA_REG_IDX(INTCTL) }, /* Interrupt Control */
- { 0x00024, 0x00004, 0xC00000FF, 0x00000000, hdaRegReadINTSTS , hdaRegWriteUnimpl , HDA_REG_IDX(INTSTS) }, /* Interrupt Status */
- { 0x00030, 0x00004, 0xFFFFFFFF, 0x00000000, hdaRegReadWALCLK , hdaRegWriteUnimpl , HDA_REG_IDX_LOCAL(WALCLK) }, /* Wall Clock Counter */
- { 0x00034, 0x00004, 0x000000FF, 0x000000FF, hdaRegReadU32 , hdaRegWriteU32 , HDA_REG_IDX(SSYNC) }, /* Stream Synchronization */
- { 0x00040, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(CORBLBASE) }, /* CORB Lower Base Address */
- { 0x00044, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(CORBUBASE) }, /* CORB Upper Base Address */
- { 0x00048, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteCORBWP , HDA_REG_IDX(CORBWP) }, /* CORB Write Pointer */
- { 0x0004A, 0x00002, 0x000080FF, 0x000080FF, hdaRegReadU16 , hdaRegWriteCORBRP , HDA_REG_IDX(CORBRP) }, /* CORB Read Pointer */
- { 0x0004C, 0x00001, 0x00000003, 0x00000003, hdaRegReadU8 , hdaRegWriteCORBCTL , HDA_REG_IDX(CORBCTL) }, /* CORB Control */
- { 0x0004D, 0x00001, 0x00000001, 0x00000001, hdaRegReadU8 , hdaRegWriteCORBSTS , HDA_REG_IDX(CORBSTS) }, /* CORB Status */
- { 0x0004E, 0x00001, 0x000000F3, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimpl , HDA_REG_IDX(CORBSIZE) }, /* CORB Size */
- { 0x00050, 0x00004, 0xFFFFFF80, 0xFFFFFF80, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(RIRBLBASE) }, /* RIRB Lower Base Address */
- { 0x00054, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(RIRBUBASE) }, /* RIRB Upper Base Address */
- { 0x00058, 0x00002, 0x000000FF, 0x00008000, hdaRegReadU8 , hdaRegWriteRIRBWP , HDA_REG_IDX(RIRBWP) }, /* RIRB Write Pointer */
- { 0x0005A, 0x00002, 0x000000FF, 0x000000FF, hdaRegReadU16 , hdaRegWriteU16 , HDA_REG_IDX(RINTCNT) }, /* Response Interrupt Count */
- { 0x0005C, 0x00001, 0x00000007, 0x00000007, hdaRegReadU8 , hdaRegWriteU8 , HDA_REG_IDX(RIRBCTL) }, /* RIRB Control */
- { 0x0005D, 0x00001, 0x00000005, 0x00000005, hdaRegReadU8 , hdaRegWriteRIRBSTS , HDA_REG_IDX(RIRBSTS) }, /* RIRB Status */
- { 0x0005E, 0x00001, 0x000000F3, 0x00000000, hdaRegReadU8 , hdaRegWriteUnimpl , HDA_REG_IDX(RIRBSIZE) }, /* RIRB Size */
- { 0x00060, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteU32 , HDA_REG_IDX(IC) }, /* Immediate Command */
- { 0x00064, 0x00004, 0x00000000, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteUnimpl , HDA_REG_IDX(IR) }, /* Immediate Response */
- { 0x00068, 0x00002, 0x00000002, 0x00000002, hdaRegReadIRS , hdaRegWriteIRS , HDA_REG_IDX(IRS) }, /* Immediate Command Status */
- { 0x00070, 0x00004, 0xFFFFFFFF, 0xFFFFFF81, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(DPLBASE) }, /* DMA Position Lower Base */
- { 0x00074, 0x00004, 0xFFFFFFFF, 0xFFFFFFFF, hdaRegReadU32 , hdaRegWriteBase , HDA_REG_IDX(DPUBASE) }, /* DMA Position Upper Base */
- /* 4 Input Stream Descriptors (ISD). */
- HDA_REG_MAP_DEF_STREAM(0, SD0),
- HDA_REG_MAP_DEF_STREAM(1, SD1),
- HDA_REG_MAP_DEF_STREAM(2, SD2),
- HDA_REG_MAP_DEF_STREAM(3, SD3),
- /* 4 Output Stream Descriptors (OSD). */
- HDA_REG_MAP_DEF_STREAM(4, SD4),
- HDA_REG_MAP_DEF_STREAM(5, SD5),
- HDA_REG_MAP_DEF_STREAM(6, SD6),
- HDA_REG_MAP_DEF_STREAM(7, SD7)
-};
-
-/**
- * HDA register aliases (HDA spec 3.3.45).
- * @remarks Sorted by offReg.
- */
-static const struct
-{
- /** The alias register offset. */
- uint32_t offReg;
- /** The register index. */
- int idxAlias;
-} g_aHdaRegAliases[] =
-{
- { 0x2084, HDA_REG_SD0LPIB },
- { 0x20a4, HDA_REG_SD1LPIB },
- { 0x20c4, HDA_REG_SD2LPIB },
- { 0x20e4, HDA_REG_SD3LPIB },
- { 0x2104, HDA_REG_SD4LPIB },
- { 0x2124, HDA_REG_SD5LPIB },
- { 0x2144, HDA_REG_SD6LPIB },
- { 0x2164, HDA_REG_SD7LPIB },
-};
-
-#ifdef IN_RING3
-/** HDABDLE field descriptors for the v6+ saved state. */
-static SSMFIELD const g_aSSMBDLEFields6[] =
-{
- SSMFIELD_ENTRY(HDABDLE, u64BufAdr),
- SSMFIELD_ENTRY(HDABDLE, u32BufSize),
- SSMFIELD_ENTRY(HDABDLE, fIntOnCompletion),
- SSMFIELD_ENTRY_TERM()
-};
-
-/** HDABDLESTATE field descriptors for the v6+ saved state. */
-static SSMFIELD const g_aSSMBDLEStateFields6[] =
-{
- SSMFIELD_ENTRY(HDABDLESTATE, u32BDLIndex),
- SSMFIELD_ENTRY(HDABDLESTATE, cbBelowFIFOW),
- SSMFIELD_ENTRY(HDABDLESTATE, au8FIFO),
- SSMFIELD_ENTRY(HDABDLESTATE, u32BufOff),
- SSMFIELD_ENTRY_TERM()
-};
-
-/** HDASTREAMSTATE field descriptors for the v6+ saved state. */
-static SSMFIELD const g_aSSMStreamStateFields6[] =
-{
- SSMFIELD_ENTRY_OLD(cBDLE, 2),
- SSMFIELD_ENTRY(HDASTREAMSTATE, uCurBDLE),
- SSMFIELD_ENTRY(HDASTREAMSTATE, fDoStop),
- SSMFIELD_ENTRY(HDASTREAMSTATE, fActive),
- SSMFIELD_ENTRY(HDASTREAMSTATE, fInReset),
- SSMFIELD_ENTRY_TERM()
-};
-#endif
-
-/**
- * 32-bit size indexed masks, i.e. g_afMasks[2 bytes] = 0xffff.
- */
-static uint32_t const g_afMasks[5] =
-{
- UINT32_C(0), UINT32_C(0x000000ff), UINT32_C(0x0000ffff), UINT32_C(0x00ffffff), UINT32_C(0xffffffff)
-};
-
-#ifdef IN_RING3
-DECLINLINE(void) hdaStreamUpdateLPIB(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t u32LPIB)
-{
- AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStrmSt);
-
- Assert(u32LPIB <= pStrmSt->u32CBL);
-
- LogFlowFunc(("[SD%RU8]: LPIB=%RU32 (DMA Position Buffer Enabled: %RTbool)\n",
- pStrmSt->u8Strm, u32LPIB, pThis->fDMAPosition));
-
- /* Update LPIB in any case. */
- HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) = u32LPIB;
-
- /* Do we need to tell the current DMA position? */
- if (pThis->fDMAPosition)
- {
- int rc2 = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
- (pThis->u64DPBase & DPBASE_ADDR_MASK) + (pStrmSt->u8Strm * 2 * sizeof(uint32_t)),
- (void *)&u32LPIB, sizeof(uint32_t));
- AssertRC(rc2);
-#ifdef DEBUG
- hdaBDLEDumpAll(pThis, pStrmSt->u64BDLBase, pStrmSt->State.uCurBDLE);
-#endif
- }
-}
-#endif
-
-#if defined(IN_RING3) || defined(LOG_ENABLED)
-/**
- * Retrieves the number of bytes of a FIFOS register.
- *
- * @return Number of bytes of a given FIFOS register.
- */
-DECLINLINE(uint16_t) hdaSDFIFOSToBytes(uint32_t u32RegFIFOS)
-{
- uint16_t cb;
- switch (u32RegFIFOS)
- {
- /* Input */
- case HDA_SDINFIFO_120B: cb = 120; break;
- case HDA_SDINFIFO_160B: cb = 160; break;
-
- /* Output */
- case HDA_SDONFIFO_16B: cb = 16; break;
- case HDA_SDONFIFO_32B: cb = 32; break;
- case HDA_SDONFIFO_64B: cb = 64; break;
- case HDA_SDONFIFO_128B: cb = 128; break;
- case HDA_SDONFIFO_192B: cb = 192; break;
- case HDA_SDONFIFO_256B: cb = 256; break;
- default:
- {
- cb = 0; /* Can happen on stream reset. */
- break;
- }
- }
-
- return cb;
-}
-#endif
-
-#if defined(IN_RING3) && (defined(VBOX_HDA_WITH_FIFO) || defined(DEBUG))
-/**
- * Retrieves the number of bytes of a FIFOW register.
- *
- * @return Number of bytes of a given FIFOW register.
- */
-DECLINLINE(uint8_t) hdaSDFIFOWToBytes(uint32_t u32RegFIFOW)
-{
- uint32_t cb;
- switch (u32RegFIFOW)
- {
- case HDA_SDFIFOW_8B: cb = 8; break;
- case HDA_SDFIFOW_16B: cb = 16; break;
- case HDA_SDFIFOW_32B: cb = 32; break;
- default: cb = 0; break;
- }
-
-#ifdef RT_STRICT
- Assert(RT_IS_POWER_OF_TWO(cb));
-#endif
- return cb;
-}
-#endif
-
-#ifdef IN_RING3
-/**
- * Fetches the next BDLE to use for a stream.
- *
- * @return IPRT status code.
- */
-DECLINLINE(int) hdaStreamGetNextBDLE(PHDASTATE pThis, PHDASTREAM pStrmSt)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
-
- NOREF(pThis);
-
- Assert(pStrmSt->State.uCurBDLE < pStrmSt->u16LVI + 1);
-
-#ifdef DEBUG
- uint32_t uOldBDLE = pStrmSt->State.uCurBDLE;
-#endif
-
- /*
- * Switch to the next BDLE entry and do a wrap around
- * if we reached the end of the Buffer Descriptor List (BDL).
- */
- pStrmSt->State.uCurBDLE++;
- if (pStrmSt->State.uCurBDLE == pStrmSt->u16LVI + 1)
- {
- pStrmSt->State.uCurBDLE = 0;
-
- hdaStreamUpdateLPIB(pThis, pStrmSt, 0);
- }
-
- Assert(pStrmSt->State.uCurBDLE < pStrmSt->u16LVI + 1);
-
- int rc = hdaBDLEFetch(pThis, &pStrmSt->State.BDLE, pStrmSt->u64BDLBase, pStrmSt->State.uCurBDLE);
-
-#ifdef DEBUG
- LogFlowFunc(("[SD%RU8]: uOldBDLE=%RU16, uCurBDLE=%RU16, LVI=%RU32, %R[bdle]\n",
- pStrmSt->u8Strm, uOldBDLE, pStrmSt->State.uCurBDLE, pStrmSt->u16LVI, &pStrmSt->State.BDLE));
-#endif
- return rc;
-}
-#endif
-
-DECLINLINE(PHDASTREAM) hdaStreamFromID(PHDASTATE pThis, uint8_t uStreamID)
-{
- PHDASTREAM pStrmSt;
-
- switch (uStreamID)
- {
- case 0: /** @todo Use dynamic indices, based on stream assignment. */
- {
- pStrmSt = &pThis->StrmStLineIn;
- break;
- }
-# ifdef VBOX_WITH_HDA_MIC_IN
- case 2: /** @todo Use dynamic indices, based on stream assignment. */
- {
- pStrmSt = &pThis->StrmStMicIn;
- break;
- }
-# endif
- case 4: /** @todo Use dynamic indices, based on stream assignment. */
- {
- pStrmSt = &pThis->StrmStOut;
- break;
- }
-
- default:
- {
- pStrmSt = NULL;
- LogFunc(("Warning: Stream with ID=%RU8 not handled\n", uStreamID));
- break;
- }
- }
-
- return pStrmSt;
-}
-
-#ifdef IN_RING3
-/**
- * Retrieves the minimum number of bytes accumulated/free in the
- * FIFO before the controller will start a fetch/eviction of data.
- *
- * Uses SDFIFOW (FIFO Watermark Register).
- *
- * @return Number of bytes accumulated/free in the FIFO.
- */
-DECLINLINE(uint8_t) hdaStreamGetFIFOW(PHDASTATE pThis, PHDASTREAM pStrmSt)
-{
- AssertPtrReturn(pThis, 0);
- AssertPtrReturn(pStrmSt, 0);
-
-# ifdef VBOX_HDA_WITH_FIFO
- return hdaSDFIFOWToBytes(HDA_STREAM_REG(pThis, FIFOW, pStrmSt->u8Strm));
-# else
- return 0;
-# endif
-}
-#endif
-
-static int hdaProcessInterrupt(PHDASTATE pThis)
-{
-#define IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, num) \
- ( INTCTL_SX((pThis), num) \
- && (SDSTS(pThis, num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
-
- bool fIrq = false;
-
- if (/* Controller Interrupt Enable (CIE). */
- HDA_REG_FLAG_VALUE(pThis, INTCTL, CIE)
- && ( HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RINTFL)
- || HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RIRBOIS)
- || (HDA_REG(pThis, STATESTS) & HDA_REG(pThis, WAKEEN))))
- fIrq = true;
-
- /** @todo Don't hardcode stream numbers here. */
- if ( IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 0)
- || IS_INTERRUPT_OCCURED_AND_ENABLED(pThis, 4))
- {
-#ifdef IN_RING3
- LogFunc(("BCIS\n"));
-#endif
- fIrq = true;
- }
-
- if (HDA_REG_FLAG_VALUE(pThis, INTCTL, GIE))
- {
- LogFunc(("%s\n", fIrq ? "Asserted" : "Deasserted"));
- PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0 , fIrq);
- }
-
-#undef IS_INTERRUPT_OCCURED_AND_ENABLED
-
- return VINF_SUCCESS;
-}
-
-/**
- * Looks up a register at the exact offset given by @a offReg.
- *
- * @returns Register index on success, -1 if not found.
- * @param pThis The HDA device state.
- * @param offReg The register offset.
- */
-static int hdaRegLookup(PHDASTATE pThis, uint32_t offReg)
-{
- RT_NOREF(pThis);
-
- /*
- * Aliases.
- */
- if (offReg >= g_aHdaRegAliases[0].offReg)
- {
- for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegAliases); i++)
- if (offReg == g_aHdaRegAliases[i].offReg)
- return g_aHdaRegAliases[i].idxAlias;
- Assert(g_aHdaRegMap[RT_ELEMENTS(g_aHdaRegMap) - 1].offset < offReg);
- return -1;
- }
-
- /*
- * Binary search the
- */
- int idxEnd = RT_ELEMENTS(g_aHdaRegMap);
- int idxLow = 0;
- for (;;)
- {
- int idxMiddle = idxLow + (idxEnd - idxLow) / 2;
- if (offReg < g_aHdaRegMap[idxMiddle].offset)
- {
- if (idxLow == idxMiddle)
- break;
- idxEnd = idxMiddle;
- }
- else if (offReg > g_aHdaRegMap[idxMiddle].offset)
- {
- idxLow = idxMiddle + 1;
- if (idxLow >= idxEnd)
- break;
- }
- else
- return idxMiddle;
- }
-
-#ifdef RT_STRICT
- for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
- Assert(g_aHdaRegMap[i].offset != offReg);
-#endif
- return -1;
-}
-
-/**
- * Looks up a register covering the offset given by @a offReg.
- *
- * @returns Register index on success, -1 if not found.
- * @param pThis The HDA device state.
- * @param offReg The register offset.
- */
-static int hdaRegLookupWithin(PHDASTATE pThis, uint32_t offReg)
-{
- RT_NOREF(pThis);
-
- /*
- * Aliases.
- */
- if (offReg >= g_aHdaRegAliases[0].offReg)
- {
- for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegAliases); i++)
- {
- uint32_t off = offReg - g_aHdaRegAliases[i].offReg;
- if (off < 4 && off < g_aHdaRegMap[g_aHdaRegAliases[i].idxAlias].size)
- return g_aHdaRegAliases[i].idxAlias;
- }
- Assert(g_aHdaRegMap[RT_ELEMENTS(g_aHdaRegMap) - 1].offset < offReg);
- return -1;
- }
-
- /*
- * Binary search the register map.
- */
- int idxEnd = RT_ELEMENTS(g_aHdaRegMap);
- int idxLow = 0;
- for (;;)
- {
- int idxMiddle = idxLow + (idxEnd - idxLow) / 2;
- if (offReg < g_aHdaRegMap[idxMiddle].offset)
- {
- if (idxLow == idxMiddle)
- break;
- idxEnd = idxMiddle;
- }
- else if (offReg >= g_aHdaRegMap[idxMiddle].offset + g_aHdaRegMap[idxMiddle].size)
- {
- idxLow = idxMiddle + 1;
- if (idxLow >= idxEnd)
- break;
- }
- else
- return idxMiddle;
- }
-
-#ifdef RT_STRICT
- for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
- Assert(offReg - g_aHdaRegMap[i].offset >= g_aHdaRegMap[i].size);
-#endif
- return -1;
-}
-
-#ifdef IN_RING3
-static int hdaCmdSync(PHDASTATE pThis, bool fLocal)
-{
- int rc = VINF_SUCCESS;
- if (fLocal)
- {
- Assert((HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)));
- rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), pThis->u64CORBBase, pThis->pu32CorbBuf, pThis->cbCorbBuf);
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
-#ifdef DEBUG_CMD_BUFFER
- uint8_t i = 0;
- do
- {
- LogFunc(("CORB%02x: ", i));
- uint8_t j = 0;
- do
- {
- const char *pszPrefix;
- if ((i + j) == HDA_REG(pThis, CORBRP));
- pszPrefix = "[R]";
- else if ((i + j) == HDA_REG(pThis, CORBWP));
- pszPrefix = "[W]";
- else
- pszPrefix = " "; /* three spaces */
- LogFunc(("%s%08x", pszPrefix, pThis->pu32CorbBuf[i + j]));
- j++;
- } while (j < 8);
- LogFunc(("\n"));
- i += 8;
- } while(i != 0);
-#endif
- }
- else
- {
- Assert((HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA)));
- rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns), pThis->u64RIRBBase, pThis->pu64RirbBuf, pThis->cbRirbBuf);
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
-#ifdef DEBUG_CMD_BUFFER
- uint8_t i = 0;
- do {
- LogFunc(("RIRB%02x: ", i));
- uint8_t j = 0;
- do {
- const char *prefix;
- if ((i + j) == HDA_REG(pThis, RIRBWP))
- prefix = "[W]";
- else
- prefix = " ";
- LogFunc((" %s%016lx", prefix, pThis->pu64RirbBuf[i + j]));
- } while (++j < 8);
- LogFunc(("\n"));
- i += 8;
- } while (i != 0);
-#endif
- }
- return rc;
-}
-
-static int hdaCORBCmdProcess(PHDASTATE pThis)
-{
- PFNHDACODECVERBPROCESSOR pfn = (PFNHDACODECVERBPROCESSOR)NULL;
-
- int rc = hdaCmdSync(pThis, true);
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
-
- uint8_t corbRp = HDA_REG(pThis, CORBRP);
- uint8_t corbWp = HDA_REG(pThis, CORBWP);
- uint8_t rirbWp = HDA_REG(pThis, RIRBWP);
-
- Assert((corbWp != corbRp));
- LogFlowFunc(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP), HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
-
- while (corbRp != corbWp)
- {
- uint32_t cmd;
- uint64_t resp = 0;
- pfn = NULL;
- corbRp++;
- cmd = pThis->pu32CorbBuf[corbRp];
-
- rc = pThis->pCodec->pfnLookup(pThis->pCodec, HDA_CODEC_CMD(cmd, 0 /* Codec index */), &pfn);
- if (RT_SUCCESS(rc))
- {
- AssertPtr(pfn);
- rc = pfn(pThis->pCodec, HDA_CODEC_CMD(cmd, 0 /* LUN */), &resp);
- }
-
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
- (rirbWp)++;
-
- LogFunc(("verb:%08x->%016lx\n", cmd, resp));
- if ( (resp & CODEC_RESPONSE_UNSOLICITED)
- && !HDA_REG_FLAG_VALUE(pThis, GCTL, UR))
- {
- LogFunc(("unexpected unsolicited response.\n"));
- HDA_REG(pThis, CORBRP) = corbRp;
- return rc;
- }
-
- pThis->pu64RirbBuf[rirbWp] = resp;
-
- pThis->u8RespIntCnt++;
- if (pThis->u8RespIntCnt == RINTCNT_N(pThis))
- break;
- }
- HDA_REG(pThis, CORBRP) = corbRp;
- HDA_REG(pThis, RIRBWP) = rirbWp;
- rc = hdaCmdSync(pThis, false);
- LogFunc(("CORB(RP:%x, WP:%x) RIRBWP:%x\n", HDA_REG(pThis, CORBRP),
- HDA_REG(pThis, CORBWP), HDA_REG(pThis, RIRBWP)));
- if (HDA_REG_FLAG_VALUE(pThis, RIRBCTL, RIC))
- {
- HDA_REG(pThis, RIRBSTS) |= HDA_REG_FIELD_FLAG_MASK(RIRBSTS,RINTFL);
-
- pThis->u8RespIntCnt = 0;
- rc = hdaProcessInterrupt(pThis);
- }
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
- return rc;
-}
-
-static int hdaStreamCreate(PHDASTREAM pStrmSt)
-{
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
-
- int rc = RTSemEventCreate(&pStrmSt->State.hStateChangedEvent);
- AssertRC(rc);
-
- pStrmSt->u8Strm = UINT8_MAX;
-
- pStrmSt->State.fActive = false;
- pStrmSt->State.fInReset = false;
- pStrmSt->State.fDoStop = false;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static void hdaStreamDestroy(PHDASTREAM pStrmSt)
-{
- AssertPtrReturnVoid(pStrmSt);
-
- LogFlowFunc(("[SD%RU8]: Destroy\n", pStrmSt->u8Strm));
-
- int rc2 = hdaStreamStop(pStrmSt);
- AssertRC(rc2);
-
- if (pStrmSt->State.hStateChangedEvent != NIL_RTSEMEVENT)
- {
- rc2 = RTSemEventDestroy(pStrmSt->State.hStateChangedEvent);
- AssertRC(rc2);
- }
-
- LogFlowFuncLeave();
-}
-
-static int hdaStreamInit(PHDASTATE pThis, PHDASTREAM pStrmSt, uint8_t u8Strm)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
-
- pStrmSt->u8Strm = u8Strm;
- pStrmSt->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrmSt->u8Strm),
- HDA_STREAM_REG(pThis, BDPU, pStrmSt->u8Strm));
- pStrmSt->u16LVI = HDA_STREAM_REG(pThis, LVI, pStrmSt->u8Strm);
- pStrmSt->u32CBL = HDA_STREAM_REG(pThis, CBL, pStrmSt->u8Strm);
- pStrmSt->u16FIFOS = hdaSDFIFOSToBytes(HDA_STREAM_REG(pThis, FIFOS, pStrmSt->u8Strm));
-
- RT_ZERO(pStrmSt->State.BDLE);
- pStrmSt->State.uCurBDLE = 0;
-
- LogFlowFunc(("[SD%RU8]: DMA @ 0x%x (%RU32 bytes), LVI=%RU16, FIFOS=%RU16\n",
- pStrmSt->u8Strm, pStrmSt->u64BDLBase, pStrmSt->u32CBL, pStrmSt->u16LVI, pStrmSt->u16FIFOS));
-
-#ifdef DEBUG
- uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
- HDA_STREAM_REG(pThis, BDPU, u8Strm));
- uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, u8Strm);
- uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, u8Strm);
-
- LogFlowFunc(("\t-> DMA @ 0x%x, LVI=%RU16, CBL=%RU32\n", u64BaseDMA, u16LVI, u32CBL));
-
- hdaBDLEDumpAll(pThis, u64BaseDMA, u16LVI + 1);
-#endif
-
- return VINF_SUCCESS;
-}
-
-static void hdaStreamReset(PHDASTATE pThis, PHDASTREAM pStrmSt, uint8_t u8Strm)
-{
- AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStrmSt);
- AssertReturnVoid(u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
-
-#ifdef VBOX_STRICT
- AssertReleaseMsg(!RT_BOOL(HDA_STREAM_REG(pThis, CTL, u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)),
- ("Cannot reset stream %RU8 while in running state\n", u8Strm));
-#endif
-
- /*
- * Set reset state.
- */
- Assert(ASMAtomicReadBool(&pStrmSt->State.fInReset) == false); /* No nested calls. */
- ASMAtomicXchgBool(&pStrmSt->State.fInReset, true);
-
- /*
- * First, reset the internal stream state.
- */
- RT_BZERO(pStrmSt, sizeof(HDASTREAM));
-
- /*
- * Second, initialize the registers.
- */
- HDA_STREAM_REG(pThis, STS, u8Strm) = 0;
- /* According to the ICH6 datasheet, 0x40000 is the default value for stream descriptor register 23:20
- * bits are reserved for stream number 18.2.33, resets SDnCTL except SRST bit. */
- HDA_STREAM_REG(pThis, CTL, u8Strm) = 0x40000 | (HDA_STREAM_REG(pThis, CTL, u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
- /* ICH6 defines default values (0x77 for input and 0xBF for output descriptors) of FIFO size. 18.2.39. */
- HDA_STREAM_REG(pThis, FIFOS, u8Strm) = u8Strm < 4 ? HDA_SDINFIFO_120B : HDA_SDONFIFO_192B;
- /* See 18.2.38: Always defaults to 0x4 (32 bytes). */
- HDA_STREAM_REG(pThis, FIFOW, u8Strm) = HDA_SDFIFOW_32B;
- HDA_STREAM_REG(pThis, LPIB, u8Strm) = 0;
- HDA_STREAM_REG(pThis, CBL, u8Strm) = 0;
- HDA_STREAM_REG(pThis, LVI, u8Strm) = 0;
- HDA_STREAM_REG(pThis, FMT, u8Strm) = 0;
- HDA_STREAM_REG(pThis, BDPU, u8Strm) = 0;
- HDA_STREAM_REG(pThis, BDPL, u8Strm) = 0;
-
- /*
- * Third, set the internal state according to the just set registers.
- */
- pStrmSt->u8Strm = u8Strm;
- pStrmSt->u16FIFOS = HDA_STREAM_REG(pThis, FIFOS, u8Strm);
-
-
- /* Report that we're done resetting this stream. */
- HDA_STREAM_REG(pThis, CTL, u8Strm) = 0;
-
- LogFunc(("[SD%RU8]: Reset\n", u8Strm));
-
- /* Exit reset mode. */
- ASMAtomicXchgBool(&pStrmSt->State.fInReset, false);
-}
-
-#if 0 // unused
-static int hdaStreamStart(PHDASTREAM pStrmSt)
-{
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
-
- ASMAtomicXchgBool(&pStrmSt->State.fDoStop, false);
- ASMAtomicXchgBool(&pStrmSt->State.fActive, true);
-
- LogFlowFuncLeave();
- return VINF_SUCCESS;
-}
-#endif
-
-static int hdaStreamStop(PHDASTREAM pStrmSt)
-{
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
-
- /* Already in stopped state? */
- bool fActive = ASMAtomicReadBool(&pStrmSt->State.fActive);
- if (!fActive)
- return VINF_SUCCESS;
-
-#if 0 /** @todo Does not work (yet), as EMT deadlocks then. */
- /*
- * Wait for the stream to stop.
- */
- ASMAtomicXchgBool(&pStrmSt->State.fDoStop, true);
-
- int rc = hdaStreamWaitForStateChange(pStrmSt, 60 * 1000 /* ms timeout */);
- fActive = ASMAtomicReadBool(&pStrmSt->State.fActive);
- if ( /* Waiting failed? */
- RT_FAILURE(rc)
- /* Stream is still active? */
- || fActive)
- {
- AssertRC(rc);
- LogRel(("HDA: Warning: Unable to stop stream %RU8 (state: %s), rc=%Rrc\n",
- pStrmSt->u8Strm, fActive ? "active" : "stopped", rc));
- }
-#else
- int rc = VINF_SUCCESS;
-#endif
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-#if 0 // unused
-static int hdaStreamWaitForStateChange(PHDASTREAM pStrmSt, RTMSINTERVAL msTimeout)
-{
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
-
- LogFlowFunc(("[SD%RU8]: msTimeout=%RU32\n", pStrmSt->u8Strm, msTimeout));
- return RTSemEventWait(pStrmSt->State.hStateChangedEvent, msTimeout);
-}
-#endif
-#endif /* IN_RING3 */
-
-/* Register access handlers. */
-
-static int hdaRegReadUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- RT_NOREF(pThis, iReg);
- *pu32Value = 0;
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteUnimpl(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF(pThis, iReg, u32Value);
- return VINF_SUCCESS;
-}
-
-/* U8 */
-static int hdaRegReadU8(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].mem_idx] & g_aHdaRegMap[iReg].readable) & 0xffffff00) == 0);
- return hdaRegReadU32(pThis, iReg, pu32Value);
-}
-
-static int hdaRegWriteU8(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- Assert((u32Value & 0xffffff00) == 0);
- return hdaRegWriteU32(pThis, iReg, u32Value);
-}
-
-/* U16 */
-static int hdaRegReadU16(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].mem_idx] & g_aHdaRegMap[iReg].readable) & 0xffff0000) == 0);
- return hdaRegReadU32(pThis, iReg, pu32Value);
-}
-
-static int hdaRegWriteU16(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- Assert((u32Value & 0xffff0000) == 0);
- return hdaRegWriteU32(pThis, iReg, u32Value);
-}
-
-/* U24 */
-static int hdaRegReadU24(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- Assert(((pThis->au32Regs[g_aHdaRegMap[iReg].mem_idx] & g_aHdaRegMap[iReg].readable) & 0xff000000) == 0);
- return hdaRegReadU32(pThis, iReg, pu32Value);
-}
-
-static int hdaRegWriteU24(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- Assert((u32Value & 0xff000000) == 0);
- return hdaRegWriteU32(pThis, iReg, u32Value);
-}
-
-/* U32 */
-static int hdaRegReadU32(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- uint32_t iRegMem = g_aHdaRegMap[iReg].mem_idx;
-
- *pu32Value = pThis->au32Regs[iRegMem] & g_aHdaRegMap[iReg].readable;
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteU32(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- uint32_t iRegMem = g_aHdaRegMap[iReg].mem_idx;
-
- pThis->au32Regs[iRegMem] = (u32Value & g_aHdaRegMap[iReg].writable)
- | (pThis->au32Regs[iRegMem] & ~g_aHdaRegMap[iReg].writable);
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteGCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF(iReg);
- if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, RST))
- {
- /* Set the CRST bit to indicate that we're leaving reset mode. */
- HDA_REG(pThis, GCTL) |= HDA_REG_FIELD_FLAG_MASK(GCTL, RST);
-
- if (pThis->fInReset)
- {
- LogFunc(("Leaving reset\n"));
- pThis->fInReset = false;
- }
- }
- else
- {
-#ifdef IN_RING3
- /* Enter reset state. */
- if ( HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA)
- || HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA))
- {
- LogFunc(("Entering reset with DMA(RIRB:%s, CORB:%s)\n",
- HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) ? "on" : "off",
- HDA_REG_FLAG_VALUE(pThis, RIRBCTL, DMA) ? "on" : "off"));
- }
-
- /* Clear the CRST bit to indicate that we're in reset mode. */
- HDA_REG(pThis, GCTL) &= ~HDA_REG_FIELD_FLAG_MASK(GCTL, RST);
- pThis->fInReset = true;
-
- /* As the CRST bit now is set, we now can proceed resetting stuff. */
- hdaReset(pThis->CTX_SUFF(pDevIns));
-#else
- return VINF_IOM_R3_MMIO_WRITE;
-#endif
- }
- if (u32Value & HDA_REG_FIELD_FLAG_MASK(GCTL, FSH))
- {
- /* Flush: GSTS:1 set, see 6.2.6. */
- HDA_REG(pThis, GSTS) |= HDA_REG_FIELD_FLAG_MASK(GSTS, FSH); /* Set the flush state. */
- /* DPLBASE and DPUBASE should be initialized with initial value (see 6.2.6). */
- }
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteSTATESTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- uint32_t iRegMem = g_aHdaRegMap[iReg].mem_idx;
-
- uint32_t v = pThis->au32Regs[iRegMem];
- uint32_t nv = u32Value & HDA_STATES_SCSF;
- pThis->au32Regs[iRegMem] &= ~(v & nv); /* write of 1 clears corresponding bit */
- return VINF_SUCCESS;
-}
-
-static int hdaRegReadINTSTS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- RT_NOREF(iReg);
- uint32_t v = 0;
- if ( HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RIRBOIS)
- || HDA_REG_FLAG_VALUE(pThis, RIRBSTS, RINTFL)
- || HDA_REG_FLAG_VALUE(pThis, CORBSTS, CMEI)
- || HDA_REG(pThis, STATESTS))
- {
- v |= RT_BIT(30); /* Touch CIS. */
- }
-
-#define HDA_IS_STREAM_EVENT(pThis, num) \
- ( (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE)) \
- || (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE)) \
- || (SDSTS((pThis), num) & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)))
-
-#define HDA_MARK_STREAM(pThis, num, v) \
- do { (v) |= HDA_IS_STREAM_EVENT((pThis), num) ? RT_BIT((num)) : 0; } while(0)
-
- HDA_MARK_STREAM(pThis, 0, v);
- HDA_MARK_STREAM(pThis, 1, v);
- HDA_MARK_STREAM(pThis, 2, v);
- HDA_MARK_STREAM(pThis, 3, v);
- HDA_MARK_STREAM(pThis, 4, v);
- HDA_MARK_STREAM(pThis, 5, v);
- HDA_MARK_STREAM(pThis, 6, v);
- HDA_MARK_STREAM(pThis, 7, v);
-
-#undef HDA_IS_STREAM_EVENT
-#undef HDA_MARK_STREAM
-
- v |= v ? RT_BIT(31) : 0;
-
- *pu32Value = v;
- return VINF_SUCCESS;
-}
-
-static int hdaRegReadLPIB(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- const uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, LPIB, iReg);
- uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, u8Strm);
-
-#if defined(LOG_ENABLED)
- const uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, u8Strm);
- LogFlowFunc(("[SD%RU8]: LPIB=%RU32, CBL=%RU32\n", u8Strm, u32LPIB, u32CBL));
-#endif
-
- *pu32Value = u32LPIB;
- return VINF_SUCCESS;
-}
-
-static int hdaRegReadWALCLK(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- RT_NOREF(iReg);
- /* HDA spec (1a): 3.3.16 WALCLK counter ticks with 24Mhz bitclock rate. */
- *pu32Value = (uint32_t)ASMMultU64ByU32DivByU32(PDMDevHlpTMTimeVirtGetNano(pThis->CTX_SUFF(pDevIns))
- - pThis->u64BaseTS, 24, 1000);
- LogFlowFunc(("%RU32\n", *pu32Value));
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteCORBRP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF(iReg);
- if (u32Value & HDA_REG_FIELD_FLAG_MASK(CORBRP, RST))
- {
- HDA_REG(pThis, CORBRP) = 0;
- }
-#ifndef BIRD_THINKS_CORBRP_IS_MOSTLY_RO
- else
- return hdaRegWriteU8(pThis, iReg, u32Value);
-#endif
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteCORBCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-#ifdef IN_RING3
- int rc = hdaRegWriteU8(pThis, iReg, u32Value);
- AssertRC(rc);
- if ( HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP)
- && HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA) != 0)
- {
- return hdaCORBCmdProcess(pThis);
- }
- return rc;
-#else
- RT_NOREF(pThis, iReg, u32Value);
- return VINF_IOM_R3_MMIO_WRITE;
-#endif
-}
-
-static int hdaRegWriteCORBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF(iReg);
- uint32_t v = HDA_REG(pThis, CORBSTS);
- HDA_REG(pThis, CORBSTS) &= ~(v & u32Value);
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteCORBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-#ifdef IN_RING3
- int rc;
- rc = hdaRegWriteU16(pThis, iReg, u32Value);
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
- if (HDA_REG(pThis, CORBWP) == HDA_REG(pThis, CORBRP))
- return VINF_SUCCESS;
- if (!HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA))
- return VINF_SUCCESS;
- rc = hdaCORBCmdProcess(pThis);
- return rc;
-#else
- RT_NOREF(pThis, iReg, u32Value);
- return VINF_IOM_R3_MMIO_WRITE;
-#endif
-}
-
-static int hdaRegWriteSDCBL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- int rc = hdaRegWriteU32(pThis, iReg, u32Value);
- if (RT_SUCCESS(rc))
- {
- uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, CBL, iReg);
-
- PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
- if (pStrmSt)
- {
- pStrmSt->u32CBL = u32Value;
-
- /* Reset BDLE state. */
- RT_ZERO(pStrmSt->State.BDLE);
- pStrmSt->State.uCurBDLE = 0;
- }
-
- LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", u8Strm, u32Value));
- }
- else
- AssertRCReturn(rc, VINF_SUCCESS);
-
- return rc;
-}
-
-static int hdaRegWriteSDCTL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-#if defined(LOG_ENABLED) || defined(IN_RING3)
- bool const fRun = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
- bool const fInRun = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
-#endif
- bool const fReset = RT_BOOL(u32Value & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
- bool const fInReset = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST));
-
- uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, CTL, iReg);
-
- PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
- if (!pStrmSt)
- {
- LogFunc(("Warning: Changing SDCTL on non-attached stream with ID=%RU8 (iReg=0x%x)\n", u8Strm, iReg));
- return hdaRegWriteU24(pThis, iReg, u32Value); /* Write 3 bytes. */
- }
-
- LogFunc(("[SD%RU8]: fRun=%RTbool, fInRun=%RTbool, fReset=%RTbool, fInReset=%RTbool, %R[sdctl]\n",
- u8Strm, fRun, fInRun, fReset, fInReset, u32Value));
-
- if (fInReset)
- {
- /* Guest is resetting HDA's stream, we're expecting guest will mark stream as exit. */
- Assert(!fReset);
- LogFunc(("Guest initiated exit of stream reset\n"));
- }
- else if (fReset)
- {
-#ifdef IN_RING3
- /* ICH6 datasheet 18.2.33 says that RUN bit should be cleared before initiation of reset. */
- Assert(!fInRun && !fRun);
-
- LogFunc(("Guest initiated enter to stream reset\n"));
- hdaStreamReset(pThis, pStrmSt, u8Strm);
-#else
- return VINF_IOM_R3_MMIO_WRITE;
-#endif
- }
- else
- {
-#ifdef IN_RING3
- /*
- * We enter here to change DMA states only.
- */
- if (fInRun != fRun)
- {
- Assert(!fReset && !fInReset);
- LogFunc(("[SD%RU8]: fRun=%RTbool\n", u8Strm, fRun));
-
- PHDADRIVER pDrv;
- switch (u8Strm)
- {
- case 0: /** @todo Use a variable here. Later. */
- {
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
- pDrv->LineIn.pStrmIn, fRun);
- break;
- }
-# ifdef VBOX_WITH_HDA_MIC_IN
- case 2: /** @todo Use a variable here. Later. */
- {
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
- pDrv->MicIn.pStrmIn, fRun);
- break;
- }
-# endif
- case 4: /** @todo Use a variable here. Later. */
- {
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
- pDrv->Out.pStrmOut, fRun);
- break;
- }
- default:
- AssertMsgFailed(("Changing RUN bit on non-attached stream, register %RU32\n", iReg));
- break;
- }
- }
-
- if (!fInRun && !fRun)
- hdaStreamInit(pThis, pStrmSt, u8Strm);
-
-#else /* IN_RING3 */
- return VINF_IOM_R3_MMIO_WRITE;
-#endif /* !IN_RING3 */
- }
-
- return hdaRegWriteU24(pThis, iReg, u32Value);
-}
-
-static int hdaRegWriteSDSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- uint32_t v = HDA_REG_IND(pThis, iReg);
- v &= ~(u32Value & v);
- HDA_REG_IND(pThis, iReg) = v;
- hdaProcessInterrupt(pThis);
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteSDLVI(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- if (!hdaRegWriteSDIsAllowed(pThis, iReg, u32Value))
- return VINF_SUCCESS;
-
- int rc = hdaRegWriteU16(pThis, iReg, u32Value);
- if (RT_SUCCESS(rc))
- {
- uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, LVI, iReg);
-
- PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
- if (pStrmSt)
- {
- pStrmSt->u16LVI = u32Value;
-
- /* Reset BDLE state. */
- RT_ZERO(pStrmSt->State.BDLE);
- pStrmSt->State.uCurBDLE = 0;
- }
-
- LogFlowFunc(("[SD%RU8]: CBL=%RU32\n", u8Strm, u32Value));
- }
- else
- AssertRCReturn(rc, VINF_SUCCESS);
-
- return rc;
-}
-
-static int hdaRegWriteSDFIFOW(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- switch (u32Value)
- {
- case HDA_SDFIFOW_8B:
- case HDA_SDFIFOW_16B:
- case HDA_SDFIFOW_32B:
- return hdaRegWriteU16(pThis, iReg, u32Value);
- default:
- LogFunc(("Attempt to store unsupported value(%x) in SDFIFOW\n", u32Value));
- return hdaRegWriteU16(pThis, iReg, HDA_SDFIFOW_32B);
- }
-}
-
-/**
- * @note This method could be called for changing value on Output Streams
- * only (ICH6 datasheet 18.2.39).
- */
-static int hdaRegWriteSDFIFOS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- /** @todo Only allow updating FIFOS if RUN bit is 0? */
- uint32_t u32FIFOS = 0;
-
- switch (iReg)
- {
- /* SDInFIFOS is RO, n=0-3. */
- case HDA_REG_SD0FIFOS:
- case HDA_REG_SD1FIFOS:
- case HDA_REG_SD2FIFOS:
- case HDA_REG_SD3FIFOS:
- {
- LogFunc(("Guest tries to change R/O value of FIFO size of input stream, ignoring\n"));
- break;
- }
- case HDA_REG_SD4FIFOS:
- case HDA_REG_SD5FIFOS:
- case HDA_REG_SD6FIFOS:
- case HDA_REG_SD7FIFOS:
- {
- switch(u32Value)
- {
- case HDA_SDONFIFO_16B:
- case HDA_SDONFIFO_32B:
- case HDA_SDONFIFO_64B:
- case HDA_SDONFIFO_128B:
- case HDA_SDONFIFO_192B:
- u32FIFOS = u32Value;
- break;
-
- case HDA_SDONFIFO_256B: /** @todo r=andy Investigate this. */
- LogFunc(("256-bit is unsupported, HDA is switched into 192-bit mode\n"));
- /* Fall through is intentional. */
- default:
- u32FIFOS = HDA_SDONFIFO_192B;
- break;
- }
-
- break;
- }
- default:
- {
- AssertMsgFailed(("Something weird happened with register lookup routine\n"));
- break;
- }
- }
-
- if (u32FIFOS)
- {
- LogFunc(("[SD%RU8]: Updating FIFOS to %RU32 bytes\n", 0, hdaSDFIFOSToBytes(u32FIFOS)));
- /** @todo Update internal stream state with new FIFOS. */
-
- return hdaRegWriteU16(pThis, iReg, u32FIFOS);
- }
-
- return VINF_SUCCESS;
-}
-
-#if defined(IN_RING3) && defined(VBOX_WITH_HDA_CODEC_EMU)
-static int hdaSDFMTToStrmCfg(uint32_t u32SDFMT, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
-# define EXTRACT_VALUE(v, mask, shift) ((v & ((mask) << (shift))) >> (shift))
-
- int rc = VINF_SUCCESS;
-
- uint32_t u32Hz = (u32SDFMT & HDA_SDFMT_BASE_RATE_SHIFT) ? 44100 : 48000;
- uint32_t u32HzMult = 1;
- uint32_t u32HzDiv = 1;
-
- switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_MULT_MASK, HDA_SDFMT_MULT_SHIFT))
- {
- case 0: u32HzMult = 1; break;
- case 1: u32HzMult = 2; break;
- case 2: u32HzMult = 3; break;
- case 3: u32HzMult = 4; break;
- default:
- LogFunc(("Unsupported multiplier %x\n",
- EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_MULT_MASK, HDA_SDFMT_MULT_SHIFT)));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
- switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_DIV_MASK, HDA_SDFMT_DIV_SHIFT))
- {
- case 0: u32HzDiv = 1; break;
- case 1: u32HzDiv = 2; break;
- case 2: u32HzDiv = 3; break;
- case 3: u32HzDiv = 4; break;
- case 4: u32HzDiv = 5; break;
- case 5: u32HzDiv = 6; break;
- case 6: u32HzDiv = 7; break;
- case 7: u32HzDiv = 8; break;
- default:
- LogFunc(("Unsupported divisor %x\n",
- EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_DIV_MASK, HDA_SDFMT_DIV_SHIFT)));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- PDMAUDIOFMT enmFmt = AUD_FMT_S16; /* Default to 16-bit signed. */
- switch (EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT))
- {
- case 0:
- LogFunc(("Requested 8-bit\n"));
- enmFmt = AUD_FMT_S8;
- break;
- case 1:
- LogFunc(("Requested 16-bit\n"));
- enmFmt = AUD_FMT_S16;
- break;
- case 2:
- LogFunc(("Requested 20-bit\n"));
- break;
- case 3:
- LogFunc(("Requested 24-bit\n"));
- break;
- case 4:
- LogFunc(("Requested 32-bit\n"));
- enmFmt = AUD_FMT_S32;
- break;
- default:
- AssertMsgFailed(("Unsupported bits shift %x\n",
- EXTRACT_VALUE(u32SDFMT, HDA_SDFMT_BITS_MASK, HDA_SDFMT_BITS_SHIFT)));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- if (RT_SUCCESS(rc))
- {
- pCfg->uHz = u32Hz * u32HzMult / u32HzDiv;
- pCfg->cChannels = (u32SDFMT & 0xf) + 1;
- pCfg->enmFormat = enmFmt;
- pCfg->enmEndianness = PDMAUDIOHOSTENDIANNESS;
- }
-
-# undef EXTRACT_VALUE
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-#endif
-
-static int hdaRegWriteSDFMT(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
-#ifdef IN_RING3
-# ifdef VBOX_WITH_HDA_CODEC_EMU
- /* No reason to re-open stream with same settings. */
- if (u32Value == HDA_REG_IND(pThis, iReg))
- return VINF_SUCCESS;
-
- PDMAUDIOSTREAMCFG strmCfg;
- int rc = hdaSDFMTToStrmCfg(u32Value, &strmCfg);
- if (RT_FAILURE(rc))
- return VINF_SUCCESS; /* Always return success to the MMIO handler. */
-
- uint8_t u8Strm = HDA_SD_NUM_FROM_REG(pThis, FMT, iReg);
-
- PHDADRIVER pDrv;
- switch (iReg)
- {
- case HDA_REG_SD0FMT:
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- rc = hdaCodecOpenStream(pThis->pCodec, PI_INDEX, &strmCfg);
- break;
-# ifdef VBOX_WITH_HDA_MIC_IN
- case HDA_REG_SD2FMT:
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- rc = hdaCodecOpenStream(pThis->pCodec, MC_INDEX, &strmCfg);
- break;
-# endif
- case HDA_REG_SD4FMT:
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- rc = hdaCodecOpenStream(pThis->pCodec, PO_INDEX, &strmCfg);
- break;
- default:
- LogFunc(("Warning: Changing SDFMT on non-attached stream with ID=%RU8 (iReg=0x%x)\n", u8Strm, iReg));
- break;
- }
-
- /** @todo r=andy rc gets lost; needs fixing. */
- return hdaRegWriteU16(pThis, iReg, u32Value);
-# else /* !VBOX_WITH_HDA_CODEC_EMU */
- return hdaRegWriteU16(pThis, iReg, u32Value);
-# endif
-#else /* !IN_RING3 */
- RT_NOREF(pThis, iReg, u32Value);
- return VINF_IOM_R3_MMIO_WRITE;
-#endif
-}
-
-/* Note: Will be called for both, BDPL and BDPU, registers. */
-DECLINLINE(int) hdaRegWriteSDBDPX(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value, uint8_t u8Strm)
-{
- if (!hdaRegWriteSDIsAllowed(pThis, iReg, u32Value))
- return VINF_SUCCESS;
-
- int rc = hdaRegWriteU32(pThis, iReg, u32Value);
- if (RT_SUCCESS(rc))
- {
- PHDASTREAM pStrmSt = hdaStreamFromID(pThis, u8Strm);
- if (pStrmSt)
- {
- pStrmSt->u64BDLBase = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, u8Strm),
- HDA_STREAM_REG(pThis, BDPU, u8Strm));
- /* Reset BDLE state. */
- RT_ZERO(pStrmSt->State.BDLE);
- pStrmSt->State.uCurBDLE = 0;
- }
- }
- else
- AssertRCReturn(rc, VINF_SUCCESS);
-
- return rc;
-}
-
-static int hdaRegWriteSDBDPL(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- return hdaRegWriteSDBDPX(pThis, iReg, u32Value, HDA_SD_NUM_FROM_REG(pThis, BDPL, iReg));
-}
-
-static int hdaRegWriteSDBDPU(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- return hdaRegWriteSDBDPX(pThis, iReg, u32Value, HDA_SD_NUM_FROM_REG(pThis, BDPU, iReg));
-}
-
-/**
- * Checks whether a write to a specific SDnXXX register is allowed or not.
- *
- * @return bool Returns @true if write is allowed, @false if not.
- * @param pThis Pointer to HDA state.
- * @param iReg Register to write.
- * @param u32Value Value to write.
- */
-inline bool hdaRegWriteSDIsAllowed(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF(u32Value);
-
- /* Check if the SD's RUN bit is set. */
- bool fIsRunning = RT_BOOL(HDA_REG_IND(pThis, iReg) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
- if (fIsRunning)
- {
-#ifdef VBOX_STRICT
- AssertMsgFailed(("[SD%RU8]: Cannot write to register 0x%x (0x%x) when RUN bit is set\n",
- HDA_SD_NUM_FROM_REG(pThis, CTL, iReg), iReg, u32Value));
-#endif
- return false;
- }
-
- return true;
-}
-
-static int hdaRegReadIRS(PHDASTATE pThis, uint32_t iReg, uint32_t *pu32Value)
-{
- int rc = VINF_SUCCESS;
- /* regarding 3.4.3 we should mark IRS as busy in case CORB is active */
- if ( HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP)
- || HDA_REG_FLAG_VALUE(pThis, CORBCTL, DMA))
- HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy */
-
- rc = hdaRegReadU32(pThis, iReg, pu32Value);
- return rc;
-}
-
-static int hdaRegWriteIRS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF(iReg);
- int rc = VINF_SUCCESS;
-
- /*
- * If the guest set the ICB bit of IRS register, HDA should process the verb in IC register,
- * write the response to IR register, and set the IRV (valid in case of success) bit of IRS register.
- */
- if ( u32Value & HDA_REG_FIELD_FLAG_MASK(IRS, ICB)
- && !HDA_REG_FLAG_VALUE(pThis, IRS, ICB))
- {
-#ifdef IN_RING3
- PFNHDACODECVERBPROCESSOR pfn = NULL;
- uint64_t resp;
- uint32_t cmd = HDA_REG(pThis, IC);
- if (HDA_REG(pThis, CORBWP) != HDA_REG(pThis, CORBRP))
- {
- /*
- * 3.4.3 defines behavior of immediate Command status register.
- */
- LogRel(("guest attempted process immediate verb (%x) with active CORB\n", cmd));
- return rc;
- }
- HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy */
- LogFunc(("IC:%x\n", cmd));
-
- rc = pThis->pCodec->pfnLookup(pThis->pCodec,
- HDA_CODEC_CMD(cmd, 0 /* LUN */),
- &pfn);
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
- rc = pfn(pThis->pCodec,
- HDA_CODEC_CMD(cmd, 0 /* LUN */), &resp);
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
-
- HDA_REG(pThis, IR) = (uint32_t)resp;
- LogFunc(("IR:%x\n", HDA_REG(pThis, IR)));
- HDA_REG(pThis, IRS) = HDA_REG_FIELD_FLAG_MASK(IRS, IRV); /* result is ready */
- HDA_REG(pThis, IRS) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, ICB); /* busy is clear */
-#else /* !IN_RING3 */
- rc = VINF_IOM_R3_MMIO_WRITE;
-#endif
- return rc;
- }
- /*
- * Once the guest read the response, it should clean the IRV bit of the IRS register.
- */
- if ( u32Value & HDA_REG_FIELD_FLAG_MASK(IRS, IRV)
- && HDA_REG_FLAG_VALUE(pThis, IRS, IRV))
- HDA_REG(pThis, IRS) &= ~HDA_REG_FIELD_FLAG_MASK(IRS, IRV);
- return rc;
-}
-
-static int hdaRegWriteRIRBWP(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF(iReg);
- if (u32Value & HDA_REG_FIELD_FLAG_MASK(RIRBWP, RST))
- {
- HDA_REG(pThis, RIRBWP) = 0;
- }
- /* The remaining bits are O, see 6.2.22 */
- return VINF_SUCCESS;
-}
-
-static int hdaRegWriteBase(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- uint32_t iRegMem = g_aHdaRegMap[iReg].mem_idx;
- int rc = hdaRegWriteU32(pThis, iReg, u32Value);
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
-
- switch(iReg)
- {
- case HDA_REG_CORBLBASE:
- pThis->u64CORBBase &= UINT64_C(0xFFFFFFFF00000000);
- pThis->u64CORBBase |= pThis->au32Regs[iRegMem];
- break;
- case HDA_REG_CORBUBASE:
- pThis->u64CORBBase &= UINT64_C(0x00000000FFFFFFFF);
- pThis->u64CORBBase |= ((uint64_t)pThis->au32Regs[iRegMem] << 32);
- break;
- case HDA_REG_RIRBLBASE:
- pThis->u64RIRBBase &= UINT64_C(0xFFFFFFFF00000000);
- pThis->u64RIRBBase |= pThis->au32Regs[iRegMem];
- break;
- case HDA_REG_RIRBUBASE:
- pThis->u64RIRBBase &= UINT64_C(0x00000000FFFFFFFF);
- pThis->u64RIRBBase |= ((uint64_t)pThis->au32Regs[iRegMem] << 32);
- break;
- case HDA_REG_DPLBASE:
- {
- pThis->u64DPBase &= UINT64_C(0xFFFFFFFF00000000);
- pThis->u64DPBase |= pThis->au32Regs[iRegMem];
-
- /* Also make sure to handle the DMA position enable bit. */
- pThis->fDMAPosition = pThis->au32Regs[iRegMem] & RT_BIT_32(0);
- LogRel(("HDA: %s DMA position buffer\n", pThis->fDMAPosition ? "Enabled" : "Disabled"));
- break;
- }
- case HDA_REG_DPUBASE:
- pThis->u64DPBase &= UINT64_C(0x00000000FFFFFFFF);
- pThis->u64DPBase |= ((uint64_t)pThis->au32Regs[iRegMem] << 32);
- break;
- default:
- AssertMsgFailed(("Invalid index\n"));
- break;
- }
-
- LogFunc(("CORB base:%llx RIRB base: %llx DP base: %llx\n",
- pThis->u64CORBBase, pThis->u64RIRBBase, pThis->u64DPBase));
- return rc;
-}
-
-static int hdaRegWriteRIRBSTS(PHDASTATE pThis, uint32_t iReg, uint32_t u32Value)
-{
- RT_NOREF(iReg);
- uint8_t v = HDA_REG(pThis, RIRBSTS);
- HDA_REG(pThis, RIRBSTS) &= ~(v & u32Value);
-
- return hdaProcessInterrupt(pThis);
-}
-
-#ifdef IN_RING3
-# ifdef LOG_ENABLED
-static void hdaBDLEDumpAll(PHDASTATE pThis, uint64_t u64BDLBase, uint16_t cBDLE)
-{
- LogFlowFunc(("BDLEs @ 0x%x (%RU16):\n", u64BDLBase, cBDLE));
- if (!u64BDLBase)
- return;
-
- uint32_t cbBDLE = 0;
- for (uint16_t i = 0; i < cBDLE; i++)
- {
- uint8_t bdle[16]; /** @todo Use a define. */
- PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BDLBase + i * 16, bdle, 16); /** @todo Use a define. */
-
- uint64_t addr = *(uint64_t *)bdle;
- uint32_t len = *(uint32_t *)&bdle[8];
- uint32_t ioc = *(uint32_t *)&bdle[12];
-
- LogFlowFunc(("\t#%03d BDLE(adr:0x%llx, size:%RU32, ioc:%RTbool)\n",
- i, addr, len, RT_BOOL(ioc & 0x1)));
-
- cbBDLE += len;
- }
-
- LogFlowFunc(("Total: %RU32 bytes\n", cbBDLE));
-
- if (!pThis->u64DPBase) /* No DMA base given? Bail out. */
- return;
-
- LogFlowFunc(("DMA counters:\n"));
-
- for (int i = 0; i < cBDLE; i++)
- {
- uint32_t uDMACnt;
- PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), (pThis->u64DPBase & DPBASE_ADDR_MASK) + (i * 2 * sizeof(uint32_t)),
- &uDMACnt, sizeof(uDMACnt));
-
- LogFlowFunc(("\t#%03d DMA @ 0x%x\n", i , uDMACnt));
- }
-}
-# endif
-
-/**
- * Fetches a Bundle Descriptor List Entry (BDLE) from the DMA engine.
- *
- * @param pThis Pointer to HDA state.
- * @param pBDLE Where to store the fetched result.
- * @param u64BaseDMA Address base of DMA engine to use.
- * @param u16Entry BDLE entry to fetch.
- */
-static int hdaBDLEFetch(PHDASTATE pThis, PHDABDLE pBDLE, uint64_t u64BaseDMA, uint16_t u16Entry)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pBDLE, VERR_INVALID_POINTER);
- AssertReturn(u64BaseDMA, VERR_INVALID_PARAMETER);
- /** @todo Compare u16Entry with LVI. */
-
- uint8_t uBundleEntry[16]; /** @todo Define a BDLE length. */
- int rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns), u64BaseDMA + u16Entry * 16, /** @todo Define a BDLE length. */
- uBundleEntry, RT_ELEMENTS(uBundleEntry));
- if (RT_FAILURE(rc))
- return rc;
-
- RT_BZERO(pBDLE, sizeof(HDABDLE));
-
- pBDLE->State.u32BDLIndex = u16Entry;
- pBDLE->u64BufAdr = *(uint64_t *) uBundleEntry;
- pBDLE->u32BufSize = *(uint32_t *)&uBundleEntry[8];
- if (pBDLE->u32BufSize < sizeof(uint16_t)) /* Must be at least one word. */
- return VERR_INVALID_STATE;
-
- pBDLE->fIntOnCompletion = (*(uint32_t *)&uBundleEntry[12]) & 0x1;
-
- return VINF_SUCCESS;
-}
-
-/**
- * Returns the number of outstanding stream data bytes which need to be processed
- * by the DMA engine assigned to this stream.
- *
- * @return Number of bytes for the DMA engine to process.
- */
-DECLINLINE(uint32_t) hdaStreamGetTransferSize(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax)
-{
- AssertPtrReturn(pThis, 0);
- AssertPtrReturn(pStrmSt, 0);
-
- if (!cbMax)
- return 0;
-
- PHDABDLE pBDLE = &pStrmSt->State.BDLE;
-
- uint32_t cbFree = pStrmSt->u32CBL - HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
- if (cbFree)
- {
- /* Limit to the available free space of the current BDLE. */
- cbFree = RT_MIN(cbFree, pBDLE->u32BufSize - pBDLE->State.u32BufOff);
-
- /* Make sure we only copy as much as the stream's FIFO can hold (SDFIFOS, 18.2.39). */
- cbFree = RT_MIN(cbFree, pStrmSt->u16FIFOS);
-
- /* Make sure we only transfer as many bytes as requested. */
- cbFree = RT_MIN(cbFree, cbMax);
-
- if (pBDLE->State.cbBelowFIFOW)
- {
- /* Are we not going to reach (or exceed) the FIFO watermark yet with the data to copy?
- * No need to read data from DMA then. */
- if (cbFree > pBDLE->State.cbBelowFIFOW)
- {
- /* Subtract the amount of bytes that still would fit in the stream's FIFO
- * and therefore do not need to be processed by DMA. */
- cbFree -= pBDLE->State.cbBelowFIFOW;
- }
- }
- }
-
- LogFlowFunc(("[SD%RU8]: CBL=%RU32, LPIB=%RU32, cbFree=%RU32, %R[bdle]\n", pStrmSt->u8Strm,
- pStrmSt->u32CBL, HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm), cbFree, pBDLE));
- return cbFree;
-}
-
-DECLINLINE(void) hdaBDLEUpdate(PHDABDLE pBDLE, uint32_t cbData, uint32_t cbProcessed)
-{
- AssertPtrReturnVoid(pBDLE);
-
- if (!cbData || !cbProcessed)
- return;
-
- /* Fewer than cbBelowFIFOW bytes were copied.
- * Probably we need to move the buffer, but it is rather hard to imagine a situation
- * where it might happen. */
- AssertMsg((cbProcessed == pBDLE->State.cbBelowFIFOW + cbData), /* we assume that we write the entire buffer including unreported bytes */
- ("cbProcessed=%RU32 != pBDLE->State.cbBelowFIFOW=%RU32 + cbData=%RU32\n",
- cbProcessed, pBDLE->State.cbBelowFIFOW, cbData));
-
-#if 0
- if ( pBDLE->State.cbBelowFIFOW
- && pBDLE->State.cbBelowFIFOW <= cbWritten)
- {
- LogFlowFunc(("BDLE(cbUnderFifoW:%RU32, off:%RU32, size:%RU32)\n",
- pBDLE->State.cbBelowFIFOW, pBDLE->State.u32BufOff, pBDLE->u32BufSize));
- }
-#endif
-
- pBDLE->State.cbBelowFIFOW -= RT_MIN(pBDLE->State.cbBelowFIFOW, cbProcessed);
- Assert(pBDLE->State.cbBelowFIFOW == 0);
-
- /* We always increment the position of DMA buffer counter because we're always reading
- * into an intermediate buffer. */
- pBDLE->State.u32BufOff += cbData;
- Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
-
- LogFlowFunc(("cbData=%RU32, cbProcessed=%RU32, %R[bdle]\n", cbData, cbProcessed, pBDLE));
-}
-
-DECLINLINE(bool) hdaStreamNeedsNextBDLE(PHDASTATE pThis, PHDASTREAM pStrmSt)
-{
- AssertPtrReturn(pThis, false);
- AssertPtrReturn(pStrmSt, false);
-
- PHDABDLE pBDLE = &pStrmSt->State.BDLE;
- uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
-
- /* Did we reach the CBL (Cyclic Buffer List) limit? */
- bool fCBLLimitReached = u32LPIB >= pStrmSt->u32CBL;
-
- /* Do we need to use the next BDLE entry? Either because we reached
- * the CBL limit or our internal DMA buffer is full. */
- bool fNeedsNextBDLE = ( fCBLLimitReached
- || (pBDLE->State.u32BufOff >= pBDLE->u32BufSize));
-
- Assert(u32LPIB <= pStrmSt->u32CBL);
- Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
-
- LogFlowFunc(("[SD%RU8]: LPIB=%RU32, CBL=%RU32, fCBLLimitReached=%RTbool, fNeedsNextBDLE=%RTbool, %R[bdle]\n",
- pStrmSt->u8Strm, u32LPIB, pStrmSt->u32CBL, fCBLLimitReached, fNeedsNextBDLE, pBDLE));
-
- if (fCBLLimitReached)
- {
- /* Reset LPIB register. */
- u32LPIB -= RT_MIN(u32LPIB, pStrmSt->u32CBL);
- hdaStreamUpdateLPIB(pThis, pStrmSt, u32LPIB);
- }
-
- return fNeedsNextBDLE;
-}
-
-DECLINLINE(void) hdaStreamTransferUpdate(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbInc)
-{
- AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStrmSt);
-
- LogFlowFunc(("[SD%RU8]: cbInc=%RU32\n", pStrmSt->u8Strm, cbInc));
-
- Assert(cbInc <= pStrmSt->u16FIFOS);
-
- PHDABDLE pBDLE = &pStrmSt->State.BDLE;
-
- /*
- * If we're below the FIFO watermark (SDFIFOW), it's expected that HDA
- * doesn't fetch anything via DMA, so just update LPIB.
- * (ICH6 datasheet 18.2.38).
- */
- if (pBDLE->State.cbBelowFIFOW == 0) /* Did we hit (or exceed) the watermark? */
- {
- const uint32_t u32LPIB = RT_MIN(HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) + cbInc,
- pStrmSt->u32CBL);
-
- LogFlowFunc(("[SD%RU8]: LPIB: %RU32 -> %RU32, CBL=%RU32\n",
- pStrmSt->u8Strm,
- HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm), HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm) + cbInc,
- pStrmSt->u32CBL));
-
- hdaStreamUpdateLPIB(pThis, pStrmSt, u32LPIB);
- }
-}
-
-static bool hdaStreamTransferIsComplete(PHDASTATE pThis, PHDASTREAM pStrmSt)
-{
- AssertPtrReturn(pThis, true);
- AssertPtrReturn(pStrmSt, true);
-
- bool fIsComplete = false;
-
- PHDABDLE pBDLE = &pStrmSt->State.BDLE;
- const uint32_t u32LPIB = HDA_STREAM_REG(pThis, LPIB, pStrmSt->u8Strm);
-
- if ( pBDLE->State.u32BufOff >= pBDLE->u32BufSize
- || u32LPIB >= pStrmSt->u32CBL)
- {
- Assert(pBDLE->State.u32BufOff <= pBDLE->u32BufSize);
- Assert(u32LPIB <= pStrmSt->u32CBL);
-
- if (/* IOC (Interrupt On Completion) bit set? */
- pBDLE->fIntOnCompletion
- /* All data put into the DMA FIFO? */
- && pBDLE->State.cbBelowFIFOW == 0
- )
- {
- /**
- * Set the BCIS (Buffer Completion Interrupt Status) flag as the
- * last byte of data for the current descriptor has been fetched
- * from memory and put into the DMA FIFO.
- *
- ** @todo More carefully investigate BCIS flag.
- *
- * Speech synthesis works fine on Mac Guest if this bit isn't set
- * but in general sound quality gets worse.
- */
- HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS);
-
- /*
- * If the ICE (IOCE, "Interrupt On Completion Enable") bit of the SDCTL register is set
- * we need to generate an interrupt.
- */
- if (HDA_STREAM_REG(pThis, CTL, pStrmSt->u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE))
- hdaProcessInterrupt(pThis);
- }
-
- fIsComplete = true;
- }
-
- LogFlowFunc(("[SD%RU8]: u32LPIB=%RU32, CBL=%RU32, %R[bdle] => %s\n",
- pStrmSt->u8Strm, u32LPIB, pStrmSt->u32CBL, pBDLE, fIsComplete ? "COMPLETE" : "INCOMPLETE"));
-
- return fIsComplete;
-}
-
-/**
- * hdaReadAudio - copies samples from audio backend to DMA.
- * Note: This function writes to the DMA buffer immediately,
- * but "reports bytes" when all conditions are met (FIFOW).
- */
-static int hdaReadAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, PAUDMIXSINK pSink, uint32_t cbMax, uint32_t *pcbRead)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- AssertPtrReturn(pSink, VERR_INVALID_POINTER);
- /* pcbRead is optional. */
-
- PHDABDLE pBDLE = &pStrmSt->State.BDLE;
-
- int rc;
- uint32_t cbRead = 0;
- uint32_t cbBuf = hdaStreamGetTransferSize(pThis, pStrmSt, cbMax);
-
- LogFlowFunc(("cbBuf=%RU32, %R[bdle]\n", cbBuf, pBDLE));
-
- if (!cbBuf)
- {
- /* Nothing to write, bail out. */
- rc = VINF_EOF;
- }
- else
- {
- rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pBDLE->State.au8FIFO, cbBuf, &cbRead);
- if (RT_SUCCESS(rc))
- {
- if (!cbRead)
- {
- rc = VINF_EOF;
- }
- else
- {
- /* Sanity checks. */
- Assert(cbRead <= pStrmSt->u16FIFOS);
- Assert(cbRead <= pBDLE->u32BufSize - pBDLE->State.u32BufOff);
-
- /*
- * Write to the BDLE's DMA buffer.
- */
- rc = PDMDevHlpPCIPhysWrite(pThis->CTX_SUFF(pDevIns),
- pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
- pBDLE->State.au8FIFO, cbRead);
- AssertRC(rc);
-
- if (pBDLE->State.cbBelowFIFOW + cbRead > hdaStreamGetFIFOW(pThis, pStrmSt))
- {
- pBDLE->State.u32BufOff += cbRead;
- pBDLE->State.cbBelowFIFOW = 0;
- //hdaBackendReadTransferReported(pBDLE, cbDMAData, cbRead, &cbRead, pcbAvail);
- }
- else
- {
- pBDLE->State.u32BufOff += cbRead;
- pBDLE->State.cbBelowFIFOW += cbRead;
- Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStrmSt));
- //hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbRead, pcbAvail);
-
- rc = VERR_NO_DATA;
- }
- }
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- if (pcbRead)
- *pcbRead = cbRead;
- }
- else
- LogFlowFunc(("Failed with %Rrc\n", rc));
-
- return rc;
-}
-
-static int hdaWriteAudio(PHDASTATE pThis, PHDASTREAM pStrmSt, uint32_t cbMax, uint32_t *pcbWritten)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
- /* pcbWritten is optional. */
-
- PHDABDLE pBDLE = &pStrmSt->State.BDLE;
-
- uint32_t cbWritten = 0;
- uint32_t cbData = hdaStreamGetTransferSize(pThis, pStrmSt, cbMax);
-
- LogFlowFunc(("cbData=%RU32, %R[bdle]\n", cbData, pBDLE));
-
- /*
- * Copy from DMA to the corresponding stream buffer (if there are any bytes from the
- * previous unreported transfer we write at offset 'pBDLE->State.cbUnderFifoW').
- */
- int rc;
- if (!cbData)
- {
- rc = VINF_EOF;
- }
- else
- {
- /*
- * Read from the current BDLE's DMA buffer.
- */
- rc = PDMDevHlpPhysRead(pThis->CTX_SUFF(pDevIns),
- pBDLE->u64BufAdr + pBDLE->State.u32BufOff,
- pBDLE->State.au8FIFO + pBDLE->State.cbBelowFIFOW, cbData);
- AssertRC(rc);
-
-#ifdef VBOX_WITH_STATISTICS
- STAM_COUNTER_ADD(&pThis->StatBytesRead, cbData);
-#endif
- /*
- * Write to audio backend. We should ensure that we have enough bytes to copy to the backend.
- */
- uint32_t cbToWrite = cbData + pBDLE->State.cbBelowFIFOW;
- if (cbToWrite >= hdaStreamGetFIFOW(pThis, pStrmSt))
- {
- uint32_t cbWrittenToStream;
- int rc2;
-
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut))
- {
- rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
- pBDLE->State.au8FIFO, cbToWrite, &cbWrittenToStream);
- if (RT_SUCCESS(rc2))
- {
- if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
- LogFlowFunc(("\tLUN#%RU8: Warning: Only written %RU32 / %RU32 bytes, expect lags\n",
- pDrv->uLUN, cbWrittenToStream, cbToWrite));
- }
- }
- else /* Stream disabled, not fatal. */
- {
- cbWrittenToStream = 0;
- rc2 = VERR_NOT_AVAILABLE;
- /* Keep going. */
- }
-
- LogFlowFunc(("\tLUN#%RU8: cbToWrite=%RU32, cbWrittenToStream=%RU32, rc=%Rrc\n",
- pDrv->uLUN, cbToWrite, cbWrittenToStream, rc2));
- }
-
- /* Always report all data as being written;
- * backends who were not able to catch up have to deal with it themselves. */
- cbWritten = cbToWrite;
-
- hdaBDLEUpdate(pBDLE, cbData, cbWritten);
- }
- else
- {
- pBDLE->State.u32BufOff += cbWritten;
- pBDLE->State.cbBelowFIFOW += cbWritten;
- Assert(pBDLE->State.cbBelowFIFOW <= hdaStreamGetFIFOW(pThis, pStrmSt));
-
- /* Not enough bytes to be processed and reported, we'll try our luck next time around. */
- //hdaBackendTransferUnreported(pThis, pBDLE, pStreamDesc, cbAvail, NULL);
- rc = VINF_EOF;
- }
- }
-
- Assert(cbWritten <= pStrmSt->u16FIFOS);
-
- if (RT_SUCCESS(rc))
- {
- if (pcbWritten)
- *pcbWritten = cbWritten;
- }
-
- LogFunc(("Returning cbWritten=%RU32, rc=%Rrc\n", cbWritten, rc));
- return rc;
-}
-
-/**
- * @interface_method_impl{HDACODEC,pfnReset}
- */
-static DECLCALLBACK(int) hdaCodecReset(PHDACODEC pCodec)
-{
- PHDASTATE pThis = pCodec->pHDAState;
- NOREF(pThis);
- return VINF_SUCCESS;
-}
-
-
-static DECLCALLBACK(void) hdaCloseIn(PHDASTATE pThis, PDMAUDIORECSOURCE enmRecSource)
-{
- NOREF(pThis);
- NOREF(enmRecSource);
- LogFlowFuncEnter();
-}
-
-static DECLCALLBACK(void) hdaCloseOut(PHDASTATE pThis)
-{
- NOREF(pThis);
- LogFlowFuncEnter();
-}
-
-static DECLCALLBACK(int) hdaOpenIn(PHDASTATE pThis,
- const char *pszName, PDMAUDIORECSOURCE enmRecSource,
- PPDMAUDIOSTREAMCFG pCfg)
-{
- PAUDMIXSINK pSink;
-
- switch (enmRecSource)
- {
-# ifdef VBOX_WITH_HDA_MIC_IN
- case PDMAUDIORECSOURCE_MIC:
- pSink = pThis->pSinkMicIn;
- break;
-# endif
- case PDMAUDIORECSOURCE_LINE_IN:
- pSink = pThis->pSinkLineIn;
- break;
- default:
- AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
- return VERR_NOT_SUPPORTED;
- }
-
- int rc = VINF_SUCCESS;
- char *pszDesc;
-
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pszName) <= 0)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
- rc = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, enmRecSource, pCfg, &pDrv->LineIn.pStrmIn);
- LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
- if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
- {
- AudioMixerRemoveStream(pSink, pDrv->LineIn.phStrmIn);
- rc = AudioMixerAddStreamIn(pSink,
- pDrv->pConnector, pDrv->LineIn.pStrmIn,
- 0 /* uFlags */, &pDrv->LineIn.phStrmIn);
- }
-
- RTStrFree(pszDesc);
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) hdaOpenOut(PHDASTATE pThis,
- const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
-{
- int rc = VINF_SUCCESS;
- char *pszDesc;
-
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
- pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel") <= 0)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
- rc = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
- LogFlowFunc(("LUN#%RU8: Created output \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
- if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
- {
- AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
- rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
- pDrv->pConnector, pDrv->Out.pStrmOut,
- 0 /* uFlags */, &pDrv->Out.phStrmOut);
- }
-
- RTStrFree(pszDesc);
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) hdaSetVolume(PHDASTATE pThis, ENMSOUNDSOURCE enmSource,
- bool fMute, uint8_t uVolLeft, uint8_t uVolRight)
-{
- int rc = VINF_SUCCESS;
- PDMAUDIOVOLUME vol = { fMute, uVolLeft, uVolRight };
- PAUDMIXSINK pSink;
-
- /* Convert the audio source to corresponding sink. */
- switch (enmSource)
- {
- case PO_INDEX:
- pSink = pThis->pSinkOutput;
- break;
- case PI_INDEX:
- pSink = pThis->pSinkLineIn;
- break;
- case MC_INDEX:
- pSink = pThis->pSinkMicIn;
- break;
- default:
- AssertFailedReturn(VERR_INVALID_PARAMETER);
- break;
- }
-
- /* Set the volume. Codec already converted it to the correct range. */
- AudioMixerSetSinkVolume(pSink, &vol);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
-
-static DECLCALLBACK(void) hdaTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
-{
- RT_NOREF(pDevIns);
- PHDASTATE pThis = (PHDASTATE)pvUser;
- Assert(pThis == PDMINS_2_DATA(pDevIns, PHDASTATE));
- AssertPtr(pThis);
-
- STAM_PROFILE_START(&pThis->StatTimer, a);
-
- uint32_t cbInMax = 0;
- uint32_t cbOutMin = UINT32_MAX;
-
- PHDADRIVER pDrv;
-
- uint64_t cTicksNow = TMTimerGet(pTimer);
- uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS;
- uint64_t cTicksPerSec = TMTimerGetFreq(pTimer);
-
- pThis->uTimerTS = cTicksNow;
-
- /*
- * Calculate the codec's (fixed) sampling rate.
- */
- AssertPtr(pThis->pCodec);
- PDMPCMPROPS codecStrmProps;
-
- int rc = DrvAudioStreamCfgToProps(&pThis->pCodec->strmCfg, &codecStrmProps);
- AssertRC(rc);
-
- uint32_t cCodecSamplesMin = (int)((2 * cTicksElapsed * pThis->pCodec->strmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
- uint32_t cbCodecSamplesMin = cCodecSamplesMin << codecStrmProps.cShift;
-
- /*
- * Process all driver nodes.
- */
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- uint32_t cbIn = 0;
- uint32_t cbOut = 0;
-
- rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector, &cbIn, &cbOut, NULL /* pcSamplesLive */);
- if (RT_SUCCESS(rc))
- rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* pcSamplesPlayed */);
-
- Log3Func(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
-
- /* If we there was an error handling (available) output or there simply is no output available,
- * then calculate the minimum data rate which must be processed by the device emulation in order
- * to function correctly.
- *
- * This is not the optimal solution, but as we have to deal with this on a timer-based approach
- * (until we have the audio callbacks) we need to have device' DMA engines running. */
- if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
- {
- /* Use the codec's (fixed) sampling rate. */
- cbOut = RT_MAX(cbOut, cbCodecSamplesMin);
- }
- else
- {
- const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
- if ( RT_FAILURE(rc)
- || !fIsActiveOut)
- {
- uint32_t cSamplesMin = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
- uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
-
- Log3Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
-
- cbOut = RT_MAX(cbOut, cbSamplesMin);
- }
- }
-
- cbOutMin = RT_MIN(cbOutMin, cbOut);
- cbInMax = RT_MAX(cbInMax, cbIn);
- }
-
- Log3Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
-
- if (cbOutMin == UINT32_MAX)
- cbOutMin = 0;
-
- /*
- * Playback.
- */
- if (cbOutMin)
- {
- Assert(cbOutMin != UINT32_MAX);
- hdaTransfer(pThis, PO_INDEX, cbOutMin /* cbToProcess */, NULL /* pcbProcessed */);
- }
-
- /*
- * Recording.
- */
- if (cbInMax)
- hdaTransfer(pThis, PI_INDEX, cbInMax /* cbToProcess */, NULL /* pcbProcessed */);
-
- /* Kick the timer again. */
- uint64_t cTicks = pThis->cTimerTicks;
- /** @todo adjust cTicks down by now much cbOutMin represents. */
- TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
-
- STAM_PROFILE_STOP(&pThis->StatTimer, a);
-}
-
-#else /* VBOX_WITH_AUDIO_CALLBACKS */
-
-static DECLCALLBACK(int) hdaCallbackInput(PDMAUDIOCALLBACKTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser)
-{
- Assert(enmType == PDMAUDIOCALLBACKTYPE_INPUT);
- AssertPtrReturn(pvCtx, VERR_INVALID_POINTER);
- AssertReturn(cbCtx, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
- AssertReturn(cbUser, VERR_INVALID_PARAMETER);
-
- PHDACALLBACKCTX pCtx = (PHDACALLBACKCTX)pvCtx;
- AssertReturn(cbCtx == sizeof(HDACALLBACKCTX), VERR_INVALID_PARAMETER);
-
- PPDMAUDIOCALLBACKDATAIN pData = (PPDMAUDIOCALLBACKDATAIN)pvUser;
- AssertReturn(cbUser == sizeof(PDMAUDIOCALLBACKDATAIN), VERR_INVALID_PARAMETER);
-
- return hdaTransfer(pCtx->pThis, PI_INDEX, UINT32_MAX, &pData->cbOutRead);
-}
-
-static DECLCALLBACK(int) hdaCallbackOutput(PDMAUDIOCALLBACKTYPE enmType, void *pvCtx, size_t cbCtx, void *pvUser, size_t cbUser)
-{
- Assert(enmType == PDMAUDIOCALLBACKTYPE_OUTPUT);
- AssertPtrReturn(pvCtx, VERR_INVALID_POINTER);
- AssertReturn(cbCtx, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
- AssertReturn(cbUser, VERR_INVALID_PARAMETER);
-
- PHDACALLBACKCTX pCtx = (PHDACALLBACKCTX)pvCtx;
- AssertReturn(cbCtx == sizeof(HDACALLBACKCTX), VERR_INVALID_PARAMETER);
-
- PPDMAUDIOCALLBACKDATAOUT pData = (PPDMAUDIOCALLBACKDATAOUT)pvUser;
- AssertReturn(cbUser == sizeof(PDMAUDIOCALLBACKDATAOUT), VERR_INVALID_PARAMETER);
-
- PHDASTATE pThis = pCtx->pThis;
-
- int rc = hdaTransfer(pCtx->pThis, PO_INDEX, UINT32_MAX, &pData->cbOutWritten);
- if ( RT_SUCCESS(rc)
- && pData->cbOutWritten)
- {
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- uint32_t cSamplesPlayed;
- int rc2 = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, &cSamplesPlayed);
- LogFlowFunc(("LUN#%RU8: cSamplesPlayed=%RU32, rc=%Rrc\n", pDrv->uLUN, cSamplesPlayed, rc2));
- }
- }
-}
-#endif /* VBOX_WITH_AUDIO_CALLBACKS */
-
-static int hdaTransfer(PHDASTATE pThis, ENMSOUNDSOURCE enmSrc, uint32_t cbToProcess, uint32_t *pcbProcessed)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- /* pcbProcessed is optional. */
-
- if (ASMAtomicReadBool(&pThis->fInReset)) /* HDA controller in reset mode? Bail out. */
- {
- LogFlowFunc(("In reset mode, skipping\n"));
-
- if (pcbProcessed)
- *pcbProcessed = 0;
- return VINF_SUCCESS;
- }
-
- PHDASTREAM pStrmSt;
- switch (enmSrc)
- {
- case PI_INDEX:
- {
- pStrmSt = &pThis->StrmStLineIn;
- break;
- }
-
-#ifdef VBOX_WITH_HDA_MIC_IN
- case MC_INDEX:
- {
- pStrmSt = &pThis->StrmStMicIn;
- break;
- }
-#endif
- case PO_INDEX:
- {
- pStrmSt = &pThis->StrmStOut;
- break;
- }
-
- default:
- {
- AssertMsgFailed(("Unknown source index %ld\n", enmSrc));
- return VERR_NOT_SUPPORTED;
- }
- }
-
- int rc = VINF_SUCCESS;
- bool fProceed = true;
-
- /* Stop request received? */
- if (ASMAtomicReadBool(&pStrmSt->State.fDoStop))
- {
- pStrmSt->State.fActive = false;
-
- rc = RTSemEventSignal(pStrmSt->State.hStateChangedEvent);
- AssertRC(rc);
-
- fProceed = false;
- }
- /* Is the stream not in a running state currently? */
- else if (!(HDA_STREAM_REG(pThis, CTL, pStrmSt->u8Strm) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)))
- fProceed = false;
- /* Nothing to process? */
- else if (!cbToProcess)
- fProceed = false;
-
- if (!fProceed)
- {
- if (pcbProcessed)
- *pcbProcessed = 0;
- return VINF_SUCCESS;
- }
-
- LogFlowFunc(("enmSrc=%RU32, cbToProcess=%RU32\n", enmSrc, cbToProcess));
-
- /* Sanity checks. */
- Assert(pStrmSt->u8Strm <= 7); /** @todo Use a define for MAX_STREAMS! */
- Assert(pStrmSt->u64BDLBase);
- Assert(pStrmSt->u32CBL);
-
- /* State sanity checks. */
- Assert(ASMAtomicReadBool(&pStrmSt->State.fInReset) == false);
-
- uint32_t cbProcessedTotal = 0;
- bool fIsComplete = false;
-
- while (cbToProcess)
- {
- /* Do we need to fetch the next Buffer Descriptor Entry (BDLE)? */
- if (hdaStreamNeedsNextBDLE(pThis, pStrmSt))
- hdaStreamGetNextBDLE(pThis, pStrmSt);
-
- /* Set the FIFORDY bit on the stream while doing the transfer. */
- HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) |= HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
-
- uint32_t cbProcessed = 0;
- switch (enmSrc)
- {
- case PI_INDEX:
- rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkLineIn, cbToProcess, &cbProcessed);
- break;
- case PO_INDEX:
- rc = hdaWriteAudio(pThis, pStrmSt, cbToProcess, &cbProcessed);
- break;
-#ifdef VBOX_WITH_HDA_MIC_IN
- case MC_INDEX:
- rc = hdaReadAudio(pThis, pStrmSt, pThis->pSinkMicIn, cbToProcess, &cbProcessed);
- break;
-#endif
- default:
- AssertMsgFailed(("Unsupported source index %ld\n", enmSrc));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- /* Remove the FIFORDY bit again. */
- HDA_STREAM_REG(pThis, STS, pStrmSt->u8Strm) &= ~HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY);
-
- if (RT_FAILURE(rc))
- break;
-
- hdaStreamTransferUpdate(pThis, pStrmSt, cbProcessed);
-
- cbToProcess -= RT_MIN(cbToProcess, cbProcessed);
- cbProcessedTotal += cbProcessed;
-
- LogFlowFunc(("cbProcessed=%RU32, cbToProcess=%RU32, cbProcessedTotal=%RU32, rc=%Rrc\n",
- cbProcessed, cbToProcess, cbProcessedTotal, rc));
-
- if (rc == VINF_EOF)
- fIsComplete = true;
-
- if (!fIsComplete)
- fIsComplete = hdaStreamTransferIsComplete(pThis, pStrmSt);
-
- if (fIsComplete)
- break;
- }
-
- if (RT_SUCCESS(rc))
- {
- if (pcbProcessed)
- *pcbProcessed = cbProcessedTotal;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-#endif /* IN_RING3 */
-
-/* MMIO callbacks */
-
-/**
- * @callback_method_impl{FNIOMMMIOREAD, Looks up and calls the appropriate handler.}
- *
- * @note During implementation, we discovered so-called "forgotten" or "hole"
- * registers whose description is not listed in the RPM, datasheet, or
- * spec.
- */
-PDMBOTHCBDECL(int) hdaMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
-{
- RT_NOREF(pvUser);
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- int rc;
-
- /*
- * Look up and log.
- */
- uint32_t offReg = GCPhysAddr - pThis->MMIOBaseAddr;
- int idxRegDsc = hdaRegLookup(pThis, offReg); /* Register descriptor index. */
-#ifdef LOG_ENABLED
- unsigned const cbLog = cb;
- uint32_t offRegLog = offReg;
-#endif
-
- LogFunc(("offReg=%#x cb=%#x\n", offReg, cb));
- Assert(cb == 4); Assert((offReg & 3) == 0);
-
- if (pThis->fInReset && idxRegDsc != HDA_REG_GCTL)
- LogFunc(("\tAccess to registers except GCTL is blocked while reset\n"));
-
- if (idxRegDsc == -1)
- LogRel(("HDA: Invalid read access @0x%x (bytes=%d)\n", offReg, cb));
-
- if (idxRegDsc != -1)
- {
- /* ASSUMES gapless DWORD at end of map. */
- if (g_aHdaRegMap[idxRegDsc].size == 4)
- {
- /*
- * Straight forward DWORD access.
- */
- rc = g_aHdaRegMap[idxRegDsc].pfnRead(pThis, idxRegDsc, (uint32_t *)pv);
- LogFunc(("\tRead %s => %x (%Rrc)\n", g_aHdaRegMap[idxRegDsc].abbrev, *(uint32_t *)pv, rc));
- }
- else
- {
- /*
- * Multi register read (unless there are trailing gaps).
- * ASSUMES that only DWORD reads have sideeffects.
- */
- uint32_t u32Value = 0;
- unsigned cbLeft = 4;
- do
- {
- uint32_t const cbReg = g_aHdaRegMap[idxRegDsc].size;
- uint32_t u32Tmp = 0;
-
- rc = g_aHdaRegMap[idxRegDsc].pfnRead(pThis, idxRegDsc, &u32Tmp);
- LogFunc(("\tRead %s[%db] => %x (%Rrc)*\n", g_aHdaRegMap[idxRegDsc].abbrev, cbReg, u32Tmp, rc));
- if (rc != VINF_SUCCESS)
- break;
- u32Value |= (u32Tmp & g_afMasks[cbReg]) << ((4 - cbLeft) * 8);
-
- cbLeft -= cbReg;
- offReg += cbReg;
- idxRegDsc++;
- } while (cbLeft > 0 && g_aHdaRegMap[idxRegDsc].offset == offReg);
-
- if (rc == VINF_SUCCESS)
- *(uint32_t *)pv = u32Value;
- else
- Assert(!IOM_SUCCESS(rc));
- }
- }
- else
- {
- rc = VINF_IOM_MMIO_UNUSED_FF;
- LogFunc(("\tHole at %x is accessed for read\n", offReg));
- }
-
- /*
- * Log the outcome.
- */
-#ifdef LOG_ENABLED
- if (cbLog == 4)
- LogFunc(("\tReturning @%#05x -> %#010x %Rrc\n", offRegLog, *(uint32_t *)pv, rc));
- else if (cbLog == 2)
- LogFunc(("\tReturning @%#05x -> %#06x %Rrc\n", offRegLog, *(uint16_t *)pv, rc));
- else if (cbLog == 1)
- LogFunc(("\tReturning @%#05x -> %#04x %Rrc\n", offRegLog, *(uint8_t *)pv, rc));
-#endif
- return rc;
-}
-
-
-DECLINLINE(int) hdaWriteReg(PHDASTATE pThis, int idxRegDsc, uint32_t u32Value, char const *pszLog)
-{
- RT_NOREF(pszLog);
- if (pThis->fInReset && idxRegDsc != HDA_REG_GCTL)
- {
- LogRel2(("HDA: Access to register 0x%x is blocked while reset\n", idxRegDsc));
- return VINF_SUCCESS;
- }
-
-#ifdef LOG_ENABLED
- uint32_t idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
- uint32_t const u32CurValue = pThis->au32Regs[idxRegMem];
-#endif
- int rc = g_aHdaRegMap[idxRegDsc].pfnWrite(pThis, idxRegDsc, u32Value);
- LogFunc(("write %#x -> %s[%db]; %x => %x%s\n", u32Value, g_aHdaRegMap[idxRegDsc].abbrev,
- g_aHdaRegMap[idxRegDsc].size, u32CurValue, pThis->au32Regs[idxRegMem], pszLog));
- return rc;
-}
-
-
-/**
- * @callback_method_impl{FNIOMMMIOWRITE, Looks up and calls the appropriate handler.}
- */
-PDMBOTHCBDECL(int) hdaMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
-{
- RT_NOREF(pvUser);
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- int rc;
-
- /*
- * The behavior of accesses that aren't aligned on natural boundraries is
- * undefined. Just reject them outright.
- */
- /** @todo IOM could check this, it could also split the 8 byte accesses for us. */
- Assert(cb == 1 || cb == 2 || cb == 4 || cb == 8);
- if (GCPhysAddr & (cb - 1))
- return PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "misaligned write access: GCPhysAddr=%RGp cb=%u\n", GCPhysAddr, cb);
-
- /*
- * Look up and log the access.
- */
- uint32_t offReg = GCPhysAddr - pThis->MMIOBaseAddr;
- int idxRegDsc = hdaRegLookup(pThis, offReg);
- uint32_t idxRegMem = idxRegDsc != -1 ? g_aHdaRegMap[idxRegDsc].mem_idx : UINT32_MAX;
- uint64_t u64Value;
- if (cb == 4) u64Value = *(uint32_t const *)pv;
- else if (cb == 2) u64Value = *(uint16_t const *)pv;
- else if (cb == 1) u64Value = *(uint8_t const *)pv;
- else if (cb == 8) u64Value = *(uint64_t const *)pv;
- else
- {
- u64Value = 0; /* shut up gcc. */
- AssertReleaseMsgFailed(("%u\n", cb));
- }
-
-#ifdef LOG_ENABLED
- uint32_t const u32LogOldValue = idxRegDsc >= 0 ? pThis->au32Regs[idxRegMem] : UINT32_MAX;
- if (idxRegDsc == -1)
- LogFunc(("@%#05x u32=%#010x cb=%d\n", offReg, *(uint32_t const *)pv, cb));
- else if (cb == 4)
- LogFunc(("@%#05x u32=%#010x %s\n", offReg, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
- else if (cb == 2)
- LogFunc(("@%#05x u16=%#06x (%#010x) %s\n", offReg, *(uint16_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
- else if (cb == 1)
- LogFunc(("@%#05x u8=%#04x (%#010x) %s\n", offReg, *(uint8_t *)pv, *(uint32_t *)pv, g_aHdaRegMap[idxRegDsc].abbrev));
-
- if (idxRegDsc >= 0 && g_aHdaRegMap[idxRegDsc].size != cb)
- LogFunc(("\tsize=%RU32 != cb=%u!!\n", g_aHdaRegMap[idxRegDsc].size, cb));
-#endif
-
- /*
- * Try for a direct hit first.
- */
- if (idxRegDsc != -1 && g_aHdaRegMap[idxRegDsc].size == cb)
- {
- rc = hdaWriteReg(pThis, idxRegDsc, u64Value, "");
-#ifdef LOG_ENABLED
- LogFunc(("\t%#x -> %#x\n", u32LogOldValue, idxRegMem != UINT32_MAX ? pThis->au32Regs[idxRegMem] : UINT32_MAX));
-#endif
- }
- /*
- * Partial or multiple register access, loop thru the requested memory.
- */
- else
- {
- /*
- * If it's an access beyond the start of the register, shift the input
- * value and fill in missing bits. Natural alignment rules means we
- * will only see 1 or 2 byte accesses of this kind, so no risk of
- * shifting out input values.
- */
- if (idxRegDsc == -1 && (idxRegDsc = hdaRegLookupWithin(pThis, offReg)) != -1)
- {
- uint32_t const cbBefore = offReg - g_aHdaRegMap[idxRegDsc].offset; Assert(cbBefore > 0 && cbBefore < 4);
- offReg -= cbBefore;
- idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
- u64Value <<= cbBefore * 8;
- u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbBefore];
- LogFunc(("\tWithin register, supplied %u leading bits: %#llx -> %#llx ...\n",
- cbBefore * 8, ~g_afMasks[cbBefore] & u64Value, u64Value));
- }
-
- /* Loop thru the write area, it may cover multiple registers. */
- rc = VINF_SUCCESS;
- for (;;)
- {
- uint32_t cbReg;
- if (idxRegDsc != -1)
- {
- idxRegMem = g_aHdaRegMap[idxRegDsc].mem_idx;
- cbReg = g_aHdaRegMap[idxRegDsc].size;
- if (cb < cbReg)
- {
- u64Value |= pThis->au32Regs[idxRegMem] & g_afMasks[cbReg] & ~g_afMasks[cb];
- LogFunc(("\tSupplying missing bits (%#x): %#llx -> %#llx ...\n",
- g_afMasks[cbReg] & ~g_afMasks[cb], u64Value & g_afMasks[cb], u64Value));
- }
-#ifdef LOG_ENABLED
- uint32_t const u32LogOldVal = pThis->au32Regs[idxRegMem];
-#endif
- rc = hdaWriteReg(pThis, idxRegDsc, u64Value, "*");
- LogFunc(("\t%#x -> %#x\n", u32LogOldVal, pThis->au32Regs[idxRegMem]));
- }
- else
- {
- LogRel(("HDA: Invalid write access @0x%x\n", offReg));
- cbReg = 1;
- }
- if (rc != VINF_SUCCESS)
- break;
- if (cbReg >= cb)
- break;
-
- /* Advance. */
- offReg += cbReg;
- cb -= cbReg;
- u64Value >>= cbReg * 8;
- if (idxRegDsc == -1)
- idxRegDsc = hdaRegLookup(pThis, offReg);
- else
- {
- idxRegDsc++;
- if ( (unsigned)idxRegDsc >= RT_ELEMENTS(g_aHdaRegMap)
- || g_aHdaRegMap[idxRegDsc].offset != offReg)
- {
- idxRegDsc = -1;
- }
- }
- }
- }
-
- return rc;
-}
-
-
-/* PCI callback. */
-
-#ifdef IN_RING3
-/**
- * @callback_method_impl{FNPCIIOREGIONMAP}
- */
-static DECLCALLBACK(int) hdaPciIoRegionMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
- RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
-{
- RT_NOREF(iRegion, enmType);
- PHDASTATE pThis = RT_FROM_MEMBER(pPciDev, HDASTATE, PciDev);
-
- /*
- * 18.2 of the ICH6 datasheet defines the valid access widths as byte, word, and double word.
- *
- * Let IOM talk DWORDs when reading, saves a lot of complications. On
- * writing though, we have to do it all ourselves because of sideeffects.
- */
- Assert(enmType == PCI_ADDRESS_SPACE_MEM);
- int rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
- IOMMMIO_FLAGS_READ_DWORD
- | IOMMMIO_FLAGS_WRITE_PASSTHRU,
- hdaMMIOWrite, hdaMMIORead, "HDA");
-
- if (RT_FAILURE(rc))
- return rc;
-
- if (pThis->fR0Enabled)
- {
- rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/,
- "hdaMMIOWrite", "hdaMMIORead");
- if (RT_FAILURE(rc))
- return rc;
- }
-
- if (pThis->fRCEnabled)
- {
- rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
- "hdaMMIOWrite", "hdaMMIORead");
- if (RT_FAILURE(rc))
- return rc;
- }
-
- pThis->MMIOBaseAddr = GCPhysAddress;
- return VINF_SUCCESS;
-}
-
-
-/* Saved state callbacks. */
-
-static int hdaSaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PHDASTREAM pStrm)
-{
- RT_NOREF(pDevIns);
-#ifdef VBOX_STRICT
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-#endif
-
- LogFlowFunc(("[SD%RU8]\n", pStrm->u8Strm));
-
- /* Save stream ID. */
- int rc = SSMR3PutU8(pSSM, pStrm->u8Strm);
- AssertRCReturn(rc, rc);
- Assert(pStrm->u8Strm <= 7); /** @todo Use a define. */
-
- rc = SSMR3PutStructEx(pSSM, &pStrm->State, sizeof(HDASTREAMSTATE), 0 /*fFlags*/, g_aSSMStreamStateFields6, NULL);
- AssertRCReturn(rc, rc);
-
-#ifdef VBOX_STRICT /* Sanity checks. */
- uint64_t u64BaseDMA = RT_MAKE_U64(HDA_STREAM_REG(pThis, BDPL, pStrm->u8Strm),
- HDA_STREAM_REG(pThis, BDPU, pStrm->u8Strm));
- uint16_t u16LVI = HDA_STREAM_REG(pThis, LVI, pStrm->u8Strm);
- uint32_t u32CBL = HDA_STREAM_REG(pThis, CBL, pStrm->u8Strm);
-
- hdaBDLEDumpAll(pThis, u64BaseDMA, u16LVI + 1);
-
- Assert(u64BaseDMA == pStrm->u64BDLBase);
- Assert(u16LVI == pStrm->u16LVI);
- Assert(u32CBL == pStrm->u32CBL);
-#endif
-
- rc = SSMR3PutStructEx(pSSM, &pStrm->State.BDLE, sizeof(HDABDLE),
- 0 /*fFlags*/, g_aSSMBDLEFields6, NULL);
- AssertRCReturn(rc, rc);
-
- rc = SSMR3PutStructEx(pSSM, &pStrm->State.BDLE.State, sizeof(HDABDLESTATE),
- 0 /*fFlags*/, g_aSSMBDLEStateFields6, NULL);
- AssertRCReturn(rc, rc);
-
-#ifdef VBOX_STRICT /* Sanity checks. */
- PHDABDLE pBDLE = &pStrm->State.BDLE;
- if (u64BaseDMA)
- {
- Assert(pStrm->State.uCurBDLE <= u16LVI + 1);
-
- HDABDLE curBDLE;
- rc = hdaBDLEFetch(pThis, &curBDLE, u64BaseDMA, pStrm->State.uCurBDLE);
- AssertRC(rc);
-
- Assert(curBDLE.u32BufSize == pBDLE->u32BufSize);
- Assert(curBDLE.u64BufAdr == pBDLE->u64BufAdr);
- Assert(curBDLE.fIntOnCompletion == pBDLE->fIntOnCompletion);
- }
- else
- {
- Assert(pBDLE->u64BufAdr == 0);
- Assert(pBDLE->u32BufSize == 0);
- }
-#endif
- return rc;
-}
-
-/**
- * @callback_method_impl{FNSSMDEVSAVEEXEC}
- */
-static DECLCALLBACK(int) hdaSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- /* Save Codec nodes states. */
- hdaCodecSaveState(pThis->pCodec, pSSM);
-
- /* Save MMIO registers. */
- AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= HDA_NREGS_SAVED);
- SSMR3PutU32(pSSM, RT_ELEMENTS(pThis->au32Regs));
- SSMR3PutMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
-
- /* Save number of streams. */
-#ifdef VBOX_WITH_HDA_MIC_IN
- SSMR3PutU32(pSSM, 3);
-#else
- SSMR3PutU32(pSSM, 2);
-#endif
-
- /* Save stream states. */
- int rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStOut);
- AssertRCReturn(rc, rc);
-#ifdef VBOX_WITH_HDA_MIC_IN
- rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStMicIn);
- AssertRCReturn(rc, rc);
-#endif
- rc = hdaSaveStream(pDevIns, pSSM, &pThis->StrmStLineIn);
- AssertRCReturn(rc, rc);
-
- return rc;
-}
-
-
-/**
- * @callback_method_impl{FNSSMDEVLOADEXEC}
- */
-static DECLCALLBACK(int) hdaLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
-
- LogRel2(("hdaLoadExec: uVersion=%RU32, uPass=0x%x\n", uVersion, uPass));
-
- /*
- * Load Codec nodes states.
- */
- int rc = hdaCodecLoadState(pThis->pCodec, pSSM, uVersion);
- if (RT_FAILURE(rc))
- {
- LogRel(("HDA: Failed loading codec state (version %RU32, pass 0x%x), rc=%Rrc\n", uVersion, uPass, rc));
- return rc;
- }
-
- /*
- * Load MMIO registers.
- */
- uint32_t cRegs;
- switch (uVersion)
- {
- case HDA_SSM_VERSION_1:
- /* Starting with r71199, we would save 112 instead of 113
- registers due to some code cleanups. This only affected trunk
- builds in the 4.1 development period. */
- cRegs = 113;
- if (SSMR3HandleRevision(pSSM) >= 71199)
- {
- uint32_t uVer = SSMR3HandleVersion(pSSM);
- if ( VBOX_FULL_VERSION_GET_MAJOR(uVer) == 4
- && VBOX_FULL_VERSION_GET_MINOR(uVer) == 0
- && VBOX_FULL_VERSION_GET_BUILD(uVer) >= 51)
- cRegs = 112;
- }
- break;
-
- case HDA_SSM_VERSION_2:
- case HDA_SSM_VERSION_3:
- cRegs = 112;
- AssertCompile(RT_ELEMENTS(pThis->au32Regs) >= HDA_NREGS_SAVED);
- break;
-
- /* Since version 4 we store the register count to stay flexible. */
- case HDA_SSM_VERSION_4:
- case HDA_SSM_VERSION_5:
- case HDA_SSM_VERSION:
- rc = SSMR3GetU32(pSSM, &cRegs); AssertRCReturn(rc, rc);
- if (cRegs != RT_ELEMENTS(pThis->au32Regs))
- LogRel(("HDA: SSM version cRegs is %RU32, expected %RU32\n", cRegs, RT_ELEMENTS(pThis->au32Regs)));
- break;
-
- default:
- LogRel(("HDA: Unsupported / too new saved state version (%RU32)\n", uVersion));
- return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
- }
-
- if (cRegs >= RT_ELEMENTS(pThis->au32Regs))
- {
- SSMR3GetMem(pSSM, pThis->au32Regs, sizeof(pThis->au32Regs));
- SSMR3Skip(pSSM, sizeof(uint32_t) * (cRegs - RT_ELEMENTS(pThis->au32Regs)));
- }
- else
- SSMR3GetMem(pSSM, pThis->au32Regs, sizeof(uint32_t) * cRegs);
-
- /*
- * Note: Saved states < v5 store LVI (u32BdleMaxCvi) for
- * *every* BDLE state, whereas it only needs to be stored
- * *once* for every stream. Most of the BDLE state we can
- * get out of the registers anyway, so just ignore those values.
- *
- * Also, only the current BDLE was saved, regardless whether
- * there were more than one (and there are at least two entries,
- * according to the spec).
- */
-#define HDA_SSM_LOAD_BDLE_STATE_PRE_V5(v, x) \
- rc = SSMR3Skip(pSSM, sizeof(uint32_t)); /* Begin marker */ \
- AssertRCReturn(rc, rc); \
- rc = SSMR3GetU64(pSSM, &x.u64BufAdr); /* u64BdleCviAddr */ \
- AssertRCReturn(rc, rc); \
- rc = SSMR3Skip(pSSM, sizeof(uint32_t)); /* u32BdleMaxCvi */ \
- AssertRCReturn(rc, rc); \
- rc = SSMR3GetU32(pSSM, &x.State.u32BDLIndex); /* u32BdleCvi */ \
- AssertRCReturn(rc, rc); \
- rc = SSMR3GetU32(pSSM, &x.u32BufSize); /* u32BdleCviLen */ \
- AssertRCReturn(rc, rc); \
- rc = SSMR3GetU32(pSSM, &x.State.u32BufOff); /* u32BdleCviPos */ \
- AssertRCReturn(rc, rc); \
- rc = SSMR3GetBool(pSSM, &x.fIntOnCompletion); /* fBdleCviIoc */ \
- AssertRCReturn(rc, rc); \
- rc = SSMR3GetU32(pSSM, &x.State.cbBelowFIFOW); /* cbUnderFifoW */ \
- AssertRCReturn(rc, rc); \
- rc = SSMR3GetMem(pSSM, &x.State.au8FIFO, sizeof(x.State.au8FIFO)); \
- AssertRCReturn(rc, rc); \
- rc = SSMR3Skip(pSSM, sizeof(uint32_t)); /* End marker */ \
- AssertRCReturn(rc, rc); \
-
- /*
- * Load BDLEs (Buffer Descriptor List Entries) and DMA counters.
- */
- switch (uVersion)
- {
- case HDA_SSM_VERSION_1:
- case HDA_SSM_VERSION_2:
- case HDA_SSM_VERSION_3:
- case HDA_SSM_VERSION_4:
- {
- /* Only load the internal states.
- * The rest will be initialized from the saved registers later. */
-
- /* Note 1: Only the *current* BDLE for a stream was saved! */
- /* Note 2: The stream's saving order is/was fixed, so don't touch! */
-
- /* Output */
- rc = hdaStreamInit(pThis, &pThis->StrmStOut, 4 /* Stream number, hardcoded */);
- if (RT_FAILURE(rc))
- break;
- HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStOut.State.BDLE);
- pThis->StrmStOut.State.uCurBDLE = pThis->StrmStOut.State.BDLE.State.u32BDLIndex;
-
- /* Microphone-In */
- rc = hdaStreamInit(pThis, &pThis->StrmStMicIn, 2 /* Stream number, hardcoded */);
- if (RT_FAILURE(rc))
- break;
- HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStMicIn.State.BDLE);
- pThis->StrmStMicIn.State.uCurBDLE = pThis->StrmStMicIn.State.BDLE.State.u32BDLIndex;
-
- /* Line-In */
- rc = hdaStreamInit(pThis, &pThis->StrmStLineIn, 0 /* Stream number, hardcoded */);
- if (RT_FAILURE(rc))
- break;
- HDA_SSM_LOAD_BDLE_STATE_PRE_V5(uVersion, pThis->StrmStLineIn.State.BDLE);
- pThis->StrmStLineIn.State.uCurBDLE = pThis->StrmStLineIn.State.BDLE.State.u32BDLIndex;
- break;
- }
-
- /* Since v5 we support flexible stream and BDLE counts. */
- case HDA_SSM_VERSION_5:
- case HDA_SSM_VERSION:
- {
- uint32_t cStreams;
- rc = SSMR3GetU32(pSSM, &cStreams);
- if (RT_FAILURE(rc))
- break;
-
- LogRel2(("hdaLoadExec: cStreams=%RU32\n", cStreams));
-
- /* Load stream states. */
- for (uint32_t i = 0; i < cStreams; i++)
- {
- uint8_t uStreamID;
- rc = SSMR3GetU8(pSSM, &uStreamID);
- if (RT_FAILURE(rc))
- break;
-
- PHDASTREAM pStrm = hdaStreamFromID(pThis, uStreamID);
- HDASTREAM StreamDummy;
-
- if (!pStrm)
- {
- pStrm = &StreamDummy;
- LogRel2(("HDA: Warning: Stream ID=%RU32 not supported, skipping to load ...\n", uStreamID));
- }
-
- RT_BZERO(pStrm, sizeof(HDASTREAM));
-
- rc = hdaStreamInit(pThis, pStrm, uStreamID);
- if (RT_FAILURE(rc))
- {
- LogRel(("HDA: Stream #%RU32: Initialization of stream %RU8 failed, rc=%Rrc\n", i, uStreamID, rc));
- break;
- }
-
- if (uVersion == HDA_SSM_VERSION_5)
- {
- /* Get the current BDLE entry and skip the rest. */
- uint16_t cBDLE;
-
- rc = SSMR3Skip(pSSM, sizeof(uint32_t)); /* Begin marker */
- AssertRC(rc);
- rc = SSMR3GetU16(pSSM, &cBDLE); /* cBDLE */
- AssertRC(rc);
- rc = SSMR3GetU16(pSSM, &pStrm->State.uCurBDLE); /* uCurBDLE */
- AssertRC(rc);
- rc = SSMR3Skip(pSSM, sizeof(uint32_t)); /* End marker */
- AssertRC(rc);
-
- uint32_t u32BDLEIndex;
- for (uint16_t a = 0; a < cBDLE; a++)
- {
- rc = SSMR3Skip(pSSM, sizeof(uint32_t)); /* Begin marker */
- AssertRC(rc);
- rc = SSMR3GetU32(pSSM, &u32BDLEIndex); /* u32BDLIndex */
- AssertRC(rc);
-
- /* Does the current BDLE index match the current BDLE to process? */
- if (u32BDLEIndex == pStrm->State.uCurBDLE)
- {
- rc = SSMR3GetU32(pSSM, &pStrm->State.BDLE.State.cbBelowFIFOW); /* cbBelowFIFOW */
- AssertRC(rc);
- rc = SSMR3GetMem(pSSM,
- &pStrm->State.BDLE.State.au8FIFO,
- sizeof(pStrm->State.BDLE.State.au8FIFO)); /* au8FIFO */
- AssertRC(rc);
- rc = SSMR3GetU32(pSSM, &pStrm->State.BDLE.State.u32BufOff); /* u32BufOff */
- AssertRC(rc);
- rc = SSMR3Skip(pSSM, sizeof(uint32_t)); /* End marker */
- AssertRC(rc);
- }
- else /* Skip not current BDLEs. */
- {
- rc = SSMR3Skip(pSSM, sizeof(uint32_t) /* cbBelowFIFOW */
- + sizeof(uint8_t) * 256 /* au8FIFO */
- + sizeof(uint32_t) /* u32BufOff */
- + sizeof(uint32_t)); /* End marker */
- AssertRC(rc);
- }
- }
- }
- else
- {
- rc = SSMR3GetStructEx(pSSM, &pStrm->State, sizeof(HDASTREAMSTATE),
- 0 /* fFlags */, g_aSSMStreamStateFields6, NULL);
- if (RT_FAILURE(rc))
- break;
-
- rc = SSMR3GetStructEx(pSSM, &pStrm->State.BDLE, sizeof(HDABDLE),
- 0 /* fFlags */, g_aSSMBDLEFields6, NULL);
- if (RT_FAILURE(rc))
- break;
-
- rc = SSMR3GetStructEx(pSSM, &pStrm->State.BDLE.State, sizeof(HDABDLESTATE),
- 0 /* fFlags */, g_aSSMBDLEStateFields6, NULL);
- if (RT_FAILURE(rc))
- break;
- }
- }
- break;
- }
-
- default:
- AssertReleaseFailed(); /* Never reached. */
- return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
- }
-
-#undef HDA_SSM_LOAD_BDLE_STATE_PRE_V5
-
- if (RT_SUCCESS(rc))
- {
- /*
- * Update stuff after the state changes.
- */
- bool fEnableIn = RT_BOOL(HDA_SDCTL(pThis, 0 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
-#ifdef VBOX_WITH_HDA_MIC_IN
- bool fEnableMicIn = RT_BOOL(HDA_SDCTL(pThis, 2 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
-#endif
- bool fEnableOut = RT_BOOL(HDA_SDCTL(pThis, 4 /** @todo Use a define. */) & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN));
-
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, fEnableIn);
- if (RT_FAILURE(rc))
- break;
-#ifdef VBOX_WITH_HDA_MIC_IN
- rc = pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, fEnableMicIn);
- if (RT_FAILURE(rc))
- break;
-#endif
- rc = pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, fEnableOut);
- if (RT_FAILURE(rc))
- break;
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- pThis->u64CORBBase = RT_MAKE_U64(HDA_REG(pThis, CORBLBASE), HDA_REG(pThis, CORBUBASE));
- pThis->u64RIRBBase = RT_MAKE_U64(HDA_REG(pThis, RIRBLBASE), HDA_REG(pThis, RIRBUBASE));
- pThis->u64DPBase = RT_MAKE_U64(HDA_REG(pThis, DPLBASE), HDA_REG(pThis, DPUBASE));
-
- /* Also make sure to update the DMA position bit if this was enabled when saving the state. */
- pThis->fDMAPosition = RT_BOOL(HDA_REG(pThis, DPLBASE) & RT_BIT_32(0));
- }
- else
- LogRel(("HDA: Failed loading device state (version %RU32, pass 0x%x), rc=%Rrc\n", uVersion, uPass, rc));
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-#ifdef DEBUG
-/* Debug and log type formatters. */
-
-/**
- * @callback_method_impl{FNRTSTRFORMATTYPE}
- */
-static DECLCALLBACK(size_t) hdaDbgFmtBDLE(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
- const char *pszType, void const *pvValue,
- int cchWidth, int cchPrecision, unsigned fFlags,
- void *pvUser)
-{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
- PHDABDLE pBDLE = (PHDABDLE)pvValue;
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "BDLE(idx:%RU32, off:%RU32, fifow:%RU32, DMA[%RU32 bytes @ 0x%x])",
- pBDLE->State.u32BDLIndex, pBDLE->State.u32BufOff, pBDLE->State.cbBelowFIFOW, pBDLE->u32BufSize, pBDLE->u64BufAdr);
-}
-
-/**
- * @callback_method_impl{FNRTSTRFORMATTYPE}
- */
-static DECLCALLBACK(size_t) hdaDbgFmtSDCTL(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
- const char *pszType, void const *pvValue,
- int cchWidth, int cchPrecision, unsigned fFlags,
- void *pvUser)
-{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
- uint32_t uSDCTL = (uint32_t)(uintptr_t)pvValue;
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "SDCTL(raw:%#x, DIR:%s, TP:%RTbool, STRIPE:%x, DEIE:%RTbool, FEIE:%RTbool, IOCE:%RTbool, RUN:%RTbool, RESET:%RTbool)",
- uSDCTL,
- (uSDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, DIR)) ? "OUT" : "IN",
- RT_BOOL(uSDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, TP)),
- (uSDCTL & HDA_REG_FIELD_MASK(SDCTL, STRIPE)) >> HDA_SDCTL_STRIPE_SHIFT,
- RT_BOOL(uSDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, DEIE)),
- RT_BOOL(uSDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, FEIE)),
- RT_BOOL(uSDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, ICE)),
- RT_BOOL(uSDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN)),
- RT_BOOL(uSDCTL & HDA_REG_FIELD_FLAG_MASK(SDCTL, SRST)));
-}
-
-/**
- * @callback_method_impl{FNRTSTRFORMATTYPE}
- */
-static DECLCALLBACK(size_t) hdaDbgFmtSDFIFOS(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
- const char *pszType, void const *pvValue,
- int cchWidth, int cchPrecision, unsigned fFlags,
- void *pvUser)
-{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
- uint32_t uSDFIFOS = (uint32_t)(uintptr_t)pvValue;
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOS(raw:%#x, sdfifos:%RU8 B)", uSDFIFOS, hdaSDFIFOSToBytes(uSDFIFOS));
-}
-
-/**
- * @callback_method_impl{FNRTSTRFORMATTYPE}
- */
-static DECLCALLBACK(size_t) hdaDbgFmtSDFIFOW(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
- const char *pszType, void const *pvValue,
- int cchWidth, int cchPrecision, unsigned fFlags,
- void *pvUser)
-{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
- uint32_t uSDFIFOW = (uint32_t)(uintptr_t)pvValue;
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "SDFIFOW(raw: %#0x, sdfifow:%d B)", uSDFIFOW, hdaSDFIFOWToBytes(uSDFIFOW));
-}
-
-/**
- * @callback_method_impl{FNRTSTRFORMATTYPE}
- */
-static DECLCALLBACK(size_t) hdaDbgFmtSDSTS(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
- const char *pszType, void const *pvValue,
- int cchWidth, int cchPrecision, unsigned fFlags,
- void *pvUser)
-{
- RT_NOREF(pszType, cchWidth, cchPrecision, fFlags, pvUser);
- uint32_t uSdSts = (uint32_t)(uintptr_t)pvValue;
- return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0,
- "SDSTS(raw:%#0x, fifordy:%RTbool, dese:%RTbool, fifoe:%RTbool, bcis:%RTbool)",
- uSdSts,
- RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, FIFORDY)),
- RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, DE)),
- RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, FE)),
- RT_BOOL(uSdSts & HDA_REG_FIELD_FLAG_MASK(SDSTS, BCIS)));
-}
-
-static int hdaLookUpRegisterByName(const char *pszArgs)
-{
- int iReg = 0;
- for (; iReg < HDA_NREGS; ++iReg)
- if (!RTStrICmp(g_aHdaRegMap[iReg].abbrev, pszArgs))
- return iReg;
- return -1;
-}
-
-
-static void hdaDbgPrintRegister(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaIndex)
-{
- Assert( pThis
- && iHdaIndex >= 0
- && iHdaIndex < HDA_NREGS);
- pHlp->pfnPrintf(pHlp, "%s: 0x%x\n", g_aHdaRegMap[iHdaIndex].abbrev, pThis->au32Regs[g_aHdaRegMap[iHdaIndex].mem_idx]);
-}
-
-/**
- * @callback_method_impl{FNDBGFHANDLERDEV}
- */
-static DECLCALLBACK(void) hdaInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- int iHdaRegisterIndex = hdaLookUpRegisterByName(pszArgs);
- if (iHdaRegisterIndex != -1)
- hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
- else
- for(iHdaRegisterIndex = 0; (unsigned int)iHdaRegisterIndex < HDA_NREGS; ++iHdaRegisterIndex)
- hdaDbgPrintRegister(pThis, pHlp, iHdaRegisterIndex);
-}
-
-static void hdaDbgPrintStream(PHDASTATE pThis, PCDBGFINFOHLP pHlp, int iHdaStrmIndex)
-{
- Assert( pThis
- && iHdaStrmIndex >= 0
- && iHdaStrmIndex < 7);
- pHlp->pfnPrintf(pHlp, "Dump of %d HDA Stream:\n", iHdaStrmIndex);
- pHlp->pfnPrintf(pHlp, "SD%dCTL: %R[sdctl]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, CTL, iHdaStrmIndex));
- pHlp->pfnPrintf(pHlp, "SD%dCTS: %R[sdsts]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, STS, iHdaStrmIndex));
- pHlp->pfnPrintf(pHlp, "SD%dFIFOS: %R[sdfifos]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, FIFOS, iHdaStrmIndex));
- pHlp->pfnPrintf(pHlp, "SD%dFIFOW: %R[sdfifow]\n", iHdaStrmIndex, HDA_STREAM_REG(pThis, FIFOW, iHdaStrmIndex));
-}
-
-static int hdaLookUpStreamIndex(PHDASTATE pThis, const char *pszArgs)
-{
- RT_NOREF(pThis, pszArgs);
- /** @todo add args parsing */
- return -1;
-}
-
-/**
- * @callback_method_impl{FNDBGFHANDLERDEV}
- */
-static DECLCALLBACK(void) hdaInfoStream(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- int iHdaStrmIndex = hdaLookUpStreamIndex(pThis, pszArgs);
- if (iHdaStrmIndex != -1)
- hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex);
- else
- for(iHdaStrmIndex = 0; iHdaStrmIndex < 7; ++iHdaStrmIndex)
- hdaDbgPrintStream(pThis, pHlp, iHdaStrmIndex);
-}
-
-/**
- * @callback_method_impl{FNDBGFHANDLERDEV}
- */
-static DECLCALLBACK(void) hdaInfoCodecNodes(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- if (pThis->pCodec->pfnDbgListNodes)
- pThis->pCodec->pfnDbgListNodes(pThis->pCodec, pHlp, pszArgs);
- else
- pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
-}
-
-/**
- * @callback_method_impl{FNDBGFHANDLERDEV}
- */
-static DECLCALLBACK(void) hdaInfoCodecSelector(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- if (pThis->pCodec->pfnDbgSelector)
- pThis->pCodec->pfnDbgSelector(pThis->pCodec, pHlp, pszArgs);
- else
- pHlp->pfnPrintf(pHlp, "Codec implementation doesn't provide corresponding callback\n");
-}
-
-/**
- * @callback_method_impl{FNDBGFHANDLERDEV}
- */
-static DECLCALLBACK(void) hdaInfoMixer(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- if (pThis->pMixer)
- AudioMixerDebug(pThis->pMixer, pHlp, pszArgs);
- else
- pHlp->pfnPrintf(pHlp, "Mixer not available\n");
-}
-#endif /* DEBUG */
-
-/* PDMIBASE */
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) hdaQueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
-{
- PHDASTATE pThis = RT_FROM_MEMBER(pInterface, HDASTATE, IBase);
- Assert(&pThis->IBase == pInterface);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
- return NULL;
-}
-
-
-/* PDMDEVREG */
-
-/**
- * Reset notification.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance data.
- *
- * @remark The original sources didn't install a reset handler, but it seems to
- * make sense to me so we'll do it.
- */
-static DECLCALLBACK(void) hdaReset(PPDMDEVINS pDevIns)
-{
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- HDA_REG(pThis, GCAP) = HDA_MAKE_GCAP(4,4,0,0,1); /* see 6.2.1 */
- HDA_REG(pThis, VMIN) = 0x00; /* see 6.2.2 */
- HDA_REG(pThis, VMAJ) = 0x01; /* see 6.2.3 */
- HDA_REG(pThis, OUTPAY) = 0x003C; /* see 6.2.4 */
- HDA_REG(pThis, INPAY) = 0x001D; /* see 6.2.5 */
- HDA_REG(pThis, CORBSIZE) = 0x42; /* see 6.2.1 */
- HDA_REG(pThis, RIRBSIZE) = 0x42; /* see 6.2.1 */
- HDA_REG(pThis, CORBRP) = 0x0;
- HDA_REG(pThis, RIRBWP) = 0x0;
-
- LogFunc(("Resetting ...\n"));
-
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- /*
- * Stop the timer, if any.
- */
- int rc2;
- if (pThis->pTimer)
- {
- rc2 = TMTimerStop(pThis->pTimer);
- AssertRC(rc2);
- }
-# endif
-
- /*
- * Stop any audio currently playing and/or recording.
- */
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, false /* Disable */);
-# ifdef VBOX_WITH_HDA_MIC_IN
- /* Ignore rc. */
- pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, false /* Disable */);
-# endif
- /* Ditto. */
- pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, false /* Disable */);
- /* Ditto. */
- }
-
- pThis->cbCorbBuf = 256 * sizeof(uint32_t); /** @todo Use a define here. */
-
- if (pThis->pu32CorbBuf)
- RT_BZERO(pThis->pu32CorbBuf, pThis->cbCorbBuf);
- else
- pThis->pu32CorbBuf = (uint32_t *)RTMemAllocZ(pThis->cbCorbBuf);
-
- pThis->cbRirbBuf = 256 * sizeof(uint64_t); /** @todo Use a define here. */
- if (pThis->pu64RirbBuf)
- RT_BZERO(pThis->pu64RirbBuf, pThis->cbRirbBuf);
- else
- pThis->pu64RirbBuf = (uint64_t *)RTMemAllocZ(pThis->cbRirbBuf);
-
- pThis->u64BaseTS = PDMDevHlpTMTimeVirtGetNano(pDevIns);
-
- for (uint8_t u8Strm = 0; u8Strm < 8; u8Strm++) /** @todo Use a define here. */
- {
- PHDASTREAM pStrmSt = NULL;
- if (u8Strm == 0) /** @todo Implement dynamic stream IDs. */
- pStrmSt = &pThis->StrmStLineIn;
-# ifdef VBOX_WITH_HDA_MIC_IN
- else if (u8Strm == 2) /** @todo Implement dynamic stream IDs. */
- pStrmSt = &pThis->StrmStMicIn;
-# endif
- else if (u8Strm == 4) /** @todo Implement dynamic stream IDs. */
- pStrmSt = &pThis->StrmStOut;
-
- if (pStrmSt)
- {
- /* Remove the RUN bit from SDnCTL in case the stream was in a running state before. */
- HDA_STREAM_REG(pThis, CTL, u8Strm) &= ~HDA_REG_FIELD_FLAG_MASK(SDCTL, RUN);
-
- hdaStreamReset(pThis, pStrmSt, u8Strm);
- }
- }
-
- /* Emulation of codec "wake up" (HDA spec 5.5.1 and 6.5). */
- HDA_REG(pThis, STATESTS) = 0x1;
-
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- /*
- * Start timer again, if any.
- */
- if (pThis->pTimer)
- {
- LogFunc(("Restarting timer\n"));
- rc2 = TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
- AssertRC(rc2);
- }
-# endif
-
- LogRel(("HDA: Reset\n"));
-}
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnDestruct}
- */
-static DECLCALLBACK(int) hdaDestruct(PPDMDEVINS pDevIns)
-{
- PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- PHDADRIVER pDrv;
- while (!RTListIsEmpty(&pThis->lstDrv))
- {
- pDrv = RTListGetFirst(&pThis->lstDrv, HDADRIVER, Node);
-
- RTListNodeRemove(&pDrv->Node);
- RTMemFree(pDrv);
- }
-
- if (pThis->pMixer)
- {
- AudioMixerDestroy(pThis->pMixer);
- pThis->pMixer = NULL;
- }
-
- if (pThis->pCodec)
- {
- int rc = hdaCodecDestruct(pThis->pCodec);
- AssertRC(rc);
-
- RTMemFree(pThis->pCodec);
- pThis->pCodec = NULL;
- }
-
- RTMemFree(pThis->pu32CorbBuf);
- pThis->pu32CorbBuf = NULL;
-
- RTMemFree(pThis->pu64RirbBuf);
- pThis->pu64RirbBuf = NULL;
-
- hdaStreamDestroy(&pThis->StrmStLineIn);
- hdaStreamDestroy(&pThis->StrmStMicIn);
- hdaStreamDestroy(&pThis->StrmStOut);
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * Attach command, internal version.
- *
- * This is called to let the device attach to a driver for a specified LUN
- * during runtime. This is not called during VM construction, the device
- * constructor has to attach to all the available drivers.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param pDrv Driver to (re-)use for (re-)attaching to.
- * If NULL is specified, a new driver will be created and appended
- * to the driver list.
- * @param uLUN The logical unit which is being detached.
- * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
- */
-static int hdaAttachInternal(PPDMDEVINS pDevIns, PHDADRIVER pDrv, unsigned uLUN, uint32_t fFlags)
-{
- RT_NOREF(fFlags);
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
-
- /*
- * Attach driver.
- */
- char *pszDesc = NULL;
- if (RTStrAPrintf(&pszDesc, "Audio driver port (HDA) for LUN#%u", uLUN) <= 0)
- AssertReleaseMsgReturn(pszDesc,
- ("Not enough memory for HDA driver port description of LUN #%u\n", uLUN),
- VERR_NO_MEMORY);
-
- PPDMIBASE pDrvBase;
- int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
- &pThis->IBase, &pDrvBase, pszDesc);
- if (RT_SUCCESS(rc))
- {
- if (pDrv == NULL)
- pDrv = (PHDADRIVER)RTMemAllocZ(sizeof(HDADRIVER));
- if (pDrv)
- {
- pDrv->pDrvBase = pDrvBase;
- pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
- AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN#%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
- pDrv->pHDAState = pThis;
- pDrv->uLUN = uLUN;
-
- /*
- * For now we always set the driver at LUN 0 as our primary
- * host backend. This might change in the future.
- */
- if (pDrv->uLUN == 0)
- pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
-
- LogFunc(("LUN#%u: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
-
- /* Attach to driver list if not attached yet. */
- if (!pDrv->fAttached)
- {
- RTListAppend(&pThis->lstDrv, &pDrv->Node);
- pDrv->fAttached = true;
- }
- }
- else
- rc = VERR_NO_MEMORY;
- }
- else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- LogFunc(("No attached driver for LUN #%u\n", uLUN));
-
- if (RT_FAILURE(rc))
- {
- /* Only free this string on failure;
- * must remain valid for the live of the driver instance. */
- RTStrFree(pszDesc);
- }
-
- LogFunc(("uLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
- return rc;
-}
-
-/**
- * Attach command.
- *
- * This is called to let the device attach to a driver for a specified LUN
- * during runtime. This is not called during VM construction, the device
- * constructor has to attach to all the available drivers.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param uLUN The logical unit which is being detached.
- * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
- */
-static DECLCALLBACK(int) hdaAttach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
-{
- return hdaAttachInternal(pDevIns, NULL /* pDrv */, uLUN, fFlags);
-}
-
-static DECLCALLBACK(void) hdaDetach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
-{
- RT_NOREF(pDevIns, uLUN, fFlags);
- LogFunc(("iLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
-}
-
-/**
- * Re-attach.
- *
- * @returns VBox status code.
- * @param pThis Device instance.
- * @param pDrv Driver instance used for attaching to.
- * If NULL is specified, a new driver will be created and appended
- * to the driver list.
- * @param uLUN The logical unit which is being re-detached.
- * @param pszDriver Driver name.
- */
-static int hdaReattach(PHDASTATE pThis, PHDADRIVER pDrv, uint8_t uLUN, const char *pszDriver)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszDriver, VERR_INVALID_POINTER);
-
- PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
- PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
- PCFGMNODE pDev0 = CFGMR3GetChild(pRoot, "Devices/hda/0/");
-
- /* Remove LUN branch. */
- CFGMR3RemoveNode(CFGMR3GetChildF(pDev0, "LUN#%u/", uLUN));
-
- if (pDrv)
- {
- /* Re-use a driver instance => detach the driver before. */
- int rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
- if (RT_FAILURE(rc))
- return rc;
- }
-
-#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
-
- int rc = VINF_SUCCESS;
- do
- {
- PCFGMNODE pLunL0;
- rc = CFGMR3InsertNodeF(pDev0, &pLunL0, "LUN#%u/", uLUN); RC_CHECK();
- rc = CFGMR3InsertString(pLunL0, "Driver", "AUDIO"); RC_CHECK();
- rc = CFGMR3InsertNode(pLunL0, "Config/", NULL); RC_CHECK();
-
- PCFGMNODE pLunL1, pLunL2;
- rc = CFGMR3InsertNode (pLunL0, "AttachedDriver/", &pLunL1); RC_CHECK();
- rc = CFGMR3InsertNode (pLunL1, "Config/", &pLunL2); RC_CHECK();
- rc = CFGMR3InsertString(pLunL1, "Driver", pszDriver); RC_CHECK();
-
- rc = CFGMR3InsertString(pLunL2, "AudioDriver", pszDriver); RC_CHECK();
-
- } while (0);
-
- if (RT_SUCCESS(rc))
- rc = hdaAttachInternal(pThis->pDevInsR3, pDrv, uLUN, 0 /* fFlags */);
-
- LogFunc(("pThis=%p, uLUN=%u, pszDriver=%s, rc=%Rrc\n", pThis, uLUN, pszDriver, rc));
-
-#undef RC_CHECK
-
- return rc;
-}
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnConstruct}
- */
-static DECLCALLBACK(int) hdaConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
-{
- RT_NOREF(iInstance);
- PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
- PHDASTATE pThis = PDMINS_2_DATA(pDevIns, PHDASTATE);
- Assert(iInstance == 0);
-
- /*
- * Validations.
- */
- if (!CFGMR3AreValuesValid(pCfg, "R0Enabled\0"
- "RCEnabled\0"
- "TimerHz\0"))
- return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
- N_ ("Invalid configuration for the Intel HDA device"));
-
- int rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &pThis->fRCEnabled, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("HDA configuration error: failed to read RCEnabled as boolean"));
- rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &pThis->fR0Enabled, false);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("HDA configuration error: failed to read R0Enabled as boolean"));
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- uint16_t uTimerHz;
- rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("HDA configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
-#endif
-
- /*
- * Initialize data (most of it anyway).
- */
- pThis->pDevInsR3 = pDevIns;
- pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
- pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
- /* IBase */
- pThis->IBase.pfnQueryInterface = hdaQueryInterface;
-
- /* PCI Device */
- PCIDevSetVendorId (&pThis->PciDev, HDA_PCI_VENDOR_ID); /* nVidia */
- PCIDevSetDeviceId (&pThis->PciDev, HDA_PCI_DEVICE_ID); /* HDA */
-
- PCIDevSetCommand (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */
- PCIDevSetStatus (&pThis->PciDev, VBOX_PCI_STATUS_CAP_LIST); /* 06 rwc?,ro? - pcists. */
- PCIDevSetRevisionId (&pThis->PciDev, 0x01); /* 08 ro - rid. */
- PCIDevSetClassProg (&pThis->PciDev, 0x00); /* 09 ro - pi. */
- PCIDevSetClassSub (&pThis->PciDev, 0x03); /* 0a ro - scc; 03 == HDA. */
- PCIDevSetClassBase (&pThis->PciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */
- PCIDevSetHeaderType (&pThis->PciDev, 0x00); /* 0e ro - headtyp. */
- PCIDevSetBaseAddress (&pThis->PciDev, 0, /* 10 rw - MMIO */
- false /* fIoSpace */, false /* fPrefetchable */, true /* f64Bit */, 0x00000000);
- PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */
- PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */
-
-#if defined(HDA_AS_PCI_EXPRESS)
- PCIDevSetCapabilityList (&pThis->PciDev, 0x80);
-#elif defined(VBOX_WITH_MSI_DEVICES)
- PCIDevSetCapabilityList (&pThis->PciDev, 0x60);
-#else
- PCIDevSetCapabilityList (&pThis->PciDev, 0x50); /* ICH6 datasheet 18.1.16 */
-#endif
-
- /// @todo r=michaln: If there are really no PCIDevSetXx for these, the meaning
- /// of these values needs to be properly documented!
- /* HDCTL off 0x40 bit 0 selects signaling mode (1-HDA, 0 - Ac97) 18.1.19 */
- PCIDevSetByte(&pThis->PciDev, 0x40, 0x01);
-
- /* Power Management */
- PCIDevSetByte(&pThis->PciDev, 0x50 + 0, VBOX_PCI_CAP_ID_PM);
- PCIDevSetByte(&pThis->PciDev, 0x50 + 1, 0x0); /* next */
- PCIDevSetWord(&pThis->PciDev, 0x50 + 2, VBOX_PCI_PM_CAP_DSI | 0x02 /* version, PM1.1 */ );
-
-#ifdef HDA_AS_PCI_EXPRESS
- /* PCI Express */
- PCIDevSetByte(&pThis->PciDev, 0x80 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
- PCIDevSetByte(&pThis->PciDev, 0x80 + 1, 0x60); /* next */
- /* Device flags */
- PCIDevSetWord(&pThis->PciDev, 0x80 + 2,
- /* version */ 0x1 |
- /* Root Complex Integrated Endpoint */ (VBOX_PCI_EXP_TYPE_ROOT_INT_EP << 4) |
- /* MSI */ (100) << 9 );
- /* Device capabilities */
- PCIDevSetDWord(&pThis->PciDev, 0x80 + 4, VBOX_PCI_EXP_DEVCAP_FLRESET);
- /* Device control */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 8, 0);
- /* Device status */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 10, 0);
- /* Link caps */
- PCIDevSetDWord(&pThis->PciDev, 0x80 + 12, 0);
- /* Link control */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 16, 0);
- /* Link status */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 18, 0);
- /* Slot capabilities */
- PCIDevSetDWord(&pThis->PciDev, 0x80 + 20, 0);
- /* Slot control */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 24, 0);
- /* Slot status */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 26, 0);
- /* Root control */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 28, 0);
- /* Root capabilities */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 30, 0);
- /* Root status */
- PCIDevSetDWord(&pThis->PciDev, 0x80 + 32, 0);
- /* Device capabilities 2 */
- PCIDevSetDWord(&pThis->PciDev, 0x80 + 36, 0);
- /* Device control 2 */
- PCIDevSetQWord(&pThis->PciDev, 0x80 + 40, 0);
- /* Link control 2 */
- PCIDevSetQWord(&pThis->PciDev, 0x80 + 48, 0);
- /* Slot control 2 */
- PCIDevSetWord( &pThis->PciDev, 0x80 + 56, 0);
-#endif
-
- /*
- * Register the PCI device.
- */
- rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
- if (RT_FAILURE(rc))
- return rc;
-
- rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x4000, PCI_ADDRESS_SPACE_MEM, hdaPciIoRegionMap);
- if (RT_FAILURE(rc))
- return rc;
-
-#ifdef VBOX_WITH_MSI_DEVICES
- PDMMSIREG MsiReg;
- RT_ZERO(MsiReg);
- MsiReg.cMsiVectors = 1;
- MsiReg.iMsiCapOffset = 0x60;
- MsiReg.iMsiNextOffset = 0x50;
- rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
- if (RT_FAILURE(rc))
- {
- /* That's OK, we can work without MSI */
- PCIDevSetCapabilityList(&pThis->PciDev, 0x50);
- }
-#endif
-
- rc = PDMDevHlpSSMRegister(pDevIns, HDA_SSM_VERSION, sizeof(*pThis), hdaSaveExec, hdaLoadExec);
- if (RT_FAILURE(rc))
- return rc;
-
- RTListInit(&pThis->lstDrv);
-
- uint8_t uLUN;
- for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
- {
- LogFunc(("Trying to attach driver for LUN #%RU32 ...\n", uLUN));
- rc = hdaAttachInternal(pDevIns, NULL /* pDrv */, uLUN, 0 /* fFlags */);
- if (RT_FAILURE(rc))
- {
- if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- rc = VINF_SUCCESS;
- else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
- {
- hdaReattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
- N_("No audio devices could be opened. Selecting the NULL audio backend "
- "with the consequence that no sound is audible"));
- /* attaching to the NULL audio backend will never fail */
- rc = VINF_SUCCESS;
- }
- break;
- }
- }
-
- LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
-
- if (RT_SUCCESS(rc))
- {
- rc = AudioMixerCreate("HDA Mixer", 0 /* uFlags */, &pThis->pMixer);
- if (RT_SUCCESS(rc))
- {
- /* Set a default audio format for our mixer. */
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = 44100;
- streamCfg.cChannels = 2;
- streamCfg.enmFormat = AUD_FMT_S16;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- rc = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
- AssertRC(rc);
-
- /* Add all required audio sinks. */
- rc = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
- AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
- AssertRC(rc);
-
- rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Line In",
- AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
- AssertRC(rc);
-
- rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Microphone In",
- AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
- AssertRC(rc);
-
- /* There is no master volume control. Set the master to max. */
- PDMAUDIOVOLUME vol = { false, 255, 255 };
- rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
- AssertRC(rc);
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- /* Construct codec. */
- pThis->pCodec = (PHDACODEC)RTMemAllocZ(sizeof(HDACODEC));
- if (!pThis->pCodec)
- return PDMDEV_SET_ERROR(pDevIns, VERR_NO_MEMORY, N_("Out of memory allocating HDA codec state"));
-
- /* Audio driver callbacks for multiplexing. */
- pThis->pCodec->pfnCloseIn = hdaCloseIn;
- pThis->pCodec->pfnCloseOut = hdaCloseOut;
- pThis->pCodec->pfnOpenIn = hdaOpenIn;
- pThis->pCodec->pfnOpenOut = hdaOpenOut;
- pThis->pCodec->pfnReset = hdaCodecReset;
- pThis->pCodec->pfnSetVolume = hdaSetVolume;
-
- pThis->pCodec->pHDAState = pThis; /* Assign HDA controller state to codec. */
-
- /* Construct the codec. */
- rc = hdaCodecConstruct(pDevIns, pThis->pCodec, 0 /* Codec index */, pCfg);
- if (RT_FAILURE(rc))
- AssertRCReturn(rc, rc);
-
- /* ICH6 datasheet defines 0 values for SVID and SID (18.1.14-15), which together with values returned for
- verb F20 should provide device/codec recognition. */
- Assert(pThis->pCodec->u16VendorId);
- Assert(pThis->pCodec->u16DeviceId);
- PCIDevSetSubSystemVendorId(&pThis->PciDev, pThis->pCodec->u16VendorId); /* 2c ro - intel.) */
- PCIDevSetSubSystemId( &pThis->PciDev, pThis->pCodec->u16DeviceId); /* 2e ro. */
- }
-
- if (RT_SUCCESS(rc))
- {
- rc = hdaStreamCreate(&pThis->StrmStLineIn);
- AssertRC(rc);
-#ifdef VBOX_WITH_HDA_MIC_IN
- rc = hdaStreamCreate(&pThis->StrmStMicIn);
- AssertRC(rc);
-#endif
- rc = hdaStreamCreate(&pThis->StrmStOut);
- AssertRC(rc);
-
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- /*
- * Only primary drivers are critical for the VM to run. Everything else
- * might not worth showing an own error message box in the GUI.
- */
- if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
- continue;
-
- PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
- AssertPtr(pCon);
-
- bool fValidLineIn = pCon->pfnIsValidIn(pCon, pDrv->LineIn.pStrmIn);
-#ifdef VBOX_WITH_HDA_MIC_IN
- bool fValidMicIn = pCon->pfnIsValidIn (pCon, pDrv->MicIn.pStrmIn);
-#endif
- bool fValidOut = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
-
- if ( !fValidLineIn
-#ifdef VBOX_WITH_HDA_MIC_IN
- && !fValidMicIn
-#endif
- && !fValidOut)
- {
- LogRel(("HDA: Falling back to NULL backend (no sound audible)\n"));
-
- hdaReset(pDevIns);
- hdaReattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
-
- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
- N_("No audio devices could be opened. Selecting the NULL audio backend "
- "with the consequence that no sound is audible"));
- }
- else
- {
- bool fWarn = false;
-
- PDMAUDIOBACKENDCFG backendCfg;
- int rc2 = pCon->pfnGetConfiguration(pCon, &backendCfg);
- if (RT_SUCCESS(rc2))
- {
- if (backendCfg.cMaxHstStrmsIn)
- {
-#ifdef VBOX_WITH_HDA_MIC_IN
- /* If the audio backend supports two or more input streams at once,
- * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
- if (backendCfg.cMaxHstStrmsIn >= 2)
- fWarn = !fValidLineIn || !fValidMicIn;
- /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
- * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
- * One of the two simply is not in use then. */
- else if (backendCfg.cMaxHstStrmsIn == 1)
- fWarn = !fValidLineIn && !fValidMicIn;
- /* Don't warn if our backend is not able of supporting any input streams at all. */
-#else
- /* We only have line-in as input source. */
- fWarn = !fValidLineIn;
-#endif
- }
-
- if ( !fWarn
- && backendCfg.cMaxHstStrmsOut)
- {
- fWarn = !fValidOut;
- }
- }
- else
- AssertReleaseMsgFailed(("Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n",
- pDrv->uLUN, rc2));
-
- if (fWarn)
- {
- char szMissingStreams[255];
- size_t len = 0;
- if (!fValidLineIn)
- {
- LogRel(("HDA: WARNING: Unable to open PCM line input for LUN #%RU8!\n", pDrv->uLUN));
- len = RTStrPrintf(szMissingStreams, sizeof(szMissingStreams), "PCM Input");
- }
-#ifdef VBOX_WITH_HDA_MIC_IN
- if (!fValidMicIn)
- {
- LogRel(("HDA: WARNING: Unable to open PCM microphone input for LUN #%RU8!\n", pDrv->uLUN));
- len += RTStrPrintf(szMissingStreams + len,
- sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
- }
-#endif
- if (!fValidOut)
- {
- LogRel(("HDA: WARNING: Unable to open PCM output for LUN #%RU8!\n", pDrv->uLUN));
- len += RTStrPrintf(szMissingStreams + len,
- sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
- }
-
- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
- N_("Some HDA audio streams (%s) could not be opened. Guest applications generating audio "
- "output or depending on audio input may hang. Make sure your host audio device "
- "is working properly. Check the logfile for error messages of the audio "
- "subsystem"), szMissingStreams);
- }
- }
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- hdaReset(pDevIns);
-
- /*
- * 18.2.6,7 defines that values of this registers might be cleared on power on/reset
- * hdaReset shouldn't affects these registers.
- */
- HDA_REG(pThis, WAKEEN) = 0x0;
- HDA_REG(pThis, STATESTS) = 0x0;
-
-#ifdef DEBUG
- /*
- * Debug and string formatter types.
- */
- PDMDevHlpDBGFInfoRegister(pDevIns, "hda", "HDA info. (hda [register case-insensitive])", hdaInfo);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdastrm", "HDA stream info. (hdastrm [stream number])", hdaInfoStream);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdcnodes", "HDA codec nodes.", hdaInfoCodecNodes);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdcselector", "HDA codec's selector states [node number].", hdaInfoCodecSelector);
- PDMDevHlpDBGFInfoRegister(pDevIns, "hdamixer", "HDA mixer state.", hdaInfoMixer);
-
- rc = RTStrFormatTypeRegister("bdle", hdaDbgFmtBDLE, NULL);
- AssertRC(rc);
- rc = RTStrFormatTypeRegister("sdctl", hdaDbgFmtSDCTL, NULL);
- AssertRC(rc);
- rc = RTStrFormatTypeRegister("sdsts", hdaDbgFmtSDSTS, NULL);
- AssertRC(rc);
- rc = RTStrFormatTypeRegister("sdfifos", hdaDbgFmtSDFIFOS, NULL);
- AssertRC(rc);
- rc = RTStrFormatTypeRegister("sdfifow", hdaDbgFmtSDFIFOW, NULL);
- AssertRC(rc);
-#endif /* DEBUG */
-
- /*
- * Some debug assertions.
- */
- for (unsigned i = 0; i < RT_ELEMENTS(g_aHdaRegMap); i++)
- {
- struct HDAREGDESC const *pReg = &g_aHdaRegMap[i];
- struct HDAREGDESC const *pNextReg = i + 1 < RT_ELEMENTS(g_aHdaRegMap) ? &g_aHdaRegMap[i + 1] : NULL;
-
- /* binary search order. */
- AssertReleaseMsg(!pNextReg || pReg->offset + pReg->size <= pNextReg->offset,
- ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
- i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
-
- /* alignment. */
- AssertReleaseMsg( pReg->size == 1
- || (pReg->size == 2 && (pReg->offset & 1) == 0)
- || (pReg->size == 3 && (pReg->offset & 3) == 0)
- || (pReg->size == 4 && (pReg->offset & 3) == 0),
- ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
-
- /* registers are packed into dwords - with 3 exceptions with gaps at the end of the dword. */
- AssertRelease(((pReg->offset + pReg->size) & 3) == 0 || pNextReg);
- if (pReg->offset & 3)
- {
- struct HDAREGDESC const *pPrevReg = i > 0 ? &g_aHdaRegMap[i - 1] : NULL;
- AssertReleaseMsg(pPrevReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
- if (pPrevReg)
- AssertReleaseMsg(pPrevReg->offset + pPrevReg->size == pReg->offset,
- ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
- i - 1, pPrevReg->offset, pPrevReg->size, i + 1, pReg->offset, pReg->size));
- }
-#if 0
- if ((pReg->offset + pReg->size) & 3)
- {
- AssertReleaseMsg(pNextReg, ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
- if (pNextReg)
- AssertReleaseMsg(pReg->offset + pReg->size == pNextReg->offset,
- ("[%#x] = {%#x LB %#x} vs. [%#x] = {%#x LB %#x}\n",
- i, pReg->offset, pReg->size, i + 1, pNextReg->offset, pNextReg->size));
- }
-#endif
- /* The final entry is a full DWORD, no gaps! Allows shortcuts. */
- AssertReleaseMsg(pNextReg || ((pReg->offset + pReg->size) & 3) == 0,
- ("[%#x] = {%#x LB %#x}\n", i, pReg->offset, pReg->size));
- }
- }
-
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- if (RT_SUCCESS(rc))
- {
- /* Start the emulation timer. */
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, hdaTimer, pThis,
- TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchHda", &pThis->pTimer);
- AssertRCReturn(rc, rc);
-
- if (RT_SUCCESS(rc))
- {
- pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
- pThis->uTimerTS = TMTimerGet(pThis->pTimer);
- LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
-
- /* Fire off timer. */
- TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
- }
- }
-# else
- if (RT_SUCCESS(rc))
- {
- PHDADRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, HDADRIVER, Node)
- {
- /* Only register primary driver.
- * The device emulation does the output multiplexing then. */
- if (pDrv->Flags != PDMAUDIODRVFLAG_PRIMARY)
- continue;
-
- PDMAUDIOCALLBACK AudioCallbacks[2];
-
- HDACALLBACKCTX Ctx = { pThis, pDrv };
-
- AudioCallbacks[0].enmType = PDMAUDIOCALLBACKTYPE_INPUT;
- AudioCallbacks[0].pfnCallback = hdaCallbackInput;
- AudioCallbacks[0].pvCtx = &Ctx;
- AudioCallbacks[0].cbCtx = sizeof(HDACALLBACKCTX);
-
- AudioCallbacks[1].enmType = PDMAUDIOCALLBACKTYPE_OUTPUT;
- AudioCallbacks[1].pfnCallback = hdaCallbackOutput;
- AudioCallbacks[1].pvCtx = &Ctx;
- AudioCallbacks[1].cbCtx = sizeof(HDACALLBACKCTX);
-
- rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
- if (RT_FAILURE(rc))
- break;
- }
- }
-# endif
-
-# ifdef VBOX_WITH_STATISTICS
- if (RT_SUCCESS(rc))
- {
- /*
- * Register statistics.
- */
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "/Devices/HDA/Timer", STAMUNIT_TICKS_PER_CALL, "Profiling hdaTimer.");
-# endif
- PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "/Devices/HDA/BytesRead" , STAMUNIT_BYTES, "Bytes read from HDA emulation.");
- PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "/Devices/HDA/BytesWritten", STAMUNIT_BYTES, "Bytes written to HDA emulation.");
- }
-# endif
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * The device registration structure.
- */
-const PDMDEVREG g_DeviceICH6_HDA =
-{
- /* u32Version */
- PDM_DEVREG_VERSION,
- /* szName */
- "hda",
- /* szRCMod */
- "VBoxDDRC.rc",
- /* szR0Mod */
- "VBoxDDR0.r0",
- /* pszDescription */
- "Intel HD Audio Controller",
- /* fFlags */
- PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
- /* fClass */
- PDM_DEVREG_CLASS_AUDIO,
- /* cMaxInstances */
- 1,
- /* cbInstance */
- sizeof(HDASTATE),
- /* pfnConstruct */
- hdaConstruct,
- /* pfnDestruct */
- hdaDestruct,
- /* pfnRelocate */
- NULL,
- /* pfnMemSetup */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- hdaReset,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- hdaAttach,
- /* pfnDetach */
- hdaDetach,
- /* pfnQueryInterface. */
- NULL,
- /* pfnInitComplete */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32VersionEnd */
- PDM_DEVREG_VERSION
-};
-
-#endif /* IN_RING3 */
-#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
diff --git a/src/VBox/Devices/Audio_50/DevIchAc97.cpp b/src/VBox/Devices/Audio_50/DevIchAc97.cpp
deleted file mode 100644
index 61f231e..0000000
--- a/src/VBox/Devices/Audio_50/DevIchAc97.cpp
+++ /dev/null
@@ -1,2758 +0,0 @@
-/* $Id: DevIchAc97.cpp $ */
-/** @file
- * DevIchAc97 - VBox ICH AC97 Audio Controller.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DEV_AC97
-#include <VBox/log.h>
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
-#include <iprt/assert.h>
-#ifdef IN_RING3
-# include <iprt/mem.h>
-# include <iprt/string.h>
-# include <iprt/uuid.h>
-#endif
-
-#include "VBoxDD.h"
-
-#include "AudioMixBuffer.h"
-#include "AudioMixer.h"
-#include "DrvAudio.h"
-
-
-/*********************************************************************************************************************************
-* Defined Constants And Macros *
-*********************************************************************************************************************************/
-
-#ifdef DEBUG
-//#define DEBUG_LUN
-# ifdef DEBUG_LUN
-# define DEBUG_LUN_NUM 1
-# endif
-#endif /* DEBUG */
-
-#define AC97_SSM_VERSION 1
-
-#ifdef VBOX
-# define SOFT_VOLUME /** @todo Get rid of this crap. */
-#else
-# define SOFT_VOLUME
-#endif
-
-#define SR_FIFOE RT_BIT(4) /* rwc, FIFO error. */
-#define SR_BCIS RT_BIT(3) /* rwc, Buffer completion interrupt status. */
-#define SR_LVBCI RT_BIT(2) /* rwc, Last valid buffer completion interrupt. */
-#define SR_CELV RT_BIT(1) /* ro, Current equals last valid. */
-#define SR_DCH RT_BIT(0) /* ro, Controller halted. */
-#define SR_VALID_MASK (RT_BIT(5) - 1)
-#define SR_WCLEAR_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
-#define SR_RO_MASK (SR_DCH | SR_CELV)
-#define SR_INT_MASK (SR_FIFOE | SR_BCIS | SR_LVBCI)
-
-#define CR_IOCE RT_BIT(4) /* rw, Interrupt On Completion Enable. */
-#define CR_FEIE RT_BIT(3) /* rw FIFO Error Interrupt Enable. */
-#define CR_LVBIE RT_BIT(2) /* rw */
-#define CR_RR RT_BIT(1) /* rw */
-#define CR_RPBM RT_BIT(0) /* rw */
-#define CR_VALID_MASK (RT_BIT(5) - 1)
-#define CR_DONT_CLEAR_MASK (CR_IOCE | CR_FEIE | CR_LVBIE)
-
-#define GC_WR 4 /* rw */
-#define GC_CR 2 /* rw */
-#define GC_VALID_MASK (RT_BIT(6) - 1)
-
-#define GS_MD3 RT_BIT(17) /* rw */
-#define GS_AD3 RT_BIT(16) /* rw */
-#define GS_RCS RT_BIT(15) /* rwc */
-#define GS_B3S12 RT_BIT(14) /* ro */
-#define GS_B2S12 RT_BIT(13) /* ro */
-#define GS_B1S12 RT_BIT(12) /* ro */
-#define GS_S1R1 RT_BIT(11) /* rwc */
-#define GS_S0R1 RT_BIT(10) /* rwc */
-#define GS_S1CR RT_BIT(9) /* ro */
-#define GS_S0CR RT_BIT(8) /* ro */
-#define GS_MINT RT_BIT(7) /* ro */
-#define GS_POINT RT_BIT(6) /* ro */
-#define GS_PIINT RT_BIT(5) /* ro */
-#define GS_RSRVD (RT_BIT(4)|RT_BIT(3))
-#define GS_MOINT RT_BIT(2) /* ro */
-#define GS_MIINT RT_BIT(1) /* ro */
-#define GS_GSCI RT_BIT(0) /* rwc */
-#define GS_RO_MASK (GS_B3S12 | \
- GS_B2S12 | \
- GS_B1S12 | \
- GS_S1CR | \
- GS_S0CR | \
- GS_MINT | \
- GS_POINT | \
- GS_PIINT | \
- GS_RSRVD | \
- GS_MOINT | \
- GS_MIINT)
-#define GS_VALID_MASK (RT_BIT(18) - 1)
-#define GS_WCLEAR_MASK (GS_RCS|GS_S1R1|GS_S0R1|GS_GSCI)
-
-/** @name Buffer Descriptor
- * @{ */
-#define BD_IOC RT_BIT(31) /**< Interrupt on Completion */
-#define BD_BUP RT_BIT(30) /**< Buffer Underrun Policy */
-/** @} */
-
-#define EACS_VRA 1
-#define EACS_VRM 8
-
-#define VOL_MASK 0x1f
-#define MUTE_SHIFT 15
-
-#define REC_MASK 7
-enum
-{
- REC_MIC = 0,
- REC_CD,
- REC_VIDEO,
- REC_AUX,
- REC_LINE_IN,
- REC_STEREO_MIX,
- REC_MONO_MIX,
- REC_PHONE
-};
-
-enum
-{
- AC97_Reset = 0x00,
- AC97_Master_Volume_Mute = 0x02,
- AC97_Headphone_Volume_Mute = 0x04, /** Also known as AUX, see table 16, section 5.7. */
- AC97_Master_Volume_Mono_Mute = 0x06,
- AC97_Master_Tone_RL = 0x08,
- AC97_PC_BEEP_Volume_Mute = 0x0A,
- AC97_Phone_Volume_Mute = 0x0C,
- AC97_Mic_Volume_Mute = 0x0E,
- AC97_Line_In_Volume_Mute = 0x10,
- AC97_CD_Volume_Mute = 0x12,
- AC97_Video_Volume_Mute = 0x14,
- AC97_Aux_Volume_Mute = 0x16,
- AC97_PCM_Out_Volume_Mute = 0x18,
- AC97_Record_Select = 0x1A,
- AC97_Record_Gain_Mute = 0x1C,
- AC97_Record_Gain_Mic_Mute = 0x1E,
- AC97_General_Purpose = 0x20,
- AC97_3D_Control = 0x22,
- AC97_AC_97_RESERVED = 0x24,
- AC97_Powerdown_Ctrl_Stat = 0x26,
- AC97_Extended_Audio_ID = 0x28,
- AC97_Extended_Audio_Ctrl_Stat = 0x2A,
- AC97_PCM_Front_DAC_Rate = 0x2C,
- AC97_PCM_Surround_DAC_Rate = 0x2E,
- AC97_PCM_LFE_DAC_Rate = 0x30,
- AC97_PCM_LR_ADC_Rate = 0x32,
- AC97_MIC_ADC_Rate = 0x34,
- AC97_6Ch_Vol_C_LFE_Mute = 0x36,
- AC97_6Ch_Vol_L_R_Surround_Mute = 0x38,
- AC97_Vendor_Reserved = 0x58,
- AC97_AD_Misc = 0x76,
- AC97_Vendor_ID1 = 0x7c,
- AC97_Vendor_ID2 = 0x7e
-};
-
-/* Codec models. */
-enum {
- Codec_STAC9700 = 0, /* SigmaTel STAC9700 */
- Codec_AD1980, /* Analog Devices AD1980 */
- Codec_AD1981B /* Analog Devices AD1981B */
-};
-
-/* Analog Devices miscellaneous regiter bits used in AD1980. */
-#define AD_MISC_LOSEL RT_BIT(5) /* Surround (rear) goes to line out outputs. */
-#define AD_MISC_HPSEL RT_BIT(10) /* PCM (front) goes to headphone outputs. */
-
-#define ICHAC97STATE_2_DEVINS(a_pAC97) ((a_pAC97)->pDevInsR3)
-
-enum
-{
- BUP_SET = RT_BIT(0),
- BUP_LAST = RT_BIT(1)
-};
-
-/** Emits registers for a specific (Native Audio Bus Master BAR) NABMBAR. */
-#define AC97_NABMBAR_REGS(prefix, off) \
- enum { \
- prefix ## _BDBAR = off, \
- prefix ## _CIV = off + 4, \
- prefix ## _LVI = off + 5, \
- prefix ## _SR = off + 6, \
- prefix ## _PICB = off + 8, \
- prefix ## _PIV = off + 10, \
- prefix ## _CR = off + 11 \
- }
-
-#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-typedef enum
-{
- PI_INDEX = 0, /** PCM in */
- PO_INDEX, /** PCM out */
- MC_INDEX, /** Mic in */
- LAST_INDEX
-} AC97SOUNDSOURCE;
-
-AC97_NABMBAR_REGS(PI, PI_INDEX * 16);
-AC97_NABMBAR_REGS(PO, PO_INDEX * 16);
-AC97_NABMBAR_REGS(MC, MC_INDEX * 16);
-#endif
-
-enum
-{
- /** NABMBAR: Global Control Register. */
- GLOB_CNT = 0x2c,
- /** NABMBAR Global Status. */
- GLOB_STA = 0x30,
- /** Codec Access Semaphore Register. */
- CAS = 0x34
-};
-
-#define AC97_PORT2IDX(a_idx) ( ((a_idx) >> 4) & 3 )
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
-
-/**
- * Buffer Descriptor List Entry (BDLE).
- */
-typedef struct AC97BDLE
-{
- uint32_t addr;
- uint32_t ctl_len;
-} AC97BDLE, *PAC97BDLE;
-
-/**
- * Bus master register set for an audio stream.
- */
-typedef struct AC97BMREGS
-{
- uint32_t bdbar; /** rw 0, Buffer Descriptor List: BAR (Base Address Register). */
- uint8_t civ; /** ro 0, Current index value. */
- uint8_t lvi; /** rw 0, Last valid index. */
- uint16_t sr; /** rw 1, Status register. */
- uint16_t picb; /** ro 0, Position in current buffer. */
- uint8_t piv; /** ro 0, Prefetched index value. */
- uint8_t cr; /** rw 0, Control register. */
- int bd_valid; /** Whether current BDLE is initialized or not. */
- AC97BDLE bd; /** Current Buffer Descriptor List Entry (BDLE). */
-} AC97BMREGS, *PAC97BMREGS;
-
-/**
- * Internal state of an AC97 stream.
- */
-typedef struct AC97STREAMSTATE
-{
- /* Nothing yet. */
-} AC97STREAMSTATE, *PAC97STREAMSTATE;
-
-/**
- * Structure for keeping an AC97 stream state.
- *
- * Contains only register values which do *not* change until a
- * stream reset occurs.
- */
-typedef struct AC97STREAM
-{
- /** Stream number (SDn). */
- uint8_t u8Strm;
- /** Bus master registers of this stream. */
- AC97BMREGS Regs;
- /** Internal state of this stream. */
- AC97STREAMSTATE State;
-} AC97STREAM, *PAC97STREAM;
-
-typedef struct AC97INPUTSTREAM
-{
- /** PCM line input stream. */
- R3PTRTYPE(PPDMAUDIOGSTSTRMIN) pStrmIn;
- /** Mixer handle for line input stream. */
- R3PTRTYPE(PAUDMIXSTREAM) phStrmIn;
-} AC97INPUTSTREAM, *PAC97INPUTSTREAM;
-
-typedef struct AC97OUTPUTSTREAM
-{
- /** PCM output stream. */
- R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
- /** Mixer handle for output stream. */
- R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
-} AC97OUTPUTSTREAM, *PAC97OUTPUTSTREAM;
-
-/**
- * Struct for maintaining a host backend driver.
- */
-typedef struct AC97STATE *PAC97STATE;
-typedef struct AC97DRIVER
-{
- /** Node for storing this driver in our device driver list of AC97STATE. */
- RTLISTNODER3 Node;
- /** Pointer to AC97 controller (state). */
- R3PTRTYPE(PAC97STATE) pAC97State;
- /** Driver flags. */
- PDMAUDIODRVFLAGS Flags;
- uint32_t PaddingFlags;
- /** LUN # to which this driver has been assigned. */
- uint8_t uLUN;
- /** Whether this driver is in an attached state or not. */
- bool fAttached;
- uint8_t Padding[4];
- /** Pointer to attached driver base interface. */
- R3PTRTYPE(PPDMIBASE) pDrvBase;
- /** Audio connector interface to the underlying host backend. */
- R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
- /** Stream for line input. */
- AC97INPUTSTREAM LineIn;
- /** Stream for mic input. */
- AC97INPUTSTREAM MicIn;
- /** Stream for output. */
- AC97OUTPUTSTREAM Out;
-} AC97DRIVER, *PAC97DRIVER;
-
-typedef struct AC97STATE
-{
- /** The PCI device state. */
- PDMPCIDEV PciDev;
- /** R3 Pointer to the device instance. */
- PPDMDEVINSR3 pDevInsR3;
- /** Global Control (Bus Master Control Register) */
- uint32_t glob_cnt;
- /** Global Status (Bus Master Control Register) */
- uint32_t glob_sta;
- /** Codec Access Semaphore Register (Bus Master Control Register) */
- uint32_t cas;
- uint32_t last_samp;
- uint8_t mixer_data[256];
- /** Stream state for line-in. */
- AC97STREAM StrmStLineIn;
- /** Stream state for microphone-in. */
- AC97STREAM StrmStMicIn;
- /** Stream state for output. */
- AC97STREAM StrmStOut;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- /** The timer for pumping data thru the attached LUN drivers. */
- PTMTIMERR3 pTimer;
- /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
- uint64_t cTimerTicks;
- /** Timestamp of the last timer callback (ac97Timer).
- * Used to calculate the time actually elapsed between two timer callbacks. */
- uint64_t uTimerTS;
-#endif
-#ifdef VBOX_WITH_STATISTICS
- STAMPROFILE StatTimer;
- STAMCOUNTER StatBytesRead;
- STAMCOUNTER StatBytesWritten;
-#endif
- /** List of associated LUN drivers (AC97DRIVER). */
- RTLISTANCHOR lstDrv;
- /** The device' software mixer. */
- R3PTRTYPE(PAUDIOMIXER) pMixer;
- /** Audio sink for PCM output. */
- R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
- /** Audio sink for line input. */
- R3PTRTYPE(PAUDMIXSINK) pSinkLineIn;
- /** Audio sink for microphone input. */
- R3PTRTYPE(PAUDMIXSINK) pSinkMicIn;
- uint8_t silence[128];
- int bup_flag;
- /** The base interface for LUN\#0. */
- PDMIBASE IBase;
- /** Base port of the I/O space region. */
- RTIOPORT IOPortBase[2];
- /** Pointer to temporary scratch read/write buffer. */
- R3PTRTYPE(uint8_t *) pvReadWriteBuf;
- /** Size of the temporary scratch read/write buffer. */
- uint32_t cbReadWriteBuf;
- /** Codec model. */
- uint32_t uCodecModel;
-} AC97STATE, *PAC97STATE;
-
-#ifdef VBOX_WITH_STATISTICS
-AssertCompileMemberAlignment(AC97STATE, StatTimer, 8);
-#endif
-
-#ifndef VBOX_DEVICE_STRUCT_TESTCASE
-
-DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID);
-static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns);
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
-static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser);
-#endif
-static int ichac97TransferAudio(PAC97STATE pThis, AC97SOUNDSOURCE enmSrc, uint32_t cbElapsed);
-
-static void ichac97WarmReset(PAC97STATE pThis)
-{
- NOREF(pThis);
-}
-
-static void ichac97ColdReset(PAC97STATE pThis)
-{
- NOREF(pThis);
-}
-
-/** Fetches the buffer descriptor at _CIV. */
-static void ichac97StreamFetchBDLE(PAC97STATE pThis, PAC97STREAM pStrmSt)
-{
- PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
- PAC97BMREGS pRegs = &pStrmSt->Regs;
-
- uint32_t u32[2];
-
- PDMDevHlpPhysRead(pDevIns, pRegs->bdbar + pRegs->civ * 8, &u32[0], sizeof(u32));
- pRegs->bd_valid = 1;
-#if !defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64)
-# error Please adapt the code (audio buffers are little endian)!
-#else
- pRegs->bd.addr = RT_H2LE_U32(u32[0] & ~3);
- pRegs->bd.ctl_len = RT_H2LE_U32(u32[1]);
-#endif
- pRegs->picb = pRegs->bd.ctl_len & 0xffff;
- LogFlowFunc(("bd %2d addr=%#x ctl=%#06x len=%#x(%d bytes)\n",
- pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len >> 16,
- pRegs->bd.ctl_len & 0xffff, (pRegs->bd.ctl_len & 0xffff) << 1));
-}
-
-/**
- * Update the BM status register
- */
-static void ichac97StreamUpdateStatus(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t new_sr)
-{
- PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
- PAC97BMREGS pRegs = &pStrmSt->Regs;
-
- bool fSignal = false;
- bool iIrqLevel = 0;
-
- uint32_t new_mask = new_sr & SR_INT_MASK;
- uint32_t old_mask = pRegs->sr & SR_INT_MASK;
-
- static uint32_t const masks[] = { GS_PIINT, GS_POINT, GS_MINT };
-
- if (new_mask ^ old_mask)
- {
- /** @todo Is IRQ deasserted when only one of status bits is cleared? */
- if (!new_mask)
- {
- fSignal = true;
- iIrqLevel = 0;
- }
- else if ((new_mask & SR_LVBCI) && (pRegs->cr & CR_LVBIE))
- {
- fSignal = true;
- iIrqLevel = 1;
- }
- else if ((new_mask & SR_BCIS) && (pRegs->cr & CR_IOCE))
- {
- fSignal = true;
- iIrqLevel = 1;
- }
- }
-
- pRegs->sr = new_sr;
-
- LogFlowFunc(("IOC%d, LVB%d, sr=%#x, fSignal=%RTbool, iIrqLevel=%d\n",
- pRegs->sr & SR_BCIS, pRegs->sr & SR_LVBCI, pRegs->sr, fSignal, iIrqLevel));
-
- if (fSignal)
- {
- if (iIrqLevel)
- pThis->glob_sta |= masks[pStrmSt->u8Strm];
- else
- pThis->glob_sta &= ~masks[pStrmSt->u8Strm];
-
- LogFlowFunc(("set irq level=%d\n", !!iIrqLevel));
- PDMDevHlpPCISetIrq(pDevIns, 0, !!iIrqLevel);
- }
-}
-
-static int ichac97StreamSetActive(PAC97STATE pThis, PAC97STREAM pStrmSt, bool fActive)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
-
- LogFlowFunc(("u8Strm=%RU8, fActive=%RTbool\n", pStrmSt->u8Strm, fActive));
-
- int rc = VINF_SUCCESS;
-
- PAC97DRIVER pDrv;
- switch (pStrmSt->u8Strm)
- {
- case PI_INDEX:
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
- pDrv->LineIn.pStrmIn, fActive);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
- break;
-
- case PO_INDEX:
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
- pDrv->Out.pStrmOut, fActive);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
- break;
-
- case MC_INDEX:
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnEnableIn(pDrv->pConnector,
- pDrv->MicIn.pStrmIn, fActive);
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
- break;
-
- default:
- AssertMsgFailed(("Wrong index %RU32\n", pStrmSt->u8Strm));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- return rc;
-}
-
-static void ichac97StreamResetBMRegs(PAC97STATE pThis, PAC97STREAM pStrmSt)
-{
- AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStrmSt);
-
- LogFlowFuncEnter();
-
- PAC97BMREGS pRegs = &pStrmSt->Regs;
-
- pRegs->bdbar = 0;
- pRegs->civ = 0;
- pRegs->lvi = 0;
-
- ichac97StreamUpdateStatus(pThis, pStrmSt, SR_DCH); /** @todo Do we need to do that? */
-
- pRegs->picb = 0;
- pRegs->piv = 0;
- pRegs->cr = pRegs->cr & CR_DONT_CLEAR_MASK;
- pRegs->bd_valid = 0;
-
- int rc = ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
- AssertRC(rc);
-
- RT_ZERO(pThis->silence);
-}
-
-static void ichac97MixerSet(PAC97STATE pThis, uint32_t u8Idx, uint16_t v)
-{
- if (u8Idx + 2 > sizeof(pThis->mixer_data))
- {
- AssertMsgFailed(("Index %RU8 out of bounds(%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
- return;
- }
-
- pThis->mixer_data[u8Idx + 0] = RT_LO_U8(v);
- pThis->mixer_data[u8Idx + 1] = RT_HI_U8(v);
-}
-
-static uint16_t ichac97MixerGet(PAC97STATE pThis, uint32_t u8Idx)
-{
- uint16_t uVal;
-
- if (u8Idx + 2 > sizeof(pThis->mixer_data))
- {
- AssertMsgFailed(("Index %RU8 out of bounds (%zu)\n", u8Idx, sizeof(pThis->mixer_data)));
- uVal = UINT16_MAX;
- }
- else
- uVal = RT_MAKE_U16(pThis->mixer_data[u8Idx + 0], pThis->mixer_data[u8Idx + 1]);
-
- return uVal;
-}
-
-#if 0 // unused
-static DECLCALLBACK(void) ichac97CloseIn(PAC97STATE pThis, PDMAUDIORECSOURCE enmRecSource)
-{
- NOREF(pThis);
- NOREF(enmRecSource);
- LogFlowFuncEnter();
-}
-
-static DECLCALLBACK(void) ichac97CloseOut(PAC97STATE pThis)
-{
- NOREF(pThis);
- LogFlowFuncEnter();
-}
-#endif
-
-static int ichac97OpenIn(PAC97STATE pThis,
- const char *pszName, PDMAUDIORECSOURCE enmRecSource,
- PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- PAUDMIXSINK pSink;
- switch (enmRecSource)
- {
- case PDMAUDIORECSOURCE_MIC:
- pSink = pThis->pSinkMicIn;
- break;
- case PDMAUDIORECSOURCE_LINE_IN:
- pSink = pThis->pSinkLineIn;
- break;
- default:
- AssertMsgFailed(("Audio source %ld not supported\n", enmRecSource));
- return VERR_NOT_SUPPORTED;
- }
-
- int rc = VINF_SUCCESS;
-
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- char *pszDesc;
- if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s", pDrv->uLUN, pszName) <= 0)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
- PAC97INPUTSTREAM pStrmIn;
- if (enmRecSource == PDMAUDIORECSOURCE_MIC) /** @todo Refine this once we have more streams. */
- pStrmIn = &pDrv->MicIn;
- else
- pStrmIn = &pDrv->LineIn;
-
- rc = pDrv->pConnector->pfnCreateIn(pDrv->pConnector, pszDesc, enmRecSource, pCfg, &pStrmIn->pStrmIn);
-
- LogFlowFunc(("LUN#%RU8: Created input \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
- if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
- {
- AudioMixerRemoveStream(pSink, pStrmIn->phStrmIn);
- rc = AudioMixerAddStreamIn(pSink,
- pDrv->pConnector, pStrmIn->pStrmIn,
- 0 /* uFlags */, &pStrmIn->phStrmIn);
- }
-
- RTStrFree(pszDesc);
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static int ichac97OpenOut(PAC97STATE pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- int rc = VINF_SUCCESS;
- char *pszDesc;
-
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] %s (%RU32Hz, %RU8 %s)",
- pDrv->uLUN, pszName, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel") <= 0)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
- rc = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
- LogFlowFunc(("LUN#%RU8: Created output \"%s\", with rc=%Rrc\n", pDrv->uLUN, pszDesc, rc));
- if (rc == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
- {
- AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
- rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
- pDrv->pConnector, pDrv->Out.pStrmOut,
- 0 /* uFlags */, &pDrv->Out.phStrmOut);
- }
-
- RTStrFree(pszDesc);
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static int ichac97StreamInitEx(PAC97STATE pThis, PAC97STREAM pStrmSt, uint8_t u8Strm, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- AssertReturn(u8Strm <= LAST_INDEX, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- pStrmSt->u8Strm = u8Strm;
-
- LogFlowFunc(("u8Strm=%RU8, %RU32Hz, %RU8 %s\n",
- pStrmSt->u8Strm, pCfg->uHz, pCfg->cChannels, pCfg->cChannels > 1 ? "Channels" : "Channel"));
-
- int rc;
- switch (pStrmSt->u8Strm)
- {
- case PI_INDEX:
- rc = ichac97OpenIn(pThis, "ac97.pi", PDMAUDIORECSOURCE_LINE_IN, pCfg);
- break;
-
- case MC_INDEX:
- rc = ichac97OpenIn(pThis, "ac97.mc", PDMAUDIORECSOURCE_MIC, pCfg);
- break;
-
- case PO_INDEX:
- rc = ichac97OpenOut(pThis, "ac97.po", pCfg);
- break;
-
- default:
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static int ichac97StreamInit(PAC97STATE pThis, PAC97STREAM pStrmSt, uint8_t u8Strm)
-{
- int rc = VINF_SUCCESS;
-
- PDMAUDIOSTREAMCFG streamCfg;
- RT_ZERO(streamCfg);
-
- switch (u8Strm)
- {
- case PI_INDEX:
- streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_LR_ADC_Rate);
- break;
-
- case MC_INDEX:
- streamCfg.uHz = ichac97MixerGet(pThis, AC97_MIC_ADC_Rate);
- break;
-
- case PO_INDEX:
- streamCfg.uHz = ichac97MixerGet(pThis, AC97_PCM_Front_DAC_Rate);
- break;
-
- default:
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- if (RT_FAILURE(rc))
- return rc;
-
- if (streamCfg.uHz)
- {
- streamCfg.cChannels = 2;
- streamCfg.enmFormat = AUD_FMT_S16;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- return ichac97StreamInitEx(pThis, pStrmSt, u8Strm, &streamCfg);
- }
-
- /* If no frequency is given, disable the stream. */
- return ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
-}
-
-static int ichac97StreamReInit(PAC97STATE pThis, PAC97STREAM pStrmSt)
-{
- return ichac97StreamInit(pThis, pStrmSt, pStrmSt->u8Strm);
-}
-
-static void ichac97StreamReset(PAC97STATE pThis, PAC97STREAM pStrmSt)
-{
- AssertPtrReturnVoid(pThis);
- AssertPtrReturnVoid(pStrmSt);
-
- LogFlowFunc(("uStrm=%RU8\n", pStrmSt->u8Strm));
-}
-
-static int ichac97MixerSetVolume(PAC97STATE pThis, int index, PDMAUDIOMIXERCTL mt, uint32_t val)
-{
- int mute = (val >> MUTE_SHIFT) & 1;
- uint8_t rvol = val & VOL_MASK;
- uint8_t lvol = (val >> 8) & VOL_MASK;
-
- /* For the master volume, 0 corresponds to 0dB gain. But for the other
- * volume controls, 0 corresponds to +12dB and 8 to 0dB. */
- if (mt != PDMAUDIOMIXERCTL_VOLUME)
- {
- /* NB: Currently there is no gain support, only attenuation. */
- lvol = lvol < 8 ? 0 : lvol - 8;
- rvol = rvol < 8 ? 0 : rvol - 8;
- }
-
- /* AC'97 has 1.5dB steps; we use 0.375dB steps. */
- rvol = 255 - rvol * 4;
- lvol = 255 - lvol * 4;
-
- LogFunc(("mt=%ld, val=%RX32, mute=%RTbool\n", mt, val, RT_BOOL(mute)));
-
- int rc;
-
-#ifdef SOFT_VOLUME
- if (pThis->pMixer) /* Device can be in reset state, so no mixer available. */
- {
- PDMAUDIOVOLUME vol = { RT_BOOL(mute), lvol, rvol };
- switch (mt)
- {
- case PDMAUDIOMIXERCTL_VOLUME:
- rc = AudioMixerSetMasterVolume(pThis->pMixer, &vol);
- break;
-
- case PDMAUDIOMIXERCTL_PCM:
- rc = AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
- break;
-
- case PDMAUDIOMIXERCTL_MIC_IN:
- rc = AudioMixerSetSinkVolume(pThis->pSinkMicIn, &vol);
- break;
-
- case PDMAUDIOMIXERCTL_LINE_IN:
- rc = AudioMixerSetSinkVolume(pThis->pSinkLineIn, &vol);
- break;
-
- default:
- rc = VERR_NOT_SUPPORTED;
- break;
- }
- }
- else
- rc = VERR_NOT_SUPPORTED;
-
- if (RT_FAILURE(rc))
- return rc;
-#else
- rc = VINF_SUCCESS;
-#endif /* SOFT_VOLUME */
-
- rvol = VOL_MASK - ((VOL_MASK * rvol) / 255);
- lvol = VOL_MASK - ((VOL_MASK * lvol) / 255);
-
- /*
- * From AC'97 SoundMax Codec AD1981A: "Because AC '97 defines 6-bit volume registers, to
- * maintain compatibility whenever the D5 or D13 bits are set to `1,' their respective
- * lower five volume bits are automatically set to `1' by the Codec logic. On readback,
- * all lower 5 bits will read ones whenever these bits are set to `1.'"
- *
- * Linux ALSA depends on this behavior.
- */
- if (val & RT_BIT(5))
- val |= RT_BIT(4) | RT_BIT(3) | RT_BIT(2) | RT_BIT(1) | RT_BIT(0);
- if (val & RT_BIT(13))
- val |= RT_BIT(12) | RT_BIT(11) | RT_BIT(10) | RT_BIT(9) | RT_BIT(8);
-
- ichac97MixerSet(pThis, index, val);
-
- return rc;
-}
-
-static PDMAUDIORECSOURCE ichac97IndextoRecSource(uint8_t i)
-{
- switch (i)
- {
- case REC_MIC: return PDMAUDIORECSOURCE_MIC;
- case REC_CD: return PDMAUDIORECSOURCE_CD;
- case REC_VIDEO: return PDMAUDIORECSOURCE_VIDEO;
- case REC_AUX: return PDMAUDIORECSOURCE_AUX;
- case REC_LINE_IN: return PDMAUDIORECSOURCE_LINE_IN;
- case REC_PHONE: return PDMAUDIORECSOURCE_PHONE;
- default:
- break;
- }
-
- LogFlowFunc(("Unknown record source %d, using MIC\n", i));
- return PDMAUDIORECSOURCE_MIC;
-}
-
-static uint8_t ichac97RecSourceToIndex(PDMAUDIORECSOURCE rs)
-{
- switch (rs)
- {
- case PDMAUDIORECSOURCE_MIC: return REC_MIC;
- case PDMAUDIORECSOURCE_CD: return REC_CD;
- case PDMAUDIORECSOURCE_VIDEO: return REC_VIDEO;
- case PDMAUDIORECSOURCE_AUX: return REC_AUX;
- case PDMAUDIORECSOURCE_LINE_IN: return REC_LINE_IN;
- case PDMAUDIORECSOURCE_PHONE: return REC_PHONE;
- default:
- break;
- }
-
- LogFlowFunc(("Unknown audio recording source %d using MIC\n", rs));
- return REC_MIC;
-}
-
-static void ichac97RecordSelect(PAC97STATE pThis, uint32_t val)
-{
- uint8_t rs = val & REC_MASK;
- uint8_t ls = (val >> 8) & REC_MASK;
- PDMAUDIORECSOURCE ars = ichac97IndextoRecSource(rs);
- PDMAUDIORECSOURCE als = ichac97IndextoRecSource(ls);
- //AUD_set_record_source(&als, &ars);
- rs = ichac97RecSourceToIndex(ars);
- ls = ichac97RecSourceToIndex(als);
- ichac97MixerSet(pThis, AC97_Record_Select, rs | (ls << 8));
-}
-
-static int ichac97MixerReset(PAC97STATE pThis)
-{
- AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
-
- LogFlowFuncEnter();
-
- RT_ZERO(pThis->mixer_data);
-
- /* Note: Make sure to reset all registers first before bailing out on error. */
-
- ichac97MixerSet(pThis, AC97_Reset , 0x0000); /* 6940 */
- ichac97MixerSet(pThis, AC97_Master_Volume_Mono_Mute , 0x8000);
- ichac97MixerSet(pThis, AC97_PC_BEEP_Volume_Mute , 0x0000);
-
- ichac97MixerSet(pThis, AC97_Phone_Volume_Mute , 0x8008);
- ichac97MixerSet(pThis, AC97_Mic_Volume_Mute , 0x8008);
- ichac97MixerSet(pThis, AC97_CD_Volume_Mute , 0x8808);
- ichac97MixerSet(pThis, AC97_Aux_Volume_Mute , 0x8808);
- ichac97MixerSet(pThis, AC97_Record_Gain_Mic_Mute , 0x8000);
- ichac97MixerSet(pThis, AC97_General_Purpose , 0x0000);
- ichac97MixerSet(pThis, AC97_3D_Control , 0x0000);
- ichac97MixerSet(pThis, AC97_Powerdown_Ctrl_Stat , 0x000f);
-
- ichac97MixerSet(pThis, AC97_Extended_Audio_ID , 0x0809);
- ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, 0x0009);
- ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate , 0xbb80);
- ichac97MixerSet(pThis, AC97_PCM_Surround_DAC_Rate , 0xbb80);
- ichac97MixerSet(pThis, AC97_PCM_LFE_DAC_Rate , 0xbb80);
- ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate , 0xbb80);
- ichac97MixerSet(pThis, AC97_MIC_ADC_Rate , 0xbb80);
-
- if (pThis->uCodecModel == Codec_AD1980)
- {
- /* Analog Devices 1980 (AD1980) */
- ichac97MixerSet(pThis, AC97_Reset , 0x0010); /* Headphones. */
- ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
- ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5370);
- ichac97MixerSet(pThis, AC97_Headphone_Volume_Mute , 0x8000);
- }
- else if (pThis->uCodecModel == Codec_AD1981B)
- {
- /* Analog Devices 1981B (AD1981B) */
- ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x4144);
- ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x5374);
- }
- else
- {
- /* Sigmatel 9700 (STAC9700) */
- ichac97MixerSet(pThis, AC97_Vendor_ID1 , 0x8384);
- ichac97MixerSet(pThis, AC97_Vendor_ID2 , 0x7600); /* 7608 */
- }
- ichac97RecordSelect(pThis, 0);
-
- ichac97MixerSetVolume(pThis, AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME, 0x8000);
- ichac97MixerSetVolume(pThis, AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM, 0x8808);
- ichac97MixerSetVolume(pThis, AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN, 0x8808);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Writes data from the device to the host backends.
- *
- * @return IPRT status code.
- * @param pThis
- * @param pStrmSt
- * @param cbMax
- * @param pcbWritten
- */
-static int ichac97WriteAudio(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t cbMax, uint32_t *pcbWritten)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- AssertReturn(cbMax, VERR_INVALID_PARAMETER);
- /* pcbWritten is optional. */
-
- PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
- PAC97BMREGS pRegs = &pStrmSt->Regs;
-
- uint32_t addr = pRegs->bd.addr;
- uint32_t cbWrittenTotal = 0;
- uint32_t cbToRead = 0;
-
- uint32_t cbToWrite = RT_MIN((uint32_t)(pRegs->picb << 1), cbMax);
- if (!cbToWrite)
- {
- if (pcbWritten)
- *pcbWritten = 0;
- return VINF_EOF;
- }
-
- int rc = VINF_SUCCESS;
-
- LogFlowFunc(("pReg=%p, cbMax=%RU32, cbToWrite=%RU32\n", pRegs, cbMax, cbToWrite));
-
- while (cbToWrite)
- {
- cbToRead = RT_MIN(cbToWrite, pThis->cbReadWriteBuf);
- PDMDevHlpPhysRead(pDevIns, addr, pThis->pvReadWriteBuf, cbToRead); /** @todo Check rc? */
-
- uint32_t cbWritten;
-
- /* Just multiplex the output to the connected backends.
- * No need to utilize the virtual mixer here (yet). */
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
- pThis->pvReadWriteBuf, cbToRead, &cbWritten);
- RT_NOREF(rc2);
- LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWritten=%RU32\n", pDrv->uLUN, rc2, cbWritten));
- }
-
- LogFlowFunc(("\tcbToRead=%RU32, cbToWrite=%RU32, cbLeft=%RU32\n",
- cbToRead, cbToWrite, cbToWrite - cbWrittenTotal));
-
- Assert(cbToWrite >= cbToRead);
- cbToWrite -= cbToRead;
- addr += cbToRead;
- cbWrittenTotal += cbToRead;
- }
-
- pRegs->bd.addr = addr;
-
- if (RT_SUCCESS(rc))
- {
- if (!cbToWrite) /* All data written? */
- {
- if (cbToRead < 4)
- {
- AssertMsgFailed(("Unable to save last written sample, cbToRead < 4 (is %RU32)\n", cbToRead));
- pThis->last_samp = 0;
- }
- else
- pThis->last_samp = *(uint32_t *)&pThis->pvReadWriteBuf[cbToRead - 4];
- }
-
- if (pcbWritten)
- *pcbWritten = cbWrittenTotal;
- }
-
- LogFlowFunc(("cbWrittenTotal=%RU32, rc=%Rrc\n", cbWrittenTotal, rc));
- return rc;
-}
-
-static void ichac97WriteBUP(PAC97STATE pThis, uint32_t cbElapsed)
-{
- if (!(pThis->bup_flag & BUP_SET))
- {
- if (pThis->bup_flag & BUP_LAST)
- {
- unsigned int i;
- uint32_t *p = (uint32_t*)pThis->silence;
- for (i = 0; i < sizeof(pThis->silence) / 4; i++)
- *p++ = pThis->last_samp;
- }
- else
- RT_ZERO(pThis->silence);
-
- pThis->bup_flag |= BUP_SET;
- }
-
- while (cbElapsed)
- {
- uint32_t cbToWrite = RT_MIN(cbElapsed, (uint32_t)sizeof(pThis->silence));
- uint32_t cbWrittenToStream;
- int rc2;
-
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- if (pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut))
- {
- rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
- pThis->silence, cbToWrite, &cbWrittenToStream);
- if (RT_SUCCESS(rc2))
- {
- if (cbWrittenToStream < cbToWrite) /* Lagging behind? */
- LogFlowFunc(("\tLUN#%RU8: Warning: Only written %RU32 / %RU32 bytes, expect lags\n",
- pDrv->uLUN, cbWrittenToStream, cbToWrite));
- }
- }
- else /* Stream disabled, not fatal. */
- {
- cbWrittenToStream = 0;
- rc2 = VERR_NOT_AVAILABLE;
- /* Keep going. */
- }
- }
-
- /* Always report all data as being written;
- * backends who were not able to catch up have to deal with it themselves. */
- Assert(cbElapsed >= cbToWrite);
- cbElapsed -= cbToWrite;
- }
-}
-
-static int ichac97ReadAudio(PAC97STATE pThis, PAC97STREAM pStrmSt, uint32_t cbMax, uint32_t *pcbRead)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pStrmSt, VERR_INVALID_POINTER);
- AssertReturn(cbMax, VERR_INVALID_PARAMETER);
- /* pcbRead is optional. */
-
- PPDMDEVINS pDevIns = ICHAC97STATE_2_DEVINS(pThis);
- PAC97BMREGS pRegs = &pStrmSt->Regs;
-
- /* Select audio sink to process. */
- AssertMsg(pStrmSt->u8Strm != PO_INDEX, ("Can't read from output\n"));
- PAUDMIXSINK pSink = pStrmSt->u8Strm == MC_INDEX ? pThis->pSinkMicIn : pThis->pSinkLineIn;
- AssertPtr(pSink);
-
- uint32_t cbRead = 0;
-
- uint32_t cbMixBuf = cbMax;
- uint32_t cbToRead = RT_MIN((uint32_t)(pRegs->picb << 1), cbMixBuf);
-
- if (!cbToRead)
- {
- if (pcbRead)
- *pcbRead = 0;
- return VINF_EOF;
- }
-
- int rc;
-
- uint8_t *pvMixBuf = (uint8_t *)RTMemAlloc(cbMixBuf);
- if (pvMixBuf)
- {
- rc = AudioMixerProcessSinkIn(pSink, AUDMIXOP_BLEND, pvMixBuf, cbToRead, &cbRead);
- if ( RT_SUCCESS(rc)
- && cbRead)
- {
- PDMDevHlpPCIPhysWrite(pDevIns, pRegs->bd.addr, pvMixBuf, cbRead);
- pRegs->bd.addr += cbRead;
- }
-
- RTMemFree(pvMixBuf);
- }
- else
- rc = VERR_NO_MEMORY;
-
- if (RT_SUCCESS(rc))
- {
- if (pcbRead)
- *pcbRead = cbRead;
- }
-
- return rc;
-}
-
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
-
-static DECLCALLBACK(void) ichac97Timer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
-{
- RT_NOREF(pDevIns);
- PAC97STATE pThis = (PAC97STATE)pvUser;
- Assert(pThis == PDMINS_2_DATA(pDevIns, PAC97STATE));
- AssertPtr(pThis);
-
- STAM_PROFILE_START(&pThis->StatTimer, a);
-
- uint32_t cbInMax = 0;
- uint32_t cbOutMin = UINT32_MAX;
-
- PAC97DRIVER pDrv;
-
- uint64_t cTicksNow = TMTimerGet(pTimer);
- uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTS;
- uint64_t cTicksPerSec = TMTimerGetFreq(pTimer);
-
- pThis->uTimerTS = cTicksNow;
-
- /*
- * Calculate the mixer's (fixed) sampling rate.
- */
- AssertPtr(pThis->pMixer);
-
- PDMAUDIOSTREAMCFG mixerStrmCfg;
- int rc = AudioMixerGetDeviceFormat(pThis->pMixer, &mixerStrmCfg);
- AssertRC(rc);
-
- PDMPCMPROPS mixerStrmProps;
- rc = DrvAudioStreamCfgToProps(&mixerStrmCfg, &mixerStrmProps);
- AssertRC(rc);
-
- uint32_t cMixerSamplesMin = (int)((2 * cTicksElapsed * mixerStrmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
- uint32_t cbMixerSamplesMin = cMixerSamplesMin << mixerStrmProps.cShift;
-
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- uint32_t cbIn = 0;
- uint32_t cbOut = 0;
-
- rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
- &cbIn, &cbOut, NULL /* cSamplesLive */);
- if (RT_SUCCESS(rc))
- rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* cSamplesPlayed */);
-
- Log3Func(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
-
- /* If we there was an error handling (available) output or there simply is no output available,
- * then calculate the minimum data rate which must be processed by the device emulation in order
- * to function correctly.
- *
- * This is not the optimal solution, but as we have to deal with this on a timer-based approach
- * (until we have the audio callbacks) we need to have device' DMA engines running. */
- if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
- {
- /* Use the mixer's (fixed) sampling rate. */
- cbOut = RT_MAX(cbOut, cbMixerSamplesMin);
- }
- else
- {
- const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
- if ( RT_FAILURE(rc)
- || !fIsActiveOut)
- {
- uint32_t cSamplesMin = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
- uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
-
- Log3Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
-
- cbOut = RT_MAX(cbOut, cbSamplesMin);
- }
- }
-
- cbOutMin = RT_MIN(cbOutMin, cbOut);
- cbInMax = RT_MAX(cbInMax, cbIn);
- }
-
- Log3Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
-
- if (cbOutMin == UINT32_MAX)
- cbOutMin = 0;
-
- /*
- * Playback.
- */
- if (cbOutMin)
- {
- Assert(cbOutMin != UINT32_MAX);
- ichac97TransferAudio(pThis, PO_INDEX, cbOutMin); /** @todo Add rc! */
- }
-
- /*
- * Recording.
- */
- if (cbInMax)
- ichac97TransferAudio(pThis, PI_INDEX, cbInMax); /** @todo Add rc! */
-
- /* Kick the timer again. */
- uint64_t cTicks = pThis->cTimerTicks;
- /** @todo adjust cTicks down by now much cbOutMin represents. */
- TMTimerSet(pThis->pTimer, cTicksNow + cTicks);
-
- STAM_PROFILE_STOP(&pThis->StatTimer, a);
-}
-
-#endif
-
-static int ichac97TransferAudio(PAC97STATE pThis, AC97SOUNDSOURCE enmSrc, uint32_t cbElapsed)
-{
- LogFlowFunc(("pThis=%p, enmSrc=%RU32, cbElapsed=%RU32\n", pThis, enmSrc, cbElapsed));
-
- PAC97STREAM pStrmSt;
- switch (enmSrc)
- {
- case PI_INDEX: pStrmSt = &pThis->StrmStLineIn; break;
- case MC_INDEX: pStrmSt = &pThis->StrmStMicIn; break;
- case PO_INDEX: pStrmSt = &pThis->StrmStOut; break;
- default:
- {
- AssertMsgFailed(("Unknown source index %ld\n", enmSrc));
- return VERR_NOT_SUPPORTED;
- }
- }
-
- PAC97BMREGS pRegs = &pStrmSt->Regs;
-
- if (pRegs->sr & SR_DCH) /* Controller halted? */
- {
- if (pRegs->cr & CR_RPBM)
- {
- switch (enmSrc)
- {
- case PO_INDEX:
- ichac97WriteBUP(pThis, cbElapsed);
- break;
-
- default:
- break;
- }
- }
-
- return VINF_SUCCESS;
- }
-
- int rc = VINF_SUCCESS;
- uint32_t cbWrittenTotal = 0;
-
- while (cbElapsed >> 1)
- {
- if (!pRegs->bd_valid)
- {
- LogFlowFunc(("Invalid buffer descriptor, fetching next one ...\n"));
- ichac97StreamFetchBDLE(pThis, pStrmSt);
- }
-
- if (!pRegs->picb) /* Got a new buffer descriptor, that is, the position is 0? */
- {
- LogFlowFunc(("Fresh buffer descriptor %RU8 is empty, addr=%#x, len=%#x, skipping\n",
- pRegs->civ, pRegs->bd.addr, pRegs->bd.ctl_len));
- if (pRegs->civ == pRegs->lvi)
- {
- pRegs->sr |= SR_DCH; /* CELV? */
- pThis->bup_flag = 0;
-
- rc = VINF_EOF;
- break;
- }
-
- pRegs->sr &= ~SR_CELV;
- pRegs->civ = pRegs->piv;
- pRegs->piv = (pRegs->piv + 1) % 32;
-
- ichac97StreamFetchBDLE(pThis, pStrmSt);
- continue;
- }
-
- uint32_t cbTransferred;
- switch (enmSrc)
- {
- case PO_INDEX:
- {
- rc = ichac97WriteAudio(pThis, pStrmSt, cbElapsed, &cbTransferred);
- if ( RT_SUCCESS(rc)
- && cbTransferred)
- {
- cbWrittenTotal += cbTransferred;
- Assert(cbElapsed >= cbTransferred);
- cbElapsed -= cbTransferred;
- Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
- pRegs->picb -= (cbTransferred >> 1);
- }
- break;
- }
-
- case PI_INDEX:
- case MC_INDEX:
- {
- rc = ichac97ReadAudio(pThis, pStrmSt, cbElapsed, &cbTransferred);
- if ( RT_SUCCESS(rc)
- && cbTransferred)
- {
- Assert(cbElapsed >= cbTransferred);
- cbElapsed -= cbTransferred;
- Assert((cbTransferred & 1) == 0); /* Else the following shift won't work */
- pRegs->picb -= (cbTransferred >> 1);
- }
- break;
- }
-
- default:
- AssertMsgFailed(("Source %RU32 not supported\n", enmSrc));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- LogFlowFunc(("pReg->picb=%#x, cbWrittenTotal=%RU32\n", pRegs->picb, cbWrittenTotal));
-
- if (!pRegs->picb)
- {
- uint32_t new_sr = pRegs->sr & ~SR_CELV;
-
- if (pRegs->bd.ctl_len & BD_IOC)
- {
- new_sr |= SR_BCIS;
- }
-
- if (pRegs->civ == pRegs->lvi)
- {
- LogFlowFunc(("Underrun civ (%RU8) == lvi (%RU8)\n", pRegs->civ, pRegs->lvi));
- new_sr |= SR_LVBCI | SR_DCH | SR_CELV;
- pThis->bup_flag = (pRegs->bd.ctl_len & BD_BUP) ? BUP_LAST : 0;
-
- rc = VINF_EOF;
- }
- else
- {
- pRegs->civ = pRegs->piv;
- pRegs->piv = (pRegs->piv + 1) % 32;
- ichac97StreamFetchBDLE(pThis, pStrmSt);
- }
-
- ichac97StreamUpdateStatus(pThis, pStrmSt, new_sr);
- }
-
- if ( RT_FAILURE(rc)
- || rc == VINF_EOF) /* All data processed? */
- {
- break;
- }
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * @callback_method_impl{FNIOMIOPORTIN}
- */
-static DECLCALLBACK(int) ichac97IOPortNABMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
- uint32_t *pu32Val, unsigned cbVal)
-{
- RT_NOREF(pDevIns);
- PAC97STATE pThis = (PAC97STATE)pvUser;
-
- /* Get the index of the NABMBAR port. */
- const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
-
- PAC97STREAM pStrmSt = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
- PAC97BMREGS pRegs = pStrmSt ? &pStrmSt->Regs : NULL;
-
- switch (cbVal)
- {
- case 1:
- {
- switch (uPortIdx)
- {
- case CAS:
- /* Codec Access Semaphore Register */
- LogFlowFunc(("CAS %d\n", pThis->cas));
- *pu32Val = pThis->cas;
- pThis->cas = 1;
- break;
- case PI_CIV:
- case PO_CIV:
- case MC_CIV:
- /* Current Index Value Register */
- *pu32Val = pRegs->civ;
- LogFlowFunc(("CIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
- break;
- case PI_LVI:
- case PO_LVI:
- case MC_LVI:
- /* Last Valid Index Register */
- *pu32Val = pRegs->lvi;
- LogFlowFunc(("LVI[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
- break;
- case PI_PIV:
- case PO_PIV:
- case MC_PIV:
- /* Prefetched Index Value Register */
- *pu32Val = pRegs->piv;
- LogFlowFunc(("PIV[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
- break;
- case PI_CR:
- case PO_CR:
- case MC_CR:
- /* Control Register */
- *pu32Val = pRegs->cr;
- LogFlowFunc(("CR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
- break;
- case PI_SR:
- case PO_SR:
- case MC_SR:
- /* Status Register (lower part) */
- *pu32Val = pRegs->sr & 0xff; /** @todo r=andy Use RT_LO_U8. */
- LogFlowFunc(("SRb[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
- break;
- default:
- *pu32Val = UINT32_MAX;
- LogFlowFunc(("U nabm readb %#x -> %#x\n", Port, *pu32Val));
- break;
- }
- break;
- }
-
- case 2:
- {
- switch (uPortIdx)
- {
- case PI_SR:
- case PO_SR:
- case MC_SR:
- /* Status Register */
- *pu32Val = pRegs->sr;
- LogFlowFunc(("SR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
- break;
- case PI_PICB:
- case PO_PICB:
- case MC_PICB:
- /* Position in Current Buffer Register */
- *pu32Val = pRegs->picb;
- LogFlowFunc(("PICB[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
- break;
- default:
- *pu32Val = UINT32_MAX;
- LogFlowFunc(("U nabm readw %#x -> %#x\n", Port, *pu32Val));
- break;
- }
- break;
- }
-
- case 4:
- {
- switch (uPortIdx)
- {
- case PI_BDBAR:
- case PO_BDBAR:
- case MC_BDBAR:
- /* Buffer Descriptor Base Address Register */
- *pu32Val = pRegs->bdbar;
- LogFlowFunc(("BMADDR[%d] -> %#x\n", AC97_PORT2IDX(uPortIdx), *pu32Val));
- break;
- case PI_CIV:
- case PO_CIV:
- case MC_CIV:
- /* 32-bit access: Current Index Value Register +
- * Last Valid Index Register +
- * Status Register */
- *pu32Val = pRegs->civ | (pRegs->lvi << 8) | (pRegs->sr << 16); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
- LogFlowFunc(("CIV LVI SR[%d] -> %#x, %#x, %#x\n",
- AC97_PORT2IDX(uPortIdx), pRegs->civ, pRegs->lvi, pRegs->sr));
- break;
- case PI_PICB:
- case PO_PICB:
- case MC_PICB:
- /* 32-bit access: Position in Current Buffer Register +
- * Prefetched Index Value Register +
- * Control Register */
- *pu32Val = pRegs->picb | (pRegs->piv << 16) | (pRegs->cr << 24); /** @todo r=andy Use RT_MAKE_U32_FROM_U8. */
- LogFlowFunc(("PICB PIV CR[%d] -> %#x %#x %#x %#x\n",
- AC97_PORT2IDX(uPortIdx), *pu32Val, pRegs->picb, pRegs->piv, pRegs->cr));
- break;
- case GLOB_CNT:
- /* Global Control */
- *pu32Val = pThis->glob_cnt;
- LogFlowFunc(("glob_cnt -> %#x\n", *pu32Val));
- break;
- case GLOB_STA:
- /* Global Status */
- *pu32Val = pThis->glob_sta | GS_S0CR;
- LogFlowFunc(("glob_sta -> %#x\n", *pu32Val));
- break;
- default:
- *pu32Val = UINT32_MAX;
- LogFlowFunc(("U nabm readl %#x -> %#x\n", Port, *pu32Val));
- break;
- }
- break;
- }
-
- default:
- return VERR_IOM_IOPORT_UNUSED;
- }
- return VINF_SUCCESS;
-}
-
-/**
- * @callback_method_impl{FNIOMIOPORTOUT}
- */
-static DECLCALLBACK(int) ichac97IOPortNABMWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port,
- uint32_t u32Val, unsigned cbVal)
-{
- RT_NOREF(pDevIns);
- PAC97STATE pThis = (PAC97STATE)pvUser;
-
- /* Get the index of the NABMBAR register. */
- const uint32_t uPortIdx = Port - pThis->IOPortBase[1];
-
- PAC97STREAM pStrmSt = ichac97GetStreamFromID(pThis, AC97_PORT2IDX(uPortIdx));
- PAC97BMREGS pRegs = pStrmSt ? &pStrmSt->Regs : NULL;
-
- switch (cbVal)
- {
- case 1:
- {
- switch (uPortIdx)
- {
- case PI_LVI:
- case PO_LVI:
- case MC_LVI:
- /* Last Valid Index */
- if ((pRegs->cr & CR_RPBM) && (pRegs->sr & SR_DCH))
- {
- pRegs->sr &= ~(SR_DCH | SR_CELV);
- pRegs->civ = pRegs->piv;
- pRegs->piv = (pRegs->piv + 1) % 32;
-
- ichac97StreamFetchBDLE(pThis, pStrmSt);
- }
- pRegs->lvi = u32Val % 32;
- LogFlowFunc(("LVI[%d] <- %#x\n", AC97_PORT2IDX(uPortIdx), u32Val));
- break;
- case PI_CR:
- case PO_CR:
- case MC_CR:
- {
- /* Control Register */
- if (u32Val & CR_RR) /* Busmaster reset */
- {
- ichac97StreamResetBMRegs(pThis, pStrmSt);
- }
- else
- {
- pRegs->cr = u32Val & CR_VALID_MASK;
- if (!(pRegs->cr & CR_RPBM))
- {
- ichac97StreamSetActive(pThis, pStrmSt, false /* fActive */);
- pRegs->sr |= SR_DCH;
- }
- else
- {
- pRegs->civ = pRegs->piv;
- pRegs->piv = (pRegs->piv + 1) % 32;
-
- ichac97StreamFetchBDLE(pThis, pStrmSt);
-
- pRegs->sr &= ~SR_DCH;
- ichac97StreamSetActive(pThis, pStrmSt, true /* fActive */);
- }
- }
- LogFlowFunc(("CR[%d] <- %#x (cr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->cr));
- break;
- }
- case PI_SR:
- case PO_SR:
- case MC_SR:
- /* Status Register */
- pRegs->sr |= u32Val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
- ichac97StreamUpdateStatus(pThis, pStrmSt, pRegs->sr & ~(u32Val & SR_WCLEAR_MASK));
- LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->sr));
- break;
- default:
- LogFlowFunc(("U nabm writeb %#x <- %#x\n", Port, u32Val));
- break;
- }
- break;
- }
-
- case 2:
- {
- switch (uPortIdx)
- {
- case PI_SR:
- case PO_SR:
- case MC_SR:
- /* Status Register */
- pRegs->sr |= u32Val & ~(SR_RO_MASK | SR_WCLEAR_MASK);
- ichac97StreamUpdateStatus(pThis, pStrmSt, pRegs->sr & ~(u32Val & SR_WCLEAR_MASK));
- LogFlowFunc(("SR[%d] <- %#x (sr %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->sr));
- break;
- default:
- LogFlowFunc(("U nabm writew %#x <- %#x\n", Port, u32Val));
- break;
- }
- break;
- }
-
- case 4:
- {
- switch (uPortIdx)
- {
- case PI_BDBAR:
- case PO_BDBAR:
- case MC_BDBAR:
- /* Buffer Descriptor list Base Address Register */
- pRegs->bdbar = u32Val & ~3;
- LogFlowFunc(("BDBAR[%d] <- %#x (bdbar %#x)\n", AC97_PORT2IDX(uPortIdx), u32Val, pRegs->bdbar));
- break;
- case GLOB_CNT:
- /* Global Control */
- if (u32Val & GC_WR)
- ichac97WarmReset(pThis);
- if (u32Val & GC_CR)
- ichac97ColdReset(pThis);
- if (!(u32Val & (GC_WR | GC_CR)))
- pThis->glob_cnt = u32Val & GC_VALID_MASK;
- LogFlowFunc(("glob_cnt <- %#x (glob_cnt %#x)\n", u32Val, pThis->glob_cnt));
- break;
- case GLOB_STA:
- /* Global Status */
- pThis->glob_sta &= ~(u32Val & GS_WCLEAR_MASK);
- pThis->glob_sta |= (u32Val & ~(GS_WCLEAR_MASK | GS_RO_MASK)) & GS_VALID_MASK;
- LogFlowFunc(("glob_sta <- %#x (glob_sta %#x)\n", u32Val, pThis->glob_sta));
- break;
- default:
- LogFlowFunc(("U nabm writel %#x <- %#x\n", Port, u32Val));
- break;
- }
- break;
- }
-
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cbVal, u32Val));
- break;
- }
- return VINF_SUCCESS;
-}
-
-/**
- * @callback_method_impl{FNIOMIOPORTIN}
- */
-static DECLCALLBACK(int) ichac97IOPortNAMRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32Val, unsigned cbVal)
-{
- RT_NOREF(pDevIns);
- PAC97STATE pThis = (PAC97STATE)pvUser;
-
- switch (cbVal)
- {
- case 1:
- {
- LogFlowFunc(("U nam readb %#x\n", Port));
- pThis->cas = 0;
- *pu32Val = UINT32_MAX;
- break;
- }
-
- case 2:
- {
- uint32_t index = Port - pThis->IOPortBase[0];
- *pu32Val = UINT32_MAX;
- pThis->cas = 0;
- switch (index)
- {
- default:
- *pu32Val = ichac97MixerGet(pThis, index);
- LogFlowFunc(("nam readw %#x -> %#x\n", Port, *pu32Val));
- break;
- }
- break;
- }
-
- case 4:
- {
- LogFlowFunc(("U nam readl %#x\n", Port));
- pThis->cas = 0;
- *pu32Val = UINT32_MAX;
- break;
- }
-
- default:
- return VERR_IOM_IOPORT_UNUSED;
- }
- return VINF_SUCCESS;
-}
-
-/**
- * @callback_method_impl{FNIOMIOPORTOUT}
- */
-static DECLCALLBACK(int) ichac97IOPortNAMWrite(PPDMDEVINS pDevIns,
- void *pvUser, RTIOPORT Port, uint32_t u32Val, unsigned cbVal)
-{
- RT_NOREF(pDevIns);
- PAC97STATE pThis = (PAC97STATE)pvUser;
-
- switch (cbVal)
- {
- case 1:
- {
- LogFlowFunc(("U nam writeb %#x <- %#x\n", Port, u32Val));
- pThis->cas = 0;
- break;
- }
-
- case 2:
- {
- uint32_t index = Port - pThis->IOPortBase[0];
- pThis->cas = 0;
- switch (index)
- {
- case AC97_Reset:
- ichac97Reset(pThis->CTX_SUFF(pDevIns));
- break;
- case AC97_Powerdown_Ctrl_Stat:
- u32Val &= ~0xf;
- u32Val |= ichac97MixerGet(pThis, index) & 0xf;
- ichac97MixerSet(pThis, index, u32Val);
- break;
- case AC97_Master_Volume_Mute:
- if (pThis->uCodecModel == Codec_AD1980)
- if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_LOSEL)
- break; /* Register controls surround (rear), do nothing. */
- ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
- break;
- case AC97_Headphone_Volume_Mute:
- if (pThis->uCodecModel == Codec_AD1980)
- if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_HPSEL)
- /* Register controls PCM (front) outputs. */
- ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_VOLUME, u32Val);
- break;
- case AC97_PCM_Out_Volume_Mute:
- ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_PCM, u32Val);
- break;
- case AC97_Line_In_Volume_Mute:
- ichac97MixerSetVolume(pThis, index, PDMAUDIOMIXERCTL_LINE_IN, u32Val);
- break;
- case AC97_Record_Select:
- ichac97RecordSelect(pThis, u32Val);
- break;
- case AC97_Vendor_ID1:
- case AC97_Vendor_ID2:
- LogFlowFunc(("Attempt to write vendor ID to %#x\n", u32Val));
- break;
- case AC97_Extended_Audio_ID:
- LogFlowFunc(("Attempt to write extended audio ID to %#x\n", u32Val));
- break;
- case AC97_Extended_Audio_Ctrl_Stat:
- if (!(u32Val & EACS_VRA))
- {
- ichac97MixerSet(pThis, AC97_PCM_Front_DAC_Rate, 48000);
- ichac97StreamReInit(pThis, &pThis->StrmStOut);
-
- ichac97MixerSet(pThis, AC97_PCM_LR_ADC_Rate, 48000);
- ichac97StreamReInit(pThis, &pThis->StrmStLineIn);
- }
- if (!(u32Val & EACS_VRM))
- {
- ichac97MixerSet(pThis, AC97_MIC_ADC_Rate, 48000);
- ichac97StreamReInit(pThis, &pThis->StrmStMicIn);
- }
- LogFlowFunc(("Setting extended audio control to %#x\n", u32Val));
- ichac97MixerSet(pThis, AC97_Extended_Audio_Ctrl_Stat, u32Val);
- break;
- case AC97_PCM_Front_DAC_Rate:
- if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
- {
- ichac97MixerSet(pThis, index, u32Val);
- LogFlowFunc(("Set front DAC rate to %RU32\n", u32Val));
- ichac97StreamReInit(pThis, &pThis->StrmStOut);
- }
- else
- LogFlowFunc(("Attempt to set front DAC rate to %RU32, but VRA is not set\n", u32Val));
- break;
- case AC97_MIC_ADC_Rate:
- if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRM)
- {
- ichac97MixerSet(pThis, index, u32Val);
- LogFlowFunc(("Set MIC ADC rate to %RU32\n", u32Val));
- ichac97StreamReInit(pThis, &pThis->StrmStMicIn);
- }
- else
- LogFlowFunc(("Attempt to set MIC ADC rate to %RU32, but VRM is not set\n", u32Val));
- break;
- case AC97_PCM_LR_ADC_Rate:
- if (ichac97MixerGet(pThis, AC97_Extended_Audio_Ctrl_Stat) & EACS_VRA)
- {
- ichac97MixerSet(pThis, index, u32Val);
- LogFlowFunc(("Set front LR ADC rate to %RU32\n", u32Val));
- ichac97StreamReInit(pThis, &pThis->StrmStLineIn);
- }
- else
- LogFlowFunc(("Attempt to set LR ADC rate to %RU32, but VRA is not set\n", u32Val));
- break;
- default:
- LogFlowFunc(("U nam writew %#x <- %#x\n", Port, u32Val));
- ichac97MixerSet(pThis, index, u32Val);
- break;
- }
- break;
- }
-
- case 4:
- {
- LogFlowFunc(("U nam writel %#x <- %#x\n", Port, u32Val));
- pThis->cas = 0;
- break;
- }
-
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", Port, cbVal, u32Val));
- break;
- }
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * @callback_method_impl{FNPCIIOREGIONMAP}
- */
-static DECLCALLBACK(int) ichac97IOPortMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
- RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
-{
- RT_NOREF(enmType, cb);
- PAC97STATE pThis = RT_FROM_MEMBER(pPciDev, AC97STATE, PciDev);
- RTIOPORT Port = (RTIOPORT)GCPhysAddress;
-
- Assert(enmType == PCI_ADDRESS_SPACE_IO);
- Assert(cb >= 0x20);
-
- if (iRegion > 1) /* We support 2 regions max. at the moment. */
- return VERR_INVALID_PARAMETER;
-
- int rc;
- if (iRegion == 0)
- rc = PDMDevHlpIOPortRegister(pDevIns, Port, 256, pThis,
- ichac97IOPortNAMWrite, ichac97IOPortNAMRead,
- NULL, NULL, "ICHAC97 NAM");
- else
- rc = PDMDevHlpIOPortRegister(pDevIns, Port, 64, pThis,
- ichac97IOPortNABMWrite, ichac97IOPortNABMRead,
- NULL, NULL, "ICHAC97 NABM");
- if (RT_FAILURE(rc))
- return rc;
-
- pThis->IOPortBase[iRegion] = Port;
- return VINF_SUCCESS;
-}
-
-DECLINLINE(PAC97STREAM) ichac97GetStreamFromID(PAC97STATE pThis, uint32_t uID)
-{
- switch (uID)
- {
- case PI_INDEX: return &pThis->StrmStLineIn;
- case MC_INDEX: return &pThis->StrmStMicIn;
- case PO_INDEX: return &pThis->StrmStOut;
- default: break;
- }
-
- return NULL;
-}
-
-#ifdef IN_RING3
-static int ichac97SaveStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStrmSt)
-{
- RT_NOREF(pDevIns);
- PAC97BMREGS pRegs = &pStrmSt->Regs;
-
- SSMR3PutU32(pSSM, pRegs->bdbar);
- SSMR3PutU8( pSSM, pRegs->civ);
- SSMR3PutU8( pSSM, pRegs->lvi);
- SSMR3PutU16(pSSM, pRegs->sr);
- SSMR3PutU16(pSSM, pRegs->picb);
- SSMR3PutU8( pSSM, pRegs->piv);
- SSMR3PutU8( pSSM, pRegs->cr);
- SSMR3PutS32(pSSM, pRegs->bd_valid);
- SSMR3PutU32(pSSM, pRegs->bd.addr);
- SSMR3PutU32(pSSM, pRegs->bd.ctl_len);
-
- return VINF_SUCCESS;
-}
-
-/**
- * @callback_method_impl{FNSSMDEVSAVEEXEC}
- */
-static DECLCALLBACK(int) ichac97SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
-{
- PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
-
- SSMR3PutU32(pSSM, pThis->glob_cnt);
- SSMR3PutU32(pSSM, pThis->glob_sta);
- SSMR3PutU32(pSSM, pThis->cas);
-
- /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
- /* Note: The order the streams are saved here is critical, so don't touch. */
- int rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStLineIn);
- AssertRC(rc2);
- rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStOut);
- AssertRC(rc2);
- rc2 = ichac97SaveStream(pDevIns, pSSM, &pThis->StrmStMicIn);
- AssertRC(rc2);
-
- SSMR3PutMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
-
- uint8_t active[LAST_INDEX];
-
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
- AssertPtr(pCon);
- active[PI_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->LineIn.pStrmIn) ? 1 : 0;
- active[PO_INDEX] = pCon->pfnIsActiveOut(pCon, pDrv->Out.pStrmOut) ? 1 : 0;
- active[MC_INDEX] = pCon->pfnIsActiveIn (pCon, pDrv->MicIn.pStrmIn) ? 1 : 0;
- }
-
- SSMR3PutMem(pSSM, active, sizeof(active));
-
- return VINF_SUCCESS;
-}
-
-static int ichac97LoadStream(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, PAC97STREAM pStrmSt)
-{
- RT_NOREF(pDevIns);
- PAC97BMREGS pRegs = &pStrmSt->Regs;
-
- SSMR3GetU32(pSSM, &pRegs->bdbar);
- SSMR3GetU8( pSSM, &pRegs->civ);
- SSMR3GetU8( pSSM, &pRegs->lvi);
- SSMR3GetU16(pSSM, &pRegs->sr);
- SSMR3GetU16(pSSM, &pRegs->picb);
- SSMR3GetU8( pSSM, &pRegs->piv);
- SSMR3GetU8( pSSM, &pRegs->cr);
- SSMR3GetS32(pSSM, &pRegs->bd_valid);
- SSMR3GetU32(pSSM, &pRegs->bd.addr);
- SSMR3GetU32(pSSM, &pRegs->bd.ctl_len);
-
- return VINF_SUCCESS;
-}
-
-/**
- * @callback_method_impl{FNSSMDEVLOADEXEC}
- */
-static DECLCALLBACK(int) ichac97LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
-{
- PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
-
- AssertMsgReturn (uVersion == AC97_SSM_VERSION, ("%RU32\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
- Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
-
- SSMR3GetU32(pSSM, &pThis->glob_cnt);
- SSMR3GetU32(pSSM, &pThis->glob_sta);
- SSMR3GetU32(pSSM, &pThis->cas);
-
- /** @todo r=andy For the next saved state version, add unique stream identifiers and a stream count. */
- /* Note: The order the streams are loaded here is critical, so don't touch. */
- int rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStLineIn);
- AssertRC(rc2);
- rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStOut);
- AssertRC(rc2);
- rc2 = ichac97LoadStream(pDevIns, pSSM, &pThis->StrmStMicIn);
- AssertRC(rc2);
-
- SSMR3GetMem(pSSM, pThis->mixer_data, sizeof(pThis->mixer_data));
-
- /** @todo r=andy Stream IDs are hardcoded to certain streams. */
- uint8_t uaStrmsActive[LAST_INDEX];
- SSMR3GetMem(pSSM, uaStrmsActive, sizeof(uaStrmsActive));
-
- ichac97RecordSelect(pThis, ichac97MixerGet(pThis, AC97_Record_Select));
-# define V_(a, b) ichac97MixerSetVolume(pThis, a, b, ichac97MixerGet(pThis, a))
- V_(AC97_Master_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME);
- V_(AC97_PCM_Out_Volume_Mute, PDMAUDIOMIXERCTL_PCM);
- V_(AC97_Line_In_Volume_Mute, PDMAUDIOMIXERCTL_LINE_IN);
-# undef V_
- if (pThis->uCodecModel == Codec_AD1980)
- if (ichac97MixerGet(pThis, AC97_AD_Misc) & AD_MISC_HPSEL)
- ichac97MixerSetVolume(pThis, AC97_Headphone_Volume_Mute, PDMAUDIOMIXERCTL_VOLUME,
- ichac97MixerGet(pThis, AC97_Headphone_Volume_Mute));
-
- int rc;
- rc = ichac97StreamInit(pThis, &pThis->StrmStLineIn, PI_INDEX);
- AssertRC(rc);
- rc = ichac97StreamInit(pThis, &pThis->StrmStMicIn, MC_INDEX);
- AssertRC(rc);
- rc = ichac97StreamInit(pThis, &pThis->StrmStOut, PO_INDEX);
- AssertRC(rc);
-
- /** @todo r=andy Stream IDs are hardcoded to certain streams. */
- rc = ichac97StreamSetActive(pThis, &pThis->StrmStLineIn, RT_BOOL(uaStrmsActive[PI_INDEX]));
- AssertRC(rc);
- rc = ichac97StreamSetActive(pThis, &pThis->StrmStMicIn, RT_BOOL(uaStrmsActive[MC_INDEX]));
- AssertRC(rc);
- rc = ichac97StreamSetActive(pThis, &pThis->StrmStOut, RT_BOOL(uaStrmsActive[PO_INDEX]));
- AssertRC(rc);
-
- pThis->bup_flag = 0;
- pThis->last_samp = 0;
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) ichac97QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
-{
- PAC97STATE pThis = RT_FROM_MEMBER(pInterface, AC97STATE, IBase);
- Assert(&pThis->IBase == pInterface);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
- return NULL;
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnReset}
- *
- * @remarks The original sources didn't install a reset handler, but it seems to
- * make sense to me so we'll do it.
- */
-static DECLCALLBACK(void) ichac97Reset(PPDMDEVINS pDevIns)
-{
- PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
-
- LogFlowFuncEnter();
-
- /*
- * Reset the device state (will need pDrv later).
- */
- ichac97StreamResetBMRegs(pThis, &pThis->StrmStLineIn);
- ichac97StreamResetBMRegs(pThis, &pThis->StrmStMicIn);
- ichac97StreamResetBMRegs(pThis, &pThis->StrmStOut);
-
- /*
- * Reset the mixer too. The Windows XP driver seems to rely on
- * this. At least it wants to read the vendor id before it resets
- * the codec manually.
- */
- ichac97MixerReset(pThis);
-
- /*
- * Stop any audio currently playing.
- */
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->LineIn.pStrmIn, false /* Disable */);
- /* Ignore rc. */
- pDrv->pConnector->pfnEnableIn(pDrv->pConnector, pDrv->MicIn.pStrmIn, false /* Disable */);
- /* Ditto. */
- pDrv->pConnector->pfnEnableOut(pDrv->pConnector, pDrv->Out.pStrmOut, false /* Disable */);
- /* Ditto. */
- }
-
- /*
- * Reset all streams.
- */
- ichac97StreamReset(pThis, &pThis->StrmStLineIn);
- ichac97StreamReset(pThis, &pThis->StrmStMicIn);
- ichac97StreamReset(pThis, &pThis->StrmStOut);
-
- LogRel(("AC97: Reset\n"));
-}
-
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnDestruct}
- */
-static DECLCALLBACK(int) ichac97Destruct(PPDMDEVINS pDevIns)
-{
- PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
- PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
-
- LogFlowFuncEnter();
-
- PAC97DRIVER pDrv;
- while (!RTListIsEmpty(&pThis->lstDrv))
- {
- pDrv = RTListGetFirst(&pThis->lstDrv, AC97DRIVER, Node);
-
- RTListNodeRemove(&pDrv->Node);
- RTMemFree(pDrv);
- }
-
- if (pThis->pMixer)
- {
- AudioMixerDestroy(pThis->pMixer);
- pThis->pMixer = NULL;
- }
-
- if (pThis->pvReadWriteBuf)
- {
- RTMemFree(pThis->pvReadWriteBuf);
- pThis->pvReadWriteBuf = NULL;
- pThis->cbReadWriteBuf = 0;
- }
-
- LogFlowFuncLeave();
- return VINF_SUCCESS;
-}
-
-
-/**
- * Attach command, internal version.
- *
- * This is called to let the device attach to a driver for a specified LUN
- * during runtime. This is not called during VM construction, the device
- * constructor has to attach to all the available drivers.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param pDrv Driver to (re-)use for (re-)attaching to.
- * If NULL is specified, a new driver will be created and appended
- * to the driver list.
- * @param uLUN The logical unit which is being detached.
- * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
- */
-static DECLCALLBACK(int) ichac97AttachInternal(PPDMDEVINS pDevIns, PAC97DRIVER pDrv, unsigned uLUN, uint32_t fFlags)
-{
- RT_NOREF(fFlags);
- PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
-
- /*
- * Attach driver.
- */
- char *pszDesc = NULL;
- if (RTStrAPrintf(&pszDesc, "Audio driver port (AC'97) for LUN #%u", uLUN) <= 0)
- AssertReleaseMsgReturn(pszDesc,
- ("Not enough memory for AC'97 driver port description of LUN #%u\n", uLUN),
- VERR_NO_MEMORY);
-
- PPDMIBASE pDrvBase;
- int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
- &pThis->IBase, &pDrvBase, pszDesc);
- if (RT_SUCCESS(rc))
- {
- if (pDrv == NULL)
- pDrv = (PAC97DRIVER)RTMemAllocZ(sizeof(AC97DRIVER));
- if (pDrv)
- {
- pDrv->pDrvBase = pDrvBase;
- pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
- AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
- pDrv->pAC97State = pThis;
- pDrv->uLUN = uLUN;
-
- /*
- * For now we always set the driver at LUN 0 as our primary
- * host backend. This might change in the future.
- */
- if (pDrv->uLUN == 0)
- pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
-
- LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
-
- /* Attach to driver list if not attached yet. */
- if (!pDrv->fAttached)
- {
- RTListAppend(&pThis->lstDrv, &pDrv->Node);
- pDrv->fAttached = true;
- }
- }
- else
- rc = VERR_NO_MEMORY;
- }
- else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- LogFunc(("No attached driver for LUN #%u\n", uLUN));
-
- if (RT_FAILURE(rc))
- {
- /* Only free this string on failure;
- * must remain valid for the live of the driver instance. */
- RTStrFree(pszDesc);
- }
-
- LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
- return rc;
-}
-
-
-/**
- * Attach command.
- *
- * This is called to let the device attach to a driver for a specified LUN
- * during runtime. This is not called during VM construction, the device
- * constructor has to attach to all the available drivers.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param uLUN The logical unit which is being detached.
- * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
- */
-static DECLCALLBACK(int) ichac97Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
-{
- return ichac97AttachInternal(pDevIns, NULL /* pDrv */, uLUN, fFlags);
-}
-
-static DECLCALLBACK(void) ichac97Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
-{
- RT_NOREF(pDevIns, uLUN, fFlags);
- LogFunc(("iLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
-}
-
-/**
- * Re-attach.
- *
- * @returns VBox status code.
- * @param pThis Device instance.
- * @param pDrv Driver instance used for attaching to.
- * If NULL is specified, a new driver will be created and appended
- * to the driver list.
- * @param uLUN The logical unit which is being re-detached.
- * @param pszDriver Driver name.
- */
-static int ichac97Reattach(PAC97STATE pThis, PAC97DRIVER pDrv, uint8_t uLUN, const char *pszDriver)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszDriver, VERR_INVALID_POINTER);
-
- PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
- PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
- PCFGMNODE pDev0 = CFGMR3GetChild(pRoot, "Devices/ichac97/0/");
-
- /* Remove LUN branch. */
- CFGMR3RemoveNode(CFGMR3GetChildF(pDev0, "LUN#%u/", uLUN));
-
- if (pDrv)
- {
- /* Re-use a driver instance => detach the driver before. */
- int rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
- if (RT_FAILURE(rc))
- return rc;
- }
-
-#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
-
- int rc = VINF_SUCCESS;
- do
- {
- PCFGMNODE pLunL0;
- rc = CFGMR3InsertNodeF(pDev0, &pLunL0, "LUN#%u/", uLUN); RC_CHECK();
- rc = CFGMR3InsertString(pLunL0, "Driver", "AUDIO"); RC_CHECK();
- rc = CFGMR3InsertNode(pLunL0, "Config/", NULL); RC_CHECK();
-
- PCFGMNODE pLunL1, pLunL2;
- rc = CFGMR3InsertNode (pLunL0, "AttachedDriver/", &pLunL1); RC_CHECK();
- rc = CFGMR3InsertNode (pLunL1, "Config/", &pLunL2); RC_CHECK();
- rc = CFGMR3InsertString(pLunL1, "Driver", pszDriver); RC_CHECK();
-
- rc = CFGMR3InsertString(pLunL2, "AudioDriver", pszDriver); RC_CHECK();
-
- } while (0);
-
- if (RT_SUCCESS(rc))
- rc = ichac97AttachInternal(pThis->pDevInsR3, pDrv, uLUN, 0 /* fFlags */);
-
- LogFunc(("pThis=%p, uLUN=%u, pszDriver=%s, rc=%Rrc\n", pThis, uLUN, pszDriver, rc));
-
-#undef RC_CHECK
-
- return rc;
-}
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnConstruct}
- */
-static DECLCALLBACK(int) ichac97Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
-{
- RT_NOREF(iInstance);
- PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
-
- PAC97STATE pThis = PDMINS_2_DATA(pDevIns, PAC97STATE);
-
- /* NB: This must be done *before* any possible failure (and running the destructor). */
- RTListInit(&pThis->lstDrv);
-
- Assert(iInstance == 0);
-
- /*
- * Validations.
- */
- if (!CFGMR3AreValuesValid(pCfg,
- "Codec\0"
- "TimerHz\0"))
- return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
- N_("Invalid configuration for the AC'97 device"));
-
- /*
- * Read config data.
- */
- char szCodec[20];
- int rc = CFGMR3QueryStringDef(pCfg, "Codec", &szCodec[0], sizeof(szCodec), "STAC9700");
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
- N_("AC'97 configuration error: Querying \"Codec\" as string failed"));
-
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- uint16_t uTimerHz;
- rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("AC'97 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
-#endif
-
- /*
- * The AD1980 codec (with corresponding PCI subsystem vendor ID) is whitelisted
- * in the Linux kernel; Linux makes no attempt to measure the data rate and assumes
- * 48 kHz rate, which is exactly what we need. Same goes for AD1981B.
- */
- if (!strcmp(szCodec, "STAC9700"))
- pThis->uCodecModel = Codec_STAC9700;
- else if (!strcmp(szCodec, "AD1980"))
- pThis->uCodecModel = Codec_AD1980;
- else if (!strcmp(szCodec, "AD1981B"))
- pThis->uCodecModel = Codec_AD1981B;
- else
- {
- return PDMDevHlpVMSetError(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, RT_SRC_POS,
- N_("AC'97 configuration error: The \"Codec\" value \"%s\" is unsupported"),
- szCodec);
- }
-
- /*
- * Initialize data (most of it anyway).
- */
- pThis->pDevInsR3 = pDevIns;
- /* IBase */
- pThis->IBase.pfnQueryInterface = ichac97QueryInterface;
-
- /* PCI Device (the assertions will be removed later) */
- PCIDevSetVendorId (&pThis->PciDev, 0x8086); /* 00 ro - intel. */ Assert(pThis->PciDev.abConfig[0x00] == 0x86); Assert(pThis->PciDev.abConfig[0x01] == 0x80);
- PCIDevSetDeviceId (&pThis->PciDev, 0x2415); /* 02 ro - 82801 / 82801aa(?). */ Assert(pThis->PciDev.abConfig[0x02] == 0x15); Assert(pThis->PciDev.abConfig[0x03] == 0x24);
- PCIDevSetCommand (&pThis->PciDev, 0x0000); /* 04 rw,ro - pcicmd. */ Assert(pThis->PciDev.abConfig[0x04] == 0x00); Assert(pThis->PciDev.abConfig[0x05] == 0x00);
- PCIDevSetStatus (&pThis->PciDev, VBOX_PCI_STATUS_DEVSEL_MEDIUM | VBOX_PCI_STATUS_FAST_BACK); /* 06 rwc?,ro? - pcists. */ Assert(pThis->PciDev.abConfig[0x06] == 0x80); Assert(pThis->PciDev.abConfig[0x07] == 0x02);
- PCIDevSetRevisionId (&pThis->PciDev, 0x01); /* 08 ro - rid. */ Assert(pThis->PciDev.abConfig[0x08] == 0x01);
- PCIDevSetClassProg (&pThis->PciDev, 0x00); /* 09 ro - pi. */ Assert(pThis->PciDev.abConfig[0x09] == 0x00);
- PCIDevSetClassSub (&pThis->PciDev, 0x01); /* 0a ro - scc; 01 == Audio. */ Assert(pThis->PciDev.abConfig[0x0a] == 0x01);
- PCIDevSetClassBase (&pThis->PciDev, 0x04); /* 0b ro - bcc; 04 == multimedia. */ Assert(pThis->PciDev.abConfig[0x0b] == 0x04);
- PCIDevSetHeaderType (&pThis->PciDev, 0x00); /* 0e ro - headtyp. */ Assert(pThis->PciDev.abConfig[0x0e] == 0x00);
- PCIDevSetBaseAddress (&pThis->PciDev, 0, /* 10 rw - nambar - native audio mixer base. */
- true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.abConfig[0x10] == 0x01); Assert(pThis->PciDev.abConfig[0x11] == 0x00); Assert(pThis->PciDev.abConfig[0x12] == 0x00); Assert(pThis->PciDev.abConfig[0x13] == 0x00);
- PCIDevSetBaseAddress (&pThis->PciDev, 1, /* 14 rw - nabmbar - native audio bus mastering. */
- true /* fIoSpace */, false /* fPrefetchable */, false /* f64Bit */, 0x00000000); Assert(pThis->PciDev.abConfig[0x14] == 0x01); Assert(pThis->PciDev.abConfig[0x15] == 0x00); Assert(pThis->PciDev.abConfig[0x16] == 0x00); Assert(pThis->PciDev.abConfig[0x17] == 0x00);
- PCIDevSetInterruptLine (&pThis->PciDev, 0x00); /* 3c rw. */ Assert(pThis->PciDev.abConfig[0x3c] == 0x00);
- PCIDevSetInterruptPin (&pThis->PciDev, 0x01); /* 3d ro - INTA#. */ Assert(pThis->PciDev.abConfig[0x3d] == 0x01);
-
- if (pThis->uCodecModel == Codec_AD1980)
- {
- PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
- PCIDevSetSubSystemId (&pThis->PciDev, 0x0177); /* 2e ro. */
- }
- else if (pThis->uCodecModel == Codec_AD1981B)
- {
- PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x1028); /* 2c ro - Dell.) */
- PCIDevSetSubSystemId (&pThis->PciDev, 0x01ad); /* 2e ro. */
- }
- else
- {
- PCIDevSetSubSystemVendorId(&pThis->PciDev, 0x8086); /* 2c ro - Intel.) */
- PCIDevSetSubSystemId (&pThis->PciDev, 0x0000); /* 2e ro. */
- }
-
- /*
- * Register the PCI device, it's I/O regions, the timer and the
- * saved state item.
- */
- rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
- if (RT_FAILURE(rc))
- return rc;
-
- rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 256, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap);
- if (RT_FAILURE(rc))
- return rc;
-
- rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 64, PCI_ADDRESS_SPACE_IO, ichac97IOPortMap);
- if (RT_FAILURE(rc))
- return rc;
-
- rc = PDMDevHlpSSMRegister(pDevIns, AC97_SSM_VERSION, sizeof(*pThis), ichac97SaveExec, ichac97LoadExec);
- if (RT_FAILURE(rc))
- return rc;
-
- /*
- * Attach driver.
- */
- uint8_t uLUN;
- for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
- {
- LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
- rc = ichac97AttachInternal(pDevIns, NULL /* pDrv */, uLUN, 0 /* fFlags */);
- if (RT_FAILURE(rc))
- {
- if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- rc = VINF_SUCCESS;
- else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
- {
- ichac97Reattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
- N_("No audio devices could be opened. Selecting the NULL audio backend "
- "with the consequence that no sound is audible"));
- /* attaching to the NULL audio backend will never fail */
- rc = VINF_SUCCESS;
- }
- break;
- }
- }
-
- LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
-
- if (RT_SUCCESS(rc))
- {
- rc = AudioMixerCreate("AC'97 Mixer", 0 /* uFlags */, &pThis->pMixer);
- if (RT_SUCCESS(rc))
- {
- /* Set a default audio format for our mixer. */
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = 44100;
- streamCfg.cChannels = 2;
- streamCfg.enmFormat = AUD_FMT_S16;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- rc = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
- AssertRC(rc);
-
- /* Add all required audio sinks. */
- rc = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output", AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
- AssertRC(rc);
-
- rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Line In", AUDMIXSINKDIR_INPUT, &pThis->pSinkLineIn);
- AssertRC(rc);
-
- rc = AudioMixerAddSink(pThis->pMixer, "[Recording] Microphone In", AUDMIXSINKDIR_INPUT, &pThis->pSinkMicIn);
- AssertRC(rc);
- }
- }
-
- ichac97Reset(pDevIns);
-
- if (RT_SUCCESS(rc))
- {
- rc = ichac97StreamInit(pThis, &pThis->StrmStLineIn, PI_INDEX);
- if (RT_FAILURE(rc))
- return rc;
- rc = ichac97StreamInit(pThis, &pThis->StrmStMicIn, MC_INDEX);
- if (RT_FAILURE(rc))
- return rc;
- rc = ichac97StreamInit(pThis, &pThis->StrmStOut, PO_INDEX);
- if (RT_FAILURE(rc))
- return rc;
-
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- /*
- * Only primary drivers are critical for the VM to run. Everything else
- * might not worth showing an own error message box in the GUI.
- */
- if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
- continue;
-
- PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
- AssertPtr(pCon);
-
- bool fValidLineIn = pCon->pfnIsValidIn(pCon, pDrv->LineIn.pStrmIn);
- bool fValidMicIn = pCon->pfnIsValidIn (pCon, pDrv->MicIn.pStrmIn);
- bool fValidOut = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
-
- if ( !fValidLineIn
- && !fValidMicIn
- && !fValidOut)
- {
- LogRel(("AC97: Falling back to NULL backend (no sound audible)\n"));
-
- ichac97Reset(pDevIns);
- ichac97Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
-
- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
- N_("No audio devices could be opened. Selecting the NULL audio backend "
- "with the consequence that no sound is audible"));
- }
- else
- {
- bool fWarn = false;
-
- PDMAUDIOBACKENDCFG backendCfg;
- int rc2 = pCon->pfnGetConfiguration(pCon, &backendCfg);
- if (RT_SUCCESS(rc2))
- {
- if (backendCfg.cMaxHstStrmsIn)
- {
- /* If the audio backend supports two or more input streams at once,
- * warn if one of our two inputs (microphone-in and line-in) failed to initialize. */
- if (backendCfg.cMaxHstStrmsIn >= 2)
- fWarn = !fValidLineIn || !fValidMicIn;
- /* If the audio backend only supports one input stream at once (e.g. pure ALSA, and
- * *not* ALSA via PulseAudio plugin!), only warn if both of our inputs failed to initialize.
- * One of the two simply is not in use then. */
- else if (backendCfg.cMaxHstStrmsIn == 1)
- fWarn = !fValidLineIn && !fValidMicIn;
- /* Don't warn if our backend is not able of supporting any input streams at all. */
- }
-
- if ( !fWarn
- && backendCfg.cMaxHstStrmsOut)
- {
- fWarn = !fValidOut;
- }
- }
- else
- AssertReleaseMsgFailed(("Unable to retrieve audio backend configuration for LUN #%RU8, rc=%Rrc\n",
- pDrv->uLUN, rc2));
-
- if (fWarn)
- {
- char szMissingStreams[255];
- size_t len = 0;
- if (!fValidLineIn)
- {
- LogRel(("AC97: WARNING: Unable to open PCM line input for LUN #%RU8!\n", pDrv->uLUN));
- len = RTStrPrintf(szMissingStreams, sizeof(szMissingStreams), "PCM Input");
- }
- if (!fValidMicIn)
- {
- LogRel(("AC97: WARNING: Unable to open PCM microphone input for LUN #%RU8!\n", pDrv->uLUN));
- len += RTStrPrintf(szMissingStreams + len,
- sizeof(szMissingStreams) - len, len ? ", PCM Microphone" : "PCM Microphone");
- }
- if (!fValidOut)
- {
- LogRel(("AC97: WARNING: Unable to open PCM output for LUN #%RU8!\n", pDrv->uLUN));
- len += RTStrPrintf(szMissingStreams + len,
- sizeof(szMissingStreams) - len, len ? ", PCM Output" : "PCM Output");
- }
-
- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
- N_("Some AC'97 audio streams (%s) could not be opened. Guest applications generating audio "
- "output or depending on audio input may hang. Make sure your host audio device "
- "is working properly. Check the logfile for error messages of the audio "
- "subsystem"), szMissingStreams);
- }
- }
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- pThis->cbReadWriteBuf = _4K; /** @todo Make this configurable. */
- pThis->pvReadWriteBuf = (uint8_t *)RTMemAllocZ(pThis->cbReadWriteBuf);
- if (!pThis->pvReadWriteBuf)
- rc = VERR_NO_MEMORY;
- }
-
-# ifndef VBOX_WITH_AUDIO_CALLBACKS
- if (RT_SUCCESS(rc))
- {
- /* Start the emulation timer. */
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, ichac97Timer, pThis,
- TMTIMER_FLAGS_NO_CRIT_SECT, "DevIchAc97", &pThis->pTimer);
- AssertRCReturn(rc, rc);
-
- if (RT_SUCCESS(rc))
- {
- pThis->cTimerTicks = TMTimerGetFreq(pThis->pTimer) / uTimerHz;
- pThis->uTimerTS = TMTimerGet(pThis->pTimer);
- LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicks, uTimerHz));
-
- /* Fire off timer. */
- TMTimerSet(pThis->pTimer, TMTimerGet(pThis->pTimer) + pThis->cTimerTicks);
- }
- }
-# else
- if (RT_SUCCESS(rc))
- {
- PAC97DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, AC97DRIVER, Node)
- {
- /* Only register primary driver.
- * The device emulation does the output multiplexing then. */
- if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
- continue;
-
- PDMAUDIOCALLBACK AudioCallbacks[2];
-
- AC97CALLBACKCTX Ctx = { pThis, pDrv };
-
- AudioCallbacks[0].enmType = PDMAUDIOCALLBACKTYPE_INPUT;
- AudioCallbacks[0].pfnCallback = ac97CallbackInput;
- AudioCallbacks[0].pvCtx = &Ctx;
- AudioCallbacks[0].cbCtx = sizeof(AC97CALLBACKCTX);
-
- AudioCallbacks[1].enmType = PDMAUDIOCALLBACKTYPE_OUTPUT;
- AudioCallbacks[1].pfnCallback = ac97CallbackOutput;
- AudioCallbacks[1].pvCtx = &Ctx;
- AudioCallbacks[1].cbCtx = sizeof(AC97CALLBACKCTX);
-
- rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
- if (RT_FAILURE(rc))
- break;
- }
- }
-# endif
-
-# ifdef VBOX_WITH_STATISTICS
- if (RT_SUCCESS(rc))
- {
- /*
- * Register statistics.
- */
- PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTimer, STAMTYPE_PROFILE, "/Devices/AC97/Timer", STAMUNIT_TICKS_PER_CALL, "Profiling ichac97Timer.");
- PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesRead, STAMTYPE_COUNTER, "/Devices/AC97/BytesRead" , STAMUNIT_BYTES, "Bytes read from AC97 emulation.");
- PDMDevHlpSTAMRegister(pDevIns, &pThis->StatBytesWritten, STAMTYPE_COUNTER, "/Devices/AC97/BytesWritten", STAMUNIT_BYTES, "Bytes written to AC97 emulation.");
- }
-# endif
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * The device registration structure.
- */
-const PDMDEVREG g_DeviceICHAC97 =
-{
- /* u32Version */
- PDM_DEVREG_VERSION,
- /* szName */
- "ichac97",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "ICH AC'97 Audio Controller",
- /* fFlags */
- PDM_DEVREG_FLAGS_DEFAULT_BITS,
- /* fClass */
- PDM_DEVREG_CLASS_AUDIO,
- /* cMaxInstances */
- 1,
- /* cbInstance */
- sizeof(AC97STATE),
- /* pfnConstruct */
- ichac97Construct,
- /* pfnDestruct */
- ichac97Destruct,
- /* pfnRelocate */
- NULL,
- /* pfnMemSetup */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- ichac97Reset,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- ichac97Attach,
- /* pfnDetach */
- ichac97Detach,
- /* pfnQueryInterface. */
- NULL,
- /* pfnInitComplete */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32VersionEnd */
- PDM_DEVREG_VERSION
-};
-
-#endif /* !IN_RING3 */
-#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
diff --git a/src/VBox/Devices/Audio_50/DevSB16.cpp b/src/VBox/Devices/Audio_50/DevSB16.cpp
deleted file mode 100644
index 81d0026..0000000
--- a/src/VBox/Devices/Audio_50/DevSB16.cpp
+++ /dev/null
@@ -1,2451 +0,0 @@
-/* $Id: DevSB16.cpp $ */
-/** @file
- * DevSB16 - VBox SB16 Audio Controller.
- *
- * @todo hiccups on NT4 and Win98.
- */
-
-/*
- * Copyright (C) 2015-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- *
- * This code is based on: sb16.c from QEMU AUDIO subsystem (r3917).
- * QEMU Soundblaster 16 emulation
- *
- * Copyright (c) 2003-2005 Vassili Karpov (malc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#define LOG_GROUP LOG_GROUP_DEV_SB16
-#include <VBox/log.h>
-#include <iprt/assert.h>
-#ifdef IN_RING3
-# include <iprt/mem.h>
-# include <iprt/string.h>
-# include <iprt/uuid.h>
-#endif
-
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
-#include "VBoxDD.h"
-
-#include "AudioMixBuffer.h"
-#include "AudioMixer.h"
-#include "DrvAudio.h"
-
-/** Current saved state version. */
-#define SB16_SAVE_STATE_VERSION 2
-/** The version used in VirtualBox version 3.0 and earlier. This didn't include the config dump. */
-#define SB16_SAVE_STATE_VERSION_VBOX_30 1
-
-#define IO_READ_PROTO(name) \
- DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque, \
- RTIOPORT nport, uint32_t *pu32, unsigned cb)
-
-#define IO_WRITE_PROTO(name) \
- DECLCALLBACK(int) name (PPDMDEVINS pDevIns, void *opaque, \
- RTIOPORT nport, uint32_t val, unsigned cb)
-
-static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
-
-typedef struct SB16OUTPUTSTREAM
-{
- /** PCM output stream. */
- R3PTRTYPE(PPDMAUDIOGSTSTRMOUT) pStrmOut;
- /** Mixer handle for output stream. */
- R3PTRTYPE(PAUDMIXSTREAM) phStrmOut;
-} SB16OUTPUTSTREAM, *PSB16OUTPUTSTREAM;
-
-/**
- * Struct for maintaining a host backend driver.
- */
-typedef struct SB16STATE *PSB16STATE;
-typedef struct SB16DRIVER
-{
- /** Node for storing this driver in our device driver list of SB16STATE. */
- RTLISTNODER3 Node;
- /** Pointer to SB16 controller (state). */
- R3PTRTYPE(PSB16STATE) pSB16State;
- /** Driver flags. */
- PDMAUDIODRVFLAGS Flags;
- uint32_t PaddingFlags;
- /** LUN # to which this driver has been assigned. */
- uint8_t uLUN;
- /** Whether this driver is in an attached state or not. */
- bool fAttached;
- uint8_t Padding[4];
- /** Pointer to attached driver base interface. */
- R3PTRTYPE(PPDMIBASE) pDrvBase;
- /** Audio connector interface to the underlying host backend. */
- R3PTRTYPE(PPDMIAUDIOCONNECTOR) pConnector;
- /** Stream for output. */
- SB16OUTPUTSTREAM Out;
-} SB16DRIVER, *PSB16DRIVER;
-
-typedef struct SB16STATE
-{
-#ifdef VBOX
- /** Pointer to the device instance. */
- PPDMDEVINSR3 pDevInsR3;
- /** Pointer to the connector of the attached audio driver. */
- PPDMIAUDIOCONNECTOR pDrv;
- int irqCfg;
- int dmaCfg;
- int hdmaCfg;
- int portCfg;
- int verCfg;
-#endif
- int irq;
- int dma;
- int hdma;
- int port;
- int ver;
-
- int in_index;
- int out_data_len;
- int fmt_stereo;
- int fmt_signed;
- int fmt_bits;
- PDMAUDIOFMT fmt;
- int dma_auto;
- int block_size;
- int fifo;
- int freq;
- int time_const;
- int speaker;
- int needed_bytes;
- int cmd;
- int use_hdma;
- int highspeed;
- int can_write; /** @todo Value never gets 0? */
-
- int v2x6;
-
- uint8_t csp_param;
- uint8_t csp_value;
- uint8_t csp_mode;
- uint8_t csp_regs[256];
- uint8_t csp_index;
- uint8_t csp_reg83[4];
- int csp_reg83r;
- int csp_reg83w;
-
- uint8_t in2_data[10];
- uint8_t out_data[50];
- uint8_t test_reg;
- uint8_t last_read_byte;
- int nzero;
-
- int left_till_irq; /** Note: Can be < 0. */
-
- int dma_running;
- int bytes_per_second;
- int align;
-
- RTLISTANCHOR lstDrv;
- /** The device' software mixer. */
- R3PTRTYPE(PAUDIOMIXER) pMixer;
- /** Audio sink for PCM output. */
- R3PTRTYPE(PAUDMIXSINK) pSinkOutput;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- /** The timer for pumping data thru the attached LUN drivers. */
- PTMTIMERR3 pTimerIO;
- /** The timer interval for pumping data thru the LUN drivers in timer ticks. */
- uint64_t cTimerTicksIO;
- /** Timestamp of the last timer callback (sb16TimerIO).
- * Used to calculate the time actually elapsed between two timer callbacks. */
- uint64_t uTimerTSIO;
-#endif
- PTMTIMER pTimerIRQ;
- /** The base interface for LUN\#0. */
- PDMIBASE IBase;
-
- /* mixer state */
- int mixer_nreg;
- uint8_t mixer_regs[256];
-} SB16STATE, *PSB16STATE;
-
-static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg);
-
-/**
- * Attach command, internal version.
- *
- * This is called to let the device attach to a driver for a specified LUN
- * during runtime. This is not called during VM construction, the device
- * constructor has to attach to all the available drivers.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param pDrv Driver to (re-)use for (re-)attaching to.
- * If NULL is specified, a new driver will be created and appended
- * to the driver list.
- * @param uLUN The logical unit which is being detached.
- * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
- */
-static DECLCALLBACK(int) sb16AttachInternal(PPDMDEVINS pDevIns, PSB16DRIVER pDrv, unsigned uLUN, uint32_t fFlags)
-{
- RT_NOREF(fFlags);
- PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
-
- /*
- * Attach driver.
- */
- char *pszDesc = NULL;
- if (RTStrAPrintf(&pszDesc, "Audio driver port (SB16) for LUN #%u", uLUN) <= 0)
- AssertReleaseMsgReturn(pszDesc,
- ("Not enough memory for SB16 driver port description of LUN #%u\n", uLUN),
- VERR_NO_MEMORY);
-
- PPDMIBASE pDrvBase;
- int rc = PDMDevHlpDriverAttach(pDevIns, uLUN,
- &pThis->IBase, &pDrvBase, pszDesc);
- if (RT_SUCCESS(rc))
- {
- if (pDrv == NULL)
- pDrv = (PSB16DRIVER)RTMemAllocZ(sizeof(SB16DRIVER));
- if (pDrv)
- {
- pDrv->pDrvBase = pDrvBase;
- pDrv->pConnector = PDMIBASE_QUERY_INTERFACE(pDrvBase, PDMIAUDIOCONNECTOR);
- AssertMsg(pDrv->pConnector != NULL, ("Configuration error: LUN #%u has no host audio interface, rc=%Rrc\n", uLUN, rc));
- pDrv->pSB16State = pThis;
- pDrv->uLUN = uLUN;
-
- /*
- * For now we always set the driver at LUN 0 as our primary
- * host backend. This might change in the future.
- */
- if (pDrv->uLUN == 0)
- pDrv->Flags |= PDMAUDIODRVFLAG_PRIMARY;
-
- LogFunc(("LUN#%RU8: pCon=%p, drvFlags=0x%x\n", uLUN, pDrv->pConnector, pDrv->Flags));
-
- /* Attach to driver list if not attached yet. */
- if (!pDrv->fAttached)
- {
- RTListAppend(&pThis->lstDrv, &pDrv->Node);
- pDrv->fAttached = true;
- }
- }
- else
- rc = VERR_NO_MEMORY;
- }
- else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- {
- LogFunc(("No attached driver for LUN #%u\n", uLUN));
- }
- else if (RT_FAILURE(rc))
- AssertMsgFailed(("Failed to attach SB16 LUN #%u (\"%s\"), rc=%Rrc\n",
- uLUN, pszDesc, rc));
-
- if (RT_FAILURE(rc))
- {
- /* Only free this string on failure;
- * must remain valid for the live of the driver instance. */
- RTStrFree(pszDesc);
- }
-
- LogFunc(("iLUN=%u, fFlags=0x%x, rc=%Rrc\n", uLUN, fFlags, rc));
- return rc;
-}
-
-/**
- * Attach command.
- *
- * This is called to let the device attach to a driver for a specified LUN
- * during runtime. This is not called during VM construction, the device
- * constructor has to attach to all the available drivers.
- *
- * @returns VBox status code.
- * @param pDevIns The device instance.
- * @param uLUN The logical unit which is being detached.
- * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
- */
-static DECLCALLBACK(int) sb16Attach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
-{
- return sb16AttachInternal(pDevIns, NULL /* pDrv */, uLUN, fFlags);
-}
-
-static DECLCALLBACK(void) sb16Detach(PPDMDEVINS pDevIns, unsigned uLUN, uint32_t fFlags)
-{
- RT_NOREF(pDevIns, uLUN, fFlags);
- LogFunc(("iLUN=%u, fFlags=0x%x\n", uLUN, fFlags));
-}
-
-/**
- * Re-attach.
- *
- * @returns VBox status code.
- * @param pThis Device instance.
- * @param pDrv Driver instance used for attaching to.
- * If NULL is specified, a new driver will be created and appended
- * to the driver list.
- * @param uLUN The logical unit which is being re-detached.
- * @param pszDriver Driver name.
- */
-static int sb16Reattach(PSB16STATE pThis, PSB16DRIVER pDrv, uint8_t uLUN, const char *pszDriver)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszDriver, VERR_INVALID_POINTER);
-
- PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
- PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
- PCFGMNODE pDev0 = CFGMR3GetChild(pRoot, "Devices/sb16/0/");
-
- /* Remove LUN branch. */
- CFGMR3RemoveNode(CFGMR3GetChildF(pDev0, "LUN#%u/", uLUN));
-
- if (pDrv)
- {
- /* Re-use the driver instance so detach it before. */
- int rc = PDMDevHlpDriverDetach(pThis->pDevInsR3, PDMIBASE_2_PDMDRV(pDrv->pDrvBase), 0 /* fFlags */);
- if (RT_FAILURE(rc))
- return rc;
- }
-
-#define RC_CHECK() if (RT_FAILURE(rc)) { AssertReleaseRC(rc); break; }
-
- int rc = VINF_SUCCESS;
- do
- {
- PCFGMNODE pLunL0;
- rc = CFGMR3InsertNodeF(pDev0, &pLunL0, "LUN#%u/", uLUN); RC_CHECK();
- rc = CFGMR3InsertString(pLunL0, "Driver", "AUDIO"); RC_CHECK();
- rc = CFGMR3InsertNode(pLunL0, "Config/", NULL); RC_CHECK();
-
- PCFGMNODE pLunL1, pLunL2;
- rc = CFGMR3InsertNode (pLunL0, "AttachedDriver/", &pLunL1); RC_CHECK();
- rc = CFGMR3InsertNode (pLunL1, "Config/", &pLunL2); RC_CHECK();
- rc = CFGMR3InsertString(pLunL1, "Driver", pszDriver); RC_CHECK();
-
- rc = CFGMR3InsertString(pLunL2, "AudioDriver", pszDriver); RC_CHECK();
-
- } while (0);
-
- if (RT_SUCCESS(rc))
- rc = sb16AttachInternal(pThis->pDevInsR3, pDrv, uLUN, 0 /* fFlags */);
-
- LogFunc(("pThis=%p, uLUN=%u, pszDriver=%s, rc=%Rrc\n", pThis, uLUN, pszDriver, rc));
-
-#undef RC_CHECK
-
- return rc;
-}
-
-static int magic_of_irq(int irq)
-{
- switch (irq)
- {
- case 5:
- return 2;
- case 7:
- return 4;
- case 9:
- return 1;
- case 10:
- return 8;
- default:
- break;
- }
-
- LogFlowFunc(("bad irq %d\n", irq));
- return 2;
-}
-
-static int irq_of_magic(int magic)
-{
- switch (magic)
- {
- case 1:
- return 9;
- case 2:
- return 5;
- case 4:
- return 7;
- case 8:
- return 10;
- default:
- break;
- }
-
- LogFlowFunc(("bad irq magic %d\n", magic));
- return -1;
-}
-
-#if 0 // unused
-static inline void log_dsp(PSB16STATE pThis)
-{
- LogFlowFunc(("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
- pThis->fmt_stereo ? "Stereo" : "Mono",
- pThis->fmt_signed ? "Signed" : "Unsigned",
- pThis->fmt_bits,
- pThis->dma_auto ? "Auto" : "Single",
- pThis->block_size,
- pThis->freq,
- pThis->time_const,
- pThis->speaker));
-}
-#endif
-
-static void sb16SpeakerControl(PSB16STATE pThis, int on)
-{
- pThis->speaker = on;
- /* AUD_enable (pThis->voice, on); */
-}
-
-static void sb16Control(PSB16STATE pThis, int hold)
-{
- int dma = pThis->use_hdma ? pThis->hdma : pThis->dma;
- pThis->dma_running = hold;
-
- LogFlowFunc(("hold %d high %d dma %d\n", hold, pThis->use_hdma, dma));
-
- PSB16DRIVER pDrv;
- if (hold)
- {
- PDMDevHlpDMASetDREQ (pThis->pDevInsR3, dma, 1);
- PDMDevHlpDMASchedule (pThis->pDevInsR3);
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
- pDrv->Out.pStrmOut, true /* fEnable */);
- }
- else
- {
- PDMDevHlpDMASetDREQ (pThis->pDevInsR3, dma, 0);
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- pDrv->pConnector->pfnEnableOut(pDrv->pConnector,
- pDrv->Out.pStrmOut, false /* fEnable */);
- }
-}
-
-static DECLCALLBACK(void) sb16TimerIRQ(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvThis)
-{
- RT_NOREF(pDevIns, pTimer);
- PSB16STATE pThis = (PSB16STATE)pvThis;
- pThis->can_write = 1;
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
-}
-
-#define DMA8_AUTO 1
-#define DMA8_HIGH 2
-
-static void continue_dma8(PSB16STATE pThis)
-{
- if (pThis->freq > 0)
- {
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = pThis->freq;
- streamCfg.cChannels = 1 << pThis->fmt_stereo;
- streamCfg.enmFormat = pThis->fmt;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- int rc = sb16OpenOut(pThis, &streamCfg);
- AssertRC(rc);
- }
-
- sb16Control(pThis, 1);
-}
-
-static void dma_cmd8(PSB16STATE pThis, int mask, int dma_len)
-{
- pThis->fmt = AUD_FMT_U8;
- pThis->use_hdma = 0;
- pThis->fmt_bits = 8;
- pThis->fmt_signed = 0;
- pThis->fmt_stereo = (pThis->mixer_regs[0x0e] & 2) != 0;
-
- if (-1 == pThis->time_const)
- {
- if (pThis->freq <= 0)
- pThis->freq = 11025;
- }
- else
- {
- int tmp = (256 - pThis->time_const);
- pThis->freq = (1000000 + (tmp / 2)) / tmp;
- }
-
- if (dma_len != -1)
- {
- pThis->block_size = dma_len << pThis->fmt_stereo;
- }
- else
- {
- /* This is apparently the only way to make both Act1/PL
- and SecondReality/FC work
-
- r=andy Wow, actually someone who remembers Future Crew :-)
-
- Act1 sets block size via command 0x48 and it's an odd number
- SR does the same with even number
- Both use stereo, and Creatives own documentation states that
- 0x48 sets block size in bytes less one.. go figure */
- pThis->block_size &= ~pThis->fmt_stereo;
- }
-
- pThis->freq >>= pThis->fmt_stereo;
- pThis->left_till_irq = pThis->block_size;
- pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo);
- /* pThis->highspeed = (mask & DMA8_HIGH) != 0; */
- pThis->dma_auto = (mask & DMA8_AUTO) != 0;
- pThis->align = (1 << pThis->fmt_stereo) - 1;
-
- if (pThis->block_size & pThis->align)
- LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
- pThis->block_size, pThis->align + 1));
-
- LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
- pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
- pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
-
- continue_dma8(pThis);
- sb16SpeakerControl(pThis, 1);
-}
-
-static void dma_cmd(PSB16STATE pThis, uint8_t cmd, uint8_t d0, int dma_len)
-{
- pThis->use_hdma = cmd < 0xc0;
- pThis->fifo = (cmd >> 1) & 1;
- pThis->dma_auto = (cmd >> 2) & 1;
- pThis->fmt_signed = (d0 >> 4) & 1;
- pThis->fmt_stereo = (d0 >> 5) & 1;
-
- switch (cmd >> 4)
- {
- case 11:
- pThis->fmt_bits = 16;
- break;
-
- case 12:
- pThis->fmt_bits = 8;
- break;
- }
-
- if (-1 != pThis->time_const)
- {
-#if 1
- int tmp = 256 - pThis->time_const;
- pThis->freq = (1000000 + (tmp / 2)) / tmp;
-#else
- /* pThis->freq = 1000000 / ((255 - pThis->time_const) << pThis->fmt_stereo); */
- pThis->freq = 1000000 / ((255 - pThis->time_const));
-#endif
- pThis->time_const = -1;
- }
-
- pThis->block_size = dma_len + 1;
- pThis->block_size <<= ((pThis->fmt_bits == 16) ? 1 : 0);
- if (!pThis->dma_auto)
- {
- /*
- * It is clear that for DOOM and auto-init this value
- * shouldn't take stereo into account, while Miles Sound Systems
- * setsound.exe with single transfer mode wouldn't work without it
- * wonders of SB16 yet again.
- */
- pThis->block_size <<= pThis->fmt_stereo;
- }
-
- LogFlowFunc(("freq %d, stereo %d, sign %d, bits %d, dma %d, auto %d, fifo %d, high %d\n",
- pThis->freq, pThis->fmt_stereo, pThis->fmt_signed, pThis->fmt_bits,
- pThis->block_size, pThis->dma_auto, pThis->fifo, pThis->highspeed));
-
- if (16 == pThis->fmt_bits)
- pThis->fmt = pThis->fmt_signed ? AUD_FMT_S16 : AUD_FMT_U16;
- else
- pThis->fmt = pThis->fmt_signed ? AUD_FMT_S8 : AUD_FMT_U8;
-
- pThis->left_till_irq = pThis->block_size;
-
- pThis->bytes_per_second = (pThis->freq << pThis->fmt_stereo) << ((pThis->fmt_bits == 16) ? 1 : 0);
- pThis->highspeed = 0;
- pThis->align = (1 << (pThis->fmt_stereo + (pThis->fmt_bits == 16))) - 1;
- if (pThis->block_size & pThis->align)
- {
- LogFlowFunc(("warning: misaligned block size %d, alignment %d\n",
- pThis->block_size, pThis->align + 1));
- }
-
- if (pThis->freq)
- {
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = pThis->freq;
- streamCfg.cChannels = 1 << pThis->fmt_stereo;
- streamCfg.enmFormat = pThis->fmt;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- int rc = sb16OpenOut(pThis, &streamCfg);
- AssertRC(rc);
- }
-
- sb16Control(pThis, 1);
- sb16SpeakerControl(pThis, 1);
-}
-
-static inline void dsp_out_data (PSB16STATE pThis, uint8_t val)
-{
- LogFlowFunc(("outdata %#x\n", val));
- if ((size_t) pThis->out_data_len < sizeof (pThis->out_data)) {
- pThis->out_data[pThis->out_data_len++] = val;
- }
-}
-
-static inline uint8_t dsp_get_data (PSB16STATE pThis)
-{
- if (pThis->in_index) {
- return pThis->in2_data[--pThis->in_index];
- }
- else {
- LogFlowFunc(("buffer underflow\n"));
- return 0;
- }
-}
-
-static void sb16HandleCommand(PSB16STATE pThis, uint8_t cmd)
-{
- LogFlowFunc(("command %#x\n", cmd));
-
- if (cmd > 0xaf && cmd < 0xd0)
- {
- if (cmd & 8) /** @todo Handle recording. */
- LogFlowFunc(("ADC not yet supported (command %#x)\n", cmd));
-
- switch (cmd >> 4)
- {
- case 11:
- case 12:
- break;
- default:
- LogFlowFunc(("%#x wrong bits\n", cmd));
- }
-
- pThis->needed_bytes = 3;
- }
- else
- {
- pThis->needed_bytes = 0;
-
- switch (cmd)
- {
- case 0x03:
- dsp_out_data(pThis, 0x10); /* pThis->csp_param); */
- goto warn;
-
- case 0x04:
- pThis->needed_bytes = 1;
- goto warn;
-
- case 0x05:
- pThis->needed_bytes = 2;
- goto warn;
-
- case 0x08:
- /* __asm__ ("int3"); */
- goto warn;
-
- case 0x0e:
- pThis->needed_bytes = 2;
- goto warn;
-
- case 0x09:
- dsp_out_data(pThis, 0xf8);
- goto warn;
-
- case 0x0f:
- pThis->needed_bytes = 1;
- goto warn;
-
- case 0x10:
- pThis->needed_bytes = 1;
- goto warn;
-
- case 0x14:
- pThis->needed_bytes = 2;
- pThis->block_size = 0;
- break;
-
- case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
- dma_cmd8(pThis, DMA8_AUTO, -1);
- break;
-
- case 0x20: /* Direct ADC, Juice/PL */
- dsp_out_data(pThis, 0xff);
- goto warn;
-
- case 0x35:
- LogFlowFunc(("0x35 - MIDI command not implemented\n"));
- break;
-
- case 0x40:
- pThis->freq = -1;
- pThis->time_const = -1;
- pThis->needed_bytes = 1;
- break;
-
- case 0x41:
- pThis->freq = -1;
- pThis->time_const = -1;
- pThis->needed_bytes = 2;
- break;
-
- case 0x42:
- pThis->freq = -1;
- pThis->time_const = -1;
- pThis->needed_bytes = 2;
- goto warn;
-
- case 0x45:
- dsp_out_data(pThis, 0xaa);
- goto warn;
-
- case 0x47: /* Continue Auto-Initialize DMA 16bit */
- break;
-
- case 0x48:
- pThis->needed_bytes = 2;
- break;
-
- case 0x74:
- pThis->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
- LogFlowFunc(("0x75 - DMA DAC, 4-bit ADPCM not implemented\n"));
- break;
-
- case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
- pThis->needed_bytes = 2;
- LogFlowFunc(("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n"));
- break;
-
- case 0x76: /* DMA DAC, 2.6-bit ADPCM */
- pThis->needed_bytes = 2;
- LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n"));
- break;
-
- case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
- pThis->needed_bytes = 2;
- LogFlowFunc(("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n"));
- break;
-
- case 0x7d:
- LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n"));
- LogFlowFunc(("not implemented\n"));
- break;
-
- case 0x7f:
- LogFlowFunc(("0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"));
- LogFlowFunc(("not implemented\n"));
- break;
-
- case 0x80:
- pThis->needed_bytes = 2;
- break;
-
- case 0x90:
- case 0x91:
- dma_cmd8(pThis, (((cmd & 1) == 0) ? 1 : 0) | DMA8_HIGH, -1);
- break;
-
- case 0xd0: /* halt DMA operation. 8bit */
- sb16Control(pThis, 0);
- break;
-
- case 0xd1: /* speaker on */
- sb16SpeakerControl(pThis, 1);
- break;
-
- case 0xd3: /* speaker off */
- sb16SpeakerControl(pThis, 0);
- break;
-
- case 0xd4: /* continue DMA operation. 8bit */
- /* KQ6 (or maybe Sierras audblst.drv in general) resets
- the frequency between halt/continue */
- continue_dma8(pThis);
- break;
-
- case 0xd5: /* halt DMA operation. 16bit */
- sb16Control(pThis, 0);
- break;
-
- case 0xd6: /* continue DMA operation. 16bit */
- sb16Control(pThis, 1);
- break;
-
- case 0xd9: /* exit auto-init DMA after this block. 16bit */
- pThis->dma_auto = 0;
- break;
-
- case 0xda: /* exit auto-init DMA after this block. 8bit */
- pThis->dma_auto = 0;
- break;
-
- case 0xe0: /* DSP identification */
- pThis->needed_bytes = 1;
- break;
-
- case 0xe1:
- dsp_out_data(pThis, pThis->ver & 0xff);
- dsp_out_data(pThis, pThis->ver >> 8);
- break;
-
- case 0xe2:
- pThis->needed_bytes = 1;
- goto warn;
-
- case 0xe3:
- {
- for (int i = sizeof (e3) - 1; i >= 0; --i)
- dsp_out_data(pThis, e3[i]);
-
- break;
- }
-
- case 0xe4: /* write test reg */
- pThis->needed_bytes = 1;
- break;
-
- case 0xe7:
- LogFlowFunc(("Attempt to probe for ESS (0xe7)?\n"));
- break;
-
- case 0xe8: /* read test reg */
- dsp_out_data(pThis, pThis->test_reg);
- break;
-
- case 0xf2:
- case 0xf3:
- dsp_out_data(pThis, 0xaa);
- pThis->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
- break;
-
- case 0xf8:
- /* Undocumented, used by old Creative diagnostic programs. */
- dsp_out_data (pThis, 0);
- goto warn;
-
- case 0xf9:
- pThis->needed_bytes = 1;
- goto warn;
-
- case 0xfa:
- dsp_out_data (pThis, 0);
- goto warn;
-
- case 0xfc: /* FIXME */
- dsp_out_data (pThis, 0);
- goto warn;
-
- default:
- LogFlowFunc(("Unrecognized command %#x\n", cmd));
- break;
- }
- }
-
- if (!pThis->needed_bytes)
- LogFlow(("\n"));
-
-exit:
-
- if (!pThis->needed_bytes)
- pThis->cmd = -1;
- else
- pThis->cmd = cmd;
-
- return;
-
-warn:
- LogFlowFunc(("warning: command %#x,%d is not truly understood yet\n",
- cmd, pThis->needed_bytes));
- goto exit;
-}
-
-static uint16_t dsp_get_lohi (PSB16STATE pThis)
-{
- uint8_t hi = dsp_get_data (pThis);
- uint8_t lo = dsp_get_data (pThis);
- return (hi << 8) | lo;
-}
-
-static uint16_t dsp_get_hilo (PSB16STATE pThis)
-{
- uint8_t lo = dsp_get_data (pThis);
- uint8_t hi = dsp_get_data (pThis);
- return (hi << 8) | lo;
-}
-
-static void complete(PSB16STATE pThis)
-{
- int d0, d1, d2;
- LogFlowFunc(("complete command %#x, in_index %d, needed_bytes %d\n",
- pThis->cmd, pThis->in_index, pThis->needed_bytes));
-
- if (pThis->cmd > 0xaf && pThis->cmd < 0xd0)
- {
- d2 = dsp_get_data (pThis);
- d1 = dsp_get_data (pThis);
- d0 = dsp_get_data (pThis);
-
- if (pThis->cmd & 8)
- LogFlowFunc(("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, d0, d1, d2));
- else
- {
- LogFlowFunc(("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n", pThis->cmd, d0, d1, d2));
- dma_cmd(pThis, pThis->cmd, d0, d1 + (d2 << 8));
- }
- }
- else
- {
- switch (pThis->cmd)
- {
- case 0x04:
- pThis->csp_mode = dsp_get_data (pThis);
- pThis->csp_reg83r = 0;
- pThis->csp_reg83w = 0;
- LogFlowFunc(("CSP command 0x04: mode=%#x\n", pThis->csp_mode));
- break;
-
- case 0x05:
- pThis->csp_param = dsp_get_data (pThis);
- pThis->csp_value = dsp_get_data (pThis);
- LogFlowFunc(("CSP command 0x05: param=%#x value=%#x\n",
- pThis->csp_param,
- pThis->csp_value));
- break;
-
- case 0x0e:
- {
- d0 = dsp_get_data(pThis);
- d1 = dsp_get_data(pThis);
- LogFlowFunc(("write CSP register %d <- %#x\n", d1, d0));
- if (d1 == 0x83)
- {
- LogFlowFunc(("0x83[%d] <- %#x\n", pThis->csp_reg83r, d0));
- pThis->csp_reg83[pThis->csp_reg83r % 4] = d0;
- pThis->csp_reg83r += 1;
- }
- else
- pThis->csp_regs[d1] = d0;
- break;
- }
-
- case 0x0f:
- d0 = dsp_get_data(pThis);
- LogFlowFunc(("read CSP register %#x -> %#x, mode=%#x\n", d0, pThis->csp_regs[d0], pThis->csp_mode));
- if (d0 == 0x83)
- {
- LogFlowFunc(("0x83[%d] -> %#x\n",
- pThis->csp_reg83w,
- pThis->csp_reg83[pThis->csp_reg83w % 4]));
- dsp_out_data (pThis, pThis->csp_reg83[pThis->csp_reg83w % 4]);
- pThis->csp_reg83w += 1;
- }
- else
- dsp_out_data(pThis, pThis->csp_regs[d0]);
- break;
-
- case 0x10:
- d0 = dsp_get_data(pThis);
- LogFlowFunc(("cmd 0x10 d0=%#x\n", d0));
- break;
-
- case 0x14:
- dma_cmd8(pThis, 0, dsp_get_lohi (pThis) + 1);
- break;
-
- case 0x40:
- pThis->time_const = dsp_get_data(pThis);
- LogFlowFunc(("set time const %d\n", pThis->time_const));
- break;
-
- case 0x42: /* FT2 sets output freq with this, go figure */
-#if 0
- LogFlowFunc(("cmd 0x42 might not do what it think it should\n"));
-#endif
- case 0x41:
- pThis->freq = dsp_get_hilo(pThis);
- LogFlowFunc(("set freq %d\n", pThis->freq));
- break;
-
- case 0x48:
- pThis->block_size = dsp_get_lohi(pThis) + 1;
- LogFlowFunc(("set dma block len %d\n", pThis->block_size));
- break;
-
- case 0x74:
- case 0x75:
- case 0x76:
- case 0x77:
- /* ADPCM stuff, ignore */
- break;
-
- case 0x80:
- {
- int freq, samples, bytes;
- uint64_t ticks;
-
- freq = pThis->freq > 0 ? pThis->freq : 11025;
- samples = dsp_get_lohi (pThis) + 1;
- bytes = samples << pThis->fmt_stereo << ((pThis->fmt_bits == 16) ? 1 : 0);
- ticks = (bytes * TMTimerGetFreq(pThis->pTimerIRQ)) / freq;
- if (ticks < TMTimerGetFreq(pThis->pTimerIRQ) / 1024)
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
- else
- TMTimerSet(pThis->pTimerIRQ, TMTimerGet(pThis->pTimerIRQ) + ticks);
- LogFlowFunc(("mix silence: %d samples, %d bytes, %RU64 ticks\n", samples, bytes, ticks));
- break;
- }
-
- case 0xe0:
- d0 = dsp_get_data(pThis);
- pThis->out_data_len = 0;
- LogFlowFunc(("E0 data = %#x\n", d0));
- dsp_out_data(pThis, ~d0);
- break;
-
- case 0xe2:
- d0 = dsp_get_data(pThis);
- LogFlow(("SB16:E2 = %#x\n", d0));
- break;
-
- case 0xe4:
- pThis->test_reg = dsp_get_data(pThis);
- break;
-
- case 0xf9:
- d0 = dsp_get_data(pThis);
- LogFlowFunc(("command 0xf9 with %#x\n", d0));
- switch (d0) {
- case 0x0e:
- dsp_out_data(pThis, 0xff);
- break;
-
- case 0x0f:
- dsp_out_data(pThis, 0x07);
- break;
-
- case 0x37:
- dsp_out_data(pThis, 0x38);
- break;
-
- default:
- dsp_out_data(pThis, 0x00);
- break;
- }
- break;
-
- default:
- LogFlowFunc(("complete: unrecognized command %#x\n", pThis->cmd));
- return;
- }
- }
-
- LogFlow(("\n"));
- pThis->cmd = -1;
- return;
-}
-
-static uint8_t sb16MixRegToVol(PSB16STATE pThis, int reg)
-{
- /* The SB16 mixer has a 0 to -62dB range in 32 levels (2dB each step).
- * We use a 0 to -96dB range in 256 levels (0.375dB each step).
- * Only the top 5 bits of a mixer register are used.
- */
- uint8_t steps = 31 - (pThis->mixer_regs[reg] >> 3);
- uint8_t vol = 255 - steps * 16 / 3; /* (2dB*8) / (0.375dB*8) */
- return vol;
-}
-
-static void sb16SetMasterVolume(PSB16STATE pThis)
-{
- /* There's no mute switch, only volume controls. */
- uint8_t lvol = sb16MixRegToVol(pThis, 0x30);
- uint8_t rvol = sb16MixRegToVol(pThis, 0x31);
- PDMAUDIOVOLUME vol = { false, lvol, rvol };
- AudioMixerSetMasterVolume(pThis->pMixer, &vol);
-}
-
-static void sb16SetPcmOutVolume(PSB16STATE pThis)
-{
- /* There's no mute switch, only volume controls. */
- uint8_t lvol = sb16MixRegToVol(pThis, 0x32);
- uint8_t rvol = sb16MixRegToVol(pThis, 0x33);
- PDMAUDIOVOLUME vol = { false, lvol, rvol };
- AudioMixerSetSinkVolume(pThis->pSinkOutput, &vol);
-}
-
-static void sb16ResetLegacy(PSB16STATE pThis)
-{
- pThis->freq = 11025;
- pThis->fmt_signed = 0;
- pThis->fmt_bits = 8;
- pThis->fmt_stereo = 0;
-
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = pThis->freq;
- streamCfg.cChannels = 1; /* Mono */
- streamCfg.enmFormat = AUD_FMT_U8;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- int rc2 = sb16OpenOut(pThis, &streamCfg);
- AssertRC(rc2);
-}
-
-static void sb16Reset(PSB16STATE pThis)
-{
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
- if (pThis->dma_auto)
- {
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 1);
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
- }
-
- pThis->mixer_regs[0x82] = 0;
- pThis->dma_auto = 0;
- pThis->in_index = 0;
- pThis->out_data_len = 0;
- pThis->left_till_irq = 0;
- pThis->needed_bytes = 0;
- pThis->block_size = -1;
- pThis->nzero = 0;
- pThis->highspeed = 0;
- pThis->v2x6 = 0;
- pThis->cmd = -1;
-
- dsp_out_data(pThis, 0xaa);
- sb16SpeakerControl(pThis, 0);
- sb16Control(pThis, 0);
- sb16ResetLegacy(pThis);
-}
-
-static IO_WRITE_PROTO(dsp_write)
-{
- RT_NOREF(cb);
- PSB16STATE pThis = (PSB16STATE)opaque;
- int iport = nport - pThis->port;
-
- LogFlowFunc(("write %#x <- %#x\n", nport, val));
- switch (iport)
- {
- case 0x06:
- switch (val)
- {
- case 0x00:
- {
- if (pThis->v2x6 == 1)
- {
- if (0 && pThis->highspeed)
- {
- pThis->highspeed = 0;
- PDMDevHlpISASetIrq(pDevIns, pThis->irq, 0);
- sb16Control(pThis, 0);
- }
- else
- sb16Reset(pThis);
- }
- pThis->v2x6 = 0;
- break;
- }
-
- case 0x01:
- case 0x03: /* FreeBSD kludge */
- pThis->v2x6 = 1;
- break;
-
- case 0xc6:
- pThis->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
- break;
-
- case 0xb8: /* Panic */
- sb16Reset(pThis);
- break;
-
- case 0x39:
- dsp_out_data(pThis, 0x38);
- sb16Reset(pThis);
- pThis->v2x6 = 0x39;
- break;
-
- default:
- pThis->v2x6 = val;
- break;
- }
- break;
-
- case 0x0c: /* Write data or command | write status */
-#if 0
- if (pThis->highspeed)
- break;
-#endif
- if (0 == pThis->needed_bytes)
- {
- sb16HandleCommand(pThis, val);
-#if 0
- if (0 == pThis->needed_bytes) {
- log_dsp (pThis);
- }
-#endif
- }
- else
- {
- if (pThis->in_index == sizeof (pThis->in2_data))
- {
- LogFlowFunc(("in data overrun\n"));
- }
- else
- {
- pThis->in2_data[pThis->in_index++] = val;
- if (pThis->in_index == pThis->needed_bytes)
- {
- pThis->needed_bytes = 0;
- complete (pThis);
-#if 0
- log_dsp (pThis);
-#endif
- }
- }
- }
- break;
-
- default:
- LogFlowFunc(("nport=%#x, val=%#x)\n", nport, val));
- break;
- }
-
- return VINF_SUCCESS;
-}
-
-static IO_READ_PROTO(dsp_read)
-{
- RT_NOREF(pDevIns, cb);
- PSB16STATE pThis = (PSB16STATE)opaque;
- int iport, retval, ack = 0;
-
- iport = nport - pThis->port;
-
- /** @todo reject non-byte access?
- * The spec does not mention a non-byte access so we should check how real hardware behaves. */
-
- switch (iport)
- {
- case 0x06: /* reset */
- retval = 0xff;
- break;
-
- case 0x0a: /* read data */
- if (pThis->out_data_len)
- {
- retval = pThis->out_data[--pThis->out_data_len];
- pThis->last_read_byte = retval;
- }
- else
- {
- if (pThis->cmd != -1)
- LogFlowFunc(("empty output buffer for command %#x\n", pThis->cmd));
- retval = pThis->last_read_byte;
- /* goto error; */
- }
- break;
-
- case 0x0c: /* 0 can write */
- retval = pThis->can_write ? 0 : 0x80;
- break;
-
- case 0x0d: /* timer interrupt clear */
- /* LogFlowFunc(("timer interrupt clear\n")); */
- retval = 0;
- break;
-
- case 0x0e: /* data available status | irq 8 ack */
- retval = (!pThis->out_data_len || pThis->highspeed) ? 0 : 0x80;
- if (pThis->mixer_regs[0x82] & 1)
- {
- ack = 1;
- pThis->mixer_regs[0x82] &= ~1;
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
- }
- break;
-
- case 0x0f: /* irq 16 ack */
- retval = 0xff;
- if (pThis->mixer_regs[0x82] & 2)
- {
- ack = 1;
- pThis->mixer_regs[0x82] &= ~2;
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
- }
- break;
-
- default:
- goto error;
- }
-
- if (!ack)
- LogFlowFunc(("read %#x -> %#x\n", nport, retval));
-
- *pu32 = retval;
- return VINF_SUCCESS;
-
- error:
- LogFlowFunc(("warning: dsp_read %#x error\n", nport));
- return VERR_IOM_IOPORT_UNUSED;
-}
-
-static void sb16MixerReset(PSB16STATE pThis)
-{
- PSB16DRIVER pDrv;
-
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- pDrv->Out.phStrmOut = NULL;
-
- pThis->pSinkOutput = NULL;
-
- if (pThis->pMixer)
- {
- AudioMixerDestroy(pThis->pMixer);
- pThis->pMixer = NULL;
- }
-
- memset(pThis->mixer_regs, 0xff, 0x7f);
- memset(pThis->mixer_regs + 0x83, 0xff, sizeof (pThis->mixer_regs) - 0x83);
-
- pThis->mixer_regs[0x02] = 4; /* master volume 3bits */
- pThis->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
- pThis->mixer_regs[0x08] = 0; /* CD volume 3bits */
- pThis->mixer_regs[0x0a] = 0; /* voice volume 2bits */
-
- /* d5=input filt, d3=lowpass filt, d1,d2=input source */
- pThis->mixer_regs[0x0c] = 0;
-
- /* d5=output filt, d1=stereo switch */
- pThis->mixer_regs[0x0e] = 0;
-
- /* voice volume L d5,d7, R d1,d3 */
- pThis->mixer_regs[0x04] = (12 << 4) | 12;
- /* master ... */
- pThis->mixer_regs[0x22] = (12 << 4) | 12;
- /* MIDI ... */
- pThis->mixer_regs[0x26] = (12 << 4) | 12;
-
- /* master/voice/MIDI L/R volume */
- for (int i = 0x30; i < 0x36; i++)
- pThis->mixer_regs[i] = 24 << 3; /* -14 dB */
-
- /* treble/bass */
- for (int i = 0x44; i < 0x48; i++)
- pThis->mixer_regs[i] = 0x80;
-
- int rc2 = AudioMixerCreate("SB16 Mixer", 0 /* uFlags */, &pThis->pMixer);
- if (RT_SUCCESS(rc2))
- {
- /* Set a default audio format for our mixer. */
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = 44100;
- streamCfg.cChannels = 2;
- streamCfg.enmFormat = AUD_FMT_S16;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- rc2 = AudioMixerSetDeviceFormat(pThis->pMixer, &streamCfg);
- AssertRC(rc2);
-
- /* Add all required audio sinks. */
- rc2 = AudioMixerAddSink(pThis->pMixer, "[Playback] PCM Output",
- AUDMIXSINKDIR_OUTPUT, &pThis->pSinkOutput);
- AssertRC(rc2);
- }
-
- /* Update the master (mixer) and PCM out volumes. */
- sb16SetMasterVolume(pThis);
- sb16SetPcmOutVolume(pThis);
-}
-
-static IO_WRITE_PROTO(mixer_write_indexb)
-{
- RT_NOREF(pDevIns, cb);
- PSB16STATE pThis = (PSB16STATE)opaque;
- (void) nport;
- pThis->mixer_nreg = val;
-
- return VINF_SUCCESS;
-}
-
-uint32_t popcount(uint32_t u) /** @todo r=andy WTF? */
-{
- u = ((u&0x55555555) + ((u>>1)&0x55555555));
- u = ((u&0x33333333) + ((u>>2)&0x33333333));
- u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
- u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
- u = ( u&0x0000ffff) + (u>>16);
- return u;
-}
-
-uint32_t lsbindex(uint32_t u)
-{
- return popcount((u & -(int32_t)u) - 1);
-}
-
-/* Convert SB16 to SB Pro mixer volume (left). */
-static inline void sb16ConvVolumeL(PSB16STATE pThis, unsigned reg, uint8_t val)
-{
- /* High nibble in SBP mixer. */
- pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0x0f) | (val & 0xf0);
-}
-
-/* Convert SB16 to SB Pro mixer volume (right). */
-static inline void sb16ConvVolumeR(PSB16STATE pThis, unsigned reg, uint8_t val)
-{
- /* Low nibble in SBP mixer. */
- pThis->mixer_regs[reg] = (pThis->mixer_regs[reg] & 0xf0) | (val >> 4);
-}
-
-/* Convert SB Pro to SB16 mixer volume (left + right). */
-static inline void sb16ConvVolumeOldToNew(PSB16STATE pThis, unsigned reg, uint8_t val)
-{
- /* Left channel. */
- pThis->mixer_regs[reg + 0] = (val & 0xf0) | RT_BIT(3);
- /* Right channel (the register immediately following). */
- pThis->mixer_regs[reg + 1] = (val << 4) | RT_BIT(3);
-}
-
-static IO_WRITE_PROTO(mixer_write_datab)
-{
- RT_NOREF(pDevIns, cb);
- PSB16STATE pThis = (PSB16STATE)opaque;
- bool fUpdateMaster = false;
- bool fUpdateStream = false;
-
- (void) nport;
- LogFlowFunc(("mixer_write [%#x] <- %#x\n", pThis->mixer_nreg, val));
-
- switch (pThis->mixer_nreg)
- {
- case 0x00:
- sb16MixerReset(pThis);
- /* And update the actual volume, too. */
- fUpdateMaster = true;
- fUpdateStream = true;
- break;
-
- case 0x04: /* Translate from old style voice volume (L/R). */
- sb16ConvVolumeOldToNew(pThis, 0x32, val);
- fUpdateStream = true;
- break;
-
- case 0x22: /* Translate from old style master volume (L/R). */
- sb16ConvVolumeOldToNew(pThis, 0x30, val);
- fUpdateMaster = true;
- break;
-
- case 0x26: /* Translate from old style MIDI volume (L/R). */
- sb16ConvVolumeOldToNew(pThis, 0x34, val);
- break;
-
- case 0x28: /* Translate from old style CD volume (L/R). */
- sb16ConvVolumeOldToNew(pThis, 0x36, val);
- break;
-
- case 0x2E: /* Translate from old style line volume (L/R). */
- sb16ConvVolumeOldToNew(pThis, 0x38, val);
- break;
-
- case 0x30: /* Translate to old style master volume (L). */
- sb16ConvVolumeL(pThis, 0x22, val);
- fUpdateMaster = true;
- break;
-
- case 0x31: /* Translate to old style master volume (R). */
- sb16ConvVolumeR(pThis, 0x22, val);
- fUpdateMaster = true;
- break;
-
- case 0x32: /* Translate to old style voice volume (L). */
- sb16ConvVolumeL(pThis, 0x04, val);
- fUpdateStream = true;
- break;
-
- case 0x33: /* Translate to old style voice volume (R). */
- sb16ConvVolumeR(pThis, 0x04, val);
- fUpdateStream = true;
- break;
-
- case 0x34: /* Translate to old style MIDI volume (L). */
- sb16ConvVolumeL(pThis, 0x26, val);
- break;
-
- case 0x35: /* Translate to old style MIDI volume (R). */
- sb16ConvVolumeR(pThis, 0x26, val);
- break;
-
- case 0x36: /* Translate to old style CD volume (L). */
- sb16ConvVolumeL(pThis, 0x28, val);
- break;
-
- case 0x37: /* Translate to old style CD volume (R). */
- sb16ConvVolumeR(pThis, 0x28, val);
- break;
-
- case 0x38: /* Translate to old style line volume (L). */
- sb16ConvVolumeL(pThis, 0x2E, val);
- break;
-
- case 0x39: /* Translate to old style line volume (R). */
- sb16ConvVolumeR(pThis, 0x2E, val);
- break;
-
- case 0x80:
- {
- int irq = irq_of_magic(val);
- LogFlowFunc(("setting irq to %d (val=%#x)\n", irq, val));
- if (irq > 0)
- pThis->irq = irq;
- break;
- }
-
- case 0x81:
- {
- int dma, hdma;
-
- dma = lsbindex (val & 0xf);
- hdma = lsbindex (val & 0xf0);
- if (dma != pThis->dma || hdma != pThis->hdma)
- LogFlow(("SB16: attempt to change DMA 8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
- dma, pThis->dma, hdma, pThis->hdma, val));
-#if 0
- pThis->dma = dma;
- pThis->hdma = hdma;
-#endif
- break;
- }
-
- case 0x82:
- LogFlowFunc(("attempt to write into IRQ status register (val=%#x)\n", val));
- return VINF_SUCCESS;
-
- default:
- if (pThis->mixer_nreg >= 0x80)
- LogFlowFunc(("attempt to write mixer[%#x] <- %#x\n", pThis->mixer_nreg, val));
- break;
- }
-
- pThis->mixer_regs[pThis->mixer_nreg] = val;
-
- /* Update the master (mixer) volume. */
- if (fUpdateMaster)
- sb16SetMasterVolume(pThis);
-
- /* Update the stream (PCM) volume. */
- if (fUpdateStream)
- sb16SetPcmOutVolume(pThis);
-
- return VINF_SUCCESS;
-}
-
-static IO_WRITE_PROTO(mixer_write)
-{
- PSB16STATE pThis = (PSB16STATE)opaque;
- int iport = nport - pThis->port;
- switch (cb)
- {
- case 1:
- switch (iport)
- {
- case 4:
- mixer_write_indexb (pDevIns, opaque, nport, val, 1);
- break;
- case 5:
- mixer_write_datab (pDevIns, opaque, nport, val, 1);
- break;
- }
- break;
- case 2:
- mixer_write_indexb (pDevIns, opaque, nport, val & 0xff, 1);
- mixer_write_datab (pDevIns, opaque, nport, (val >> 8) & 0xff, 1);
- break;
- default:
- AssertMsgFailed(("Port=%#x cb=%d u32=%#x\n", nport, cb, val));
- break;
- }
- return VINF_SUCCESS;
-}
-
-static IO_READ_PROTO(mixer_read)
-{
- RT_NOREF(pDevIns, cb);
- PSB16STATE pThis = (PSB16STATE)opaque;
-
- (void) nport;
-#ifndef DEBUG_SB16_MOST
- if (pThis->mixer_nreg != 0x82) {
- LogFlowFunc(("mixer_read[%#x] -> %#x\n",
- pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
- }
-#else
- LogFlowFunc(("mixer_read[%#x] -> %#x\n",
- pThis->mixer_nreg, pThis->mixer_regs[pThis->mixer_nreg]));
-#endif
- *pu32 = pThis->mixer_regs[pThis->mixer_nreg];
- return VINF_SUCCESS;
-}
-
-static int sb16WriteAudio(PSB16STATE pThis, int nchan, uint32_t dma_pos,
- uint32_t dma_len, int len)
-{
- uint8_t tmpbuf[_4K]; /** @todo Have a buffer on the heap. */
- uint32_t cbToWrite = len;
- uint32_t cbWrittenTotal = 0;
-
- while (cbToWrite)
- {
- uint32_t cbToRead;
- uint32_t cbRead;
-
- cbToRead = RT_MIN(dma_len - dma_pos, cbToWrite);
- if (cbToRead > sizeof(tmpbuf))
- cbToRead = sizeof(tmpbuf);
-
- int rc = PDMDevHlpDMAReadMemory(pThis->pDevInsR3, nchan, tmpbuf, dma_pos, cbToRead, &cbRead);
- AssertMsgRC(rc, ("DMAReadMemory -> %Rrc\n", rc));
-
- uint32_t cbWritten;
-
- /* Just multiplex the output to the connected backends.
- * No need to utilize the virtual mixer here (yet). */
- PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnWrite(pDrv->pConnector, pDrv->Out.pStrmOut,
- tmpbuf, cbToRead, &cbWritten);
- RT_NOREF(rc2);
- LogFlowFunc(("\tLUN#%RU8: rc=%Rrc, cbWritten=%RU32\n", pDrv->uLUN, rc2, cbWritten));
- }
-
- Assert(cbToWrite >= cbToRead);
- cbToWrite -= cbToRead;
- dma_pos = (dma_pos + cbToRead) % dma_len;
- cbWrittenTotal += cbToRead;
-
- if (!cbRead)
- break;
- }
-
- return cbWrittenTotal;
-}
-
-static DECLCALLBACK(uint32_t) sb16DMARead(PPDMDEVINS pDevIns, void *opaque, unsigned nchan, uint32_t dma_pos, uint32_t dma_len)
-{
- RT_NOREF(pDevIns);
- PSB16STATE pThis = (PSB16STATE)opaque;
- int till, copy, written, free;
-
- if (pThis->block_size <= 0)
- {
- LogFlowFunc(("invalid block size=%d nchan=%d dma_pos=%d dma_len=%d\n",
- pThis->block_size, nchan, dma_pos, dma_len));
- return dma_pos;
- }
-
- if (pThis->left_till_irq < 0)
- pThis->left_till_irq = pThis->block_size;
-
- PSB16DRIVER pDrv;
-
- uint32_t cbOutMin = UINT32_MAX;
- uint32_t cbOut;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- int rc2 = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
- NULL /* pcbIn */, &cbOut, NULL /* pcSamplesLive */);
- if (RT_SUCCESS(rc2))
- cbOutMin = RT_MIN(cbOutMin, cbOut);
- }
-
- LogFlowFunc(("cbOutMin=%RU32\n", cbOutMin));
- if (cbOutMin == UINT32_MAX)
- {
- free = dma_len;
- }
- else
- {
- free = cbOutMin & ~pThis->align; /** @todo int vs. uint32. */
- if ((free <= 0) || !dma_len)
- return dma_pos;
- }
-
- copy = free;
- till = pThis->left_till_irq;
-
-#ifdef DEBUG_SB16_MOST
- LogFlowFunc(("pos:%06d %d till:%d len:%d\n", dma_pos, free, till, dma_len));
-#endif
-
- if (copy >= till)
- {
- if (0 == pThis->dma_auto)
- {
- copy = till;
- }
- else
- {
- if (copy >= till + pThis->block_size)
- copy = till; /* Make sure we won't skip IRQs. */
- }
- }
-
- written = sb16WriteAudio(pThis, nchan, dma_pos, dma_len, copy);
- dma_pos = (dma_pos + written) % dma_len;
- pThis->left_till_irq -= written;
-
- if (pThis->left_till_irq <= 0)
- {
- pThis->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
- PDMDevHlpISASetIrq(pDevIns, pThis->irq, 1);
- if (0 == pThis->dma_auto)
- {
- sb16Control(pThis, 0);
- sb16SpeakerControl(pThis, 0);
- }
- }
-
-#ifdef DEBUG_SB16_MOST
- LogFlowFunc(("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
- dma_pos, free, dma_len, pThis->left_till_irq, copy, written,
- pThis->block_size));
-#endif
-
- while (pThis->left_till_irq <= 0)
- pThis->left_till_irq += pThis->block_size;
-
- return dma_pos;
-}
-
-static DECLCALLBACK(void) sb16TimerIO(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
-{
- RT_NOREF(pDevIns);
- PSB16STATE pThis = (PSB16STATE)pvUser;
- Assert(pThis == PDMINS_2_DATA(pDevIns, PSB16STATE));
- AssertPtr(pThis);
-
- uint32_t cbInMax = 0;
- uint32_t cbOutMin = UINT32_MAX;
-
- PSB16DRIVER pDrv;
-
- uint64_t cTicksNow = TMTimerGet(pTimer);
- uint64_t cTicksElapsed = cTicksNow - pThis->uTimerTSIO;
- uint64_t cTicksPerSec = TMTimerGetFreq(pTimer);
-
- pThis->uTimerTSIO = cTicksNow;
-
- /*
- * Calculate the mixer's (fixed) sampling rate.
- */
- AssertPtr(pThis->pMixer);
-
- PDMAUDIOSTREAMCFG mixerStrmCfg;
- int rc = AudioMixerGetDeviceFormat(pThis->pMixer, &mixerStrmCfg);
- AssertRC(rc);
-
- PDMPCMPROPS mixerStrmProps;
- rc = DrvAudioStreamCfgToProps(&mixerStrmCfg, &mixerStrmProps);
- AssertRC(rc);
-
- uint32_t cMixerSamplesMin = (int)((2 * cTicksElapsed * mixerStrmCfg.uHz + cTicksPerSec) / cTicksPerSec / 2);
- uint32_t cbMixerSamplesMin = cMixerSamplesMin << mixerStrmProps.cShift;
-
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- uint32_t cbIn = 0;
- uint32_t cbOut = 0;
-
- rc = pDrv->pConnector->pfnQueryStatus(pDrv->pConnector,
- &cbIn, &cbOut, NULL /* cSamplesLive */);
- if (RT_SUCCESS(rc))
- rc = pDrv->pConnector->pfnPlayOut(pDrv->pConnector, NULL /* cSamplesPlayed */);
-
-#ifdef DEBUG_TIMER
- LogFlowFunc(("LUN#%RU8: rc=%Rrc, cbIn=%RU32, cbOut=%RU32\n", pDrv->uLUN, rc, cbIn, cbOut));
-#endif
- /* If we there was an error handling (available) output or there simply is no output available,
- * then calculate the minimum data rate which must be processed by the device emulation in order
- * to function correctly.
- *
- * This is not the optimal solution, but as we have to deal with this on a timer-based approach
- * (until we have the audio callbacks) we need to have device' DMA engines running. */
- if (!pDrv->pConnector->pfnIsValidOut(pDrv->pConnector, pDrv->Out.pStrmOut))
- {
- /* Use the mixer's (fixed) sampling rate. */
- cbOut = RT_MAX(cbOut, cbMixerSamplesMin);
- continue;
- }
-
- const bool fIsActiveOut = pDrv->pConnector->pfnIsActiveOut(pDrv->pConnector, pDrv->Out.pStrmOut);
- if ( RT_FAILURE(rc)
- || !fIsActiveOut)
- {
- uint32_t cSamplesMin = (int)((2 * cTicksElapsed * pDrv->Out.pStrmOut->Props.uHz + cTicksPerSec) / cTicksPerSec / 2);
- uint32_t cbSamplesMin = AUDIOMIXBUF_S2B(&pDrv->Out.pStrmOut->MixBuf, cSamplesMin);
-
- Log2Func(("\trc=%Rrc, cSamplesMin=%RU32, cbSamplesMin=%RU32\n", rc, cSamplesMin, cbSamplesMin));
-
- cbOut = RT_MAX(cbOut, cbSamplesMin);
- }
-
- cbOutMin = RT_MIN(cbOutMin, cbOut);
- cbInMax = RT_MAX(cbInMax, cbIn);
- }
-
- Log2Func(("cbInMax=%RU32, cbOutMin=%RU32\n", cbInMax, cbOutMin));
-
- if (cbOutMin == UINT32_MAX)
- cbOutMin = 0;
-
- /*
- * Playback.
- */
- if (cbOutMin)
- {
- Assert(cbOutMin != UINT32_MAX);
-
- /* New space available, see if we can transfer more. */
- PDMDevHlpDMASchedule(pThis->pDevInsR3);
- }
-
- /*
- * Recording.
- */
- /** @todo Implement recording. */
-
- /* Kick the timer again. */
- uint64_t cTicks = pThis->cTimerTicksIO;
- /** @todo adjust cTicks down by now much cbOutMin represents. */
- TMTimerSet(pThis->pTimerIO, cTicksNow + cTicks);
-}
-
-static void sb16Save(PSSMHANDLE pSSM, PSB16STATE pThis)
-{
- SSMR3PutS32(pSSM, pThis->irq);
- SSMR3PutS32(pSSM, pThis->dma);
- SSMR3PutS32(pSSM, pThis->hdma);
- SSMR3PutS32(pSSM, pThis->port);
- SSMR3PutS32(pSSM, pThis->ver);
- SSMR3PutS32(pSSM, pThis->in_index);
- SSMR3PutS32(pSSM, pThis->out_data_len);
- SSMR3PutS32(pSSM, pThis->fmt_stereo);
- SSMR3PutS32(pSSM, pThis->fmt_signed);
- SSMR3PutS32(pSSM, pThis->fmt_bits);
-
- SSMR3PutU32(pSSM, pThis->fmt);
-
- SSMR3PutS32(pSSM, pThis->dma_auto);
- SSMR3PutS32(pSSM, pThis->block_size);
- SSMR3PutS32(pSSM, pThis->fifo);
- SSMR3PutS32(pSSM, pThis->freq);
- SSMR3PutS32(pSSM, pThis->time_const);
- SSMR3PutS32(pSSM, pThis->speaker);
- SSMR3PutS32(pSSM, pThis->needed_bytes);
- SSMR3PutS32(pSSM, pThis->cmd);
- SSMR3PutS32(pSSM, pThis->use_hdma);
- SSMR3PutS32(pSSM, pThis->highspeed);
- SSMR3PutS32(pSSM, pThis->can_write);
- SSMR3PutS32(pSSM, pThis->v2x6);
-
- SSMR3PutU8 (pSSM, pThis->csp_param);
- SSMR3PutU8 (pSSM, pThis->csp_value);
- SSMR3PutU8 (pSSM, pThis->csp_mode);
- SSMR3PutU8 (pSSM, pThis->csp_param); /* Bug compatible! */
- SSMR3PutMem(pSSM, pThis->csp_regs, 256);
- SSMR3PutU8 (pSSM, pThis->csp_index);
- SSMR3PutMem(pSSM, pThis->csp_reg83, 4);
- SSMR3PutS32(pSSM, pThis->csp_reg83r);
- SSMR3PutS32(pSSM, pThis->csp_reg83w);
-
- SSMR3PutMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
- SSMR3PutMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
- SSMR3PutU8 (pSSM, pThis->test_reg);
- SSMR3PutU8 (pSSM, pThis->last_read_byte);
-
- SSMR3PutS32(pSSM, pThis->nzero);
- SSMR3PutS32(pSSM, pThis->left_till_irq);
- SSMR3PutS32(pSSM, pThis->dma_running);
- SSMR3PutS32(pSSM, pThis->bytes_per_second);
- SSMR3PutS32(pSSM, pThis->align);
-
- SSMR3PutS32(pSSM, pThis->mixer_nreg);
- SSMR3PutMem(pSSM, pThis->mixer_regs, 256);
-
-}
-
-static int sb16Load(PSSMHANDLE pSSM, PSB16STATE pThis, int version_id)
-{
- RT_NOREF(version_id);
- SSMR3GetS32(pSSM, &pThis->irq);
- SSMR3GetS32(pSSM, &pThis->dma);
- SSMR3GetS32(pSSM, &pThis->hdma);
- SSMR3GetS32(pSSM, &pThis->port);
- SSMR3GetS32(pSSM, &pThis->ver);
- SSMR3GetS32(pSSM, &pThis->in_index);
- SSMR3GetS32(pSSM, &pThis->out_data_len);
- SSMR3GetS32(pSSM, &pThis->fmt_stereo);
- SSMR3GetS32(pSSM, &pThis->fmt_signed);
- SSMR3GetS32(pSSM, &pThis->fmt_bits);
-
- SSMR3GetU32(pSSM, (uint32_t *)&pThis->fmt);
-
- SSMR3GetS32(pSSM, &pThis->dma_auto);
- SSMR3GetS32(pSSM, &pThis->block_size);
- SSMR3GetS32(pSSM, &pThis->fifo);
- SSMR3GetS32(pSSM, &pThis->freq);
- SSMR3GetS32(pSSM, &pThis->time_const);
- SSMR3GetS32(pSSM, &pThis->speaker);
- SSMR3GetS32(pSSM, &pThis->needed_bytes);
- SSMR3GetS32(pSSM, &pThis->cmd);
- SSMR3GetS32(pSSM, &pThis->use_hdma);
- SSMR3GetS32(pSSM, &pThis->highspeed);
- SSMR3GetS32(pSSM, &pThis->can_write);
- SSMR3GetS32(pSSM, &pThis->v2x6);
-
- SSMR3GetU8 (pSSM, &pThis->csp_param);
- SSMR3GetU8 (pSSM, &pThis->csp_value);
- SSMR3GetU8 (pSSM, &pThis->csp_mode);
- SSMR3GetU8 (pSSM, &pThis->csp_param); /* Bug compatible! */
- SSMR3GetMem(pSSM, pThis->csp_regs, 256);
- SSMR3GetU8 (pSSM, &pThis->csp_index);
- SSMR3GetMem(pSSM, pThis->csp_reg83, 4);
- SSMR3GetS32(pSSM, &pThis->csp_reg83r);
- SSMR3GetS32(pSSM, &pThis->csp_reg83w);
-
- SSMR3GetMem(pSSM, pThis->in2_data, sizeof (pThis->in2_data));
- SSMR3GetMem(pSSM, pThis->out_data, sizeof (pThis->out_data));
- SSMR3GetU8 (pSSM, &pThis->test_reg);
- SSMR3GetU8 (pSSM, &pThis->last_read_byte);
-
- SSMR3GetS32(pSSM, &pThis->nzero);
- SSMR3GetS32(pSSM, &pThis->left_till_irq);
- SSMR3GetS32(pSSM, &pThis->dma_running);
- SSMR3GetS32(pSSM, &pThis->bytes_per_second);
- SSMR3GetS32(pSSM, &pThis->align);
-
- SSMR3GetS32(pSSM, &pThis->mixer_nreg);
- SSMR3GetMem(pSSM, pThis->mixer_regs, 256);
-
-#if 0
- PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- if (pDrv->Out.pStrmOut)
- {
- pDrv->pConnector->pfnCloseOut(pThis->pDrv, pDrv->Out.pStrmOut);
- pDrv->Out.pStrmOut = NULL;
- }
- }
-#endif
-
- if (pThis->dma_running)
- {
- if (pThis->freq)
- {
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = pThis->freq;
- streamCfg.cChannels = 1 << pThis->fmt_stereo;
- streamCfg.enmFormat = pThis->fmt;
- streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- int rc = sb16OpenOut(pThis, &streamCfg);
- AssertRC(rc);
- }
-
- sb16Control(pThis, 1);
- sb16SpeakerControl(pThis, pThis->speaker);
- }
-
- /* Update the master (mixer) and PCM out volumes. */
- sb16SetMasterVolume(pThis);
- sb16SetPcmOutVolume(pThis);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) sb16LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
-{
- RT_NOREF(uPass);
- PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
-
- SSMR3PutS32(pSSM, pThis->irqCfg);
- SSMR3PutS32(pSSM, pThis->dmaCfg);
- SSMR3PutS32(pSSM, pThis->hdmaCfg);
- SSMR3PutS32(pSSM, pThis->portCfg);
- SSMR3PutS32(pSSM, pThis->verCfg);
- return VINF_SSM_DONT_CALL_AGAIN;
-}
-
-static DECLCALLBACK(int) sb16SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
-{
- PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
-
- sb16LiveExec(pDevIns, pSSM, 0);
- sb16Save(pSSM, pThis);
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) sb16LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
-{
- PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
-
- AssertMsgReturn( uVersion == SB16_SAVE_STATE_VERSION
- || uVersion == SB16_SAVE_STATE_VERSION_VBOX_30,
- ("%u\n", uVersion),
- VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
- if (uVersion > SB16_SAVE_STATE_VERSION_VBOX_30)
- {
- int32_t irq;
- SSMR3GetS32 (pSSM, &irq);
- int32_t dma;
- SSMR3GetS32 (pSSM, &dma);
- int32_t hdma;
- SSMR3GetS32 (pSSM, &hdma);
- int32_t port;
- SSMR3GetS32 (pSSM, &port);
- int32_t ver;
- int rc = SSMR3GetS32 (pSSM, &ver);
- AssertRCReturn (rc, rc);
-
- if ( irq != pThis->irqCfg
- || dma != pThis->dmaCfg
- || hdma != pThis->hdmaCfg
- || port != pThis->portCfg
- || ver != pThis->verCfg)
- {
- return SSMR3SetCfgError(pSSM, RT_SRC_POS,
- N_("config changed: irq=%x/%x dma=%x/%x hdma=%x/%x port=%x/%x ver=%x/%x (saved/config)"),
- irq, pThis->irqCfg,
- dma, pThis->dmaCfg,
- hdma, pThis->hdmaCfg,
- port, pThis->portCfg,
- ver, pThis->verCfg);
- }
- }
-
- if (uPass != SSM_PASS_FINAL)
- return VINF_SUCCESS;
-
- sb16Load(pSSM, pThis, uVersion);
- return VINF_SUCCESS;
-}
-
-static int sb16OpenOut(PSB16STATE pThis, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- int rc = VINF_SUCCESS;
-
- PSB16DRIVER pDrv;
- uint8_t uLUN = 0;
-
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- char *pszDesc;
- if (RTStrAPrintf(&pszDesc, "[LUN#%RU8] sb16.po", uLUN) <= 0)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
- int rc2 = pDrv->pConnector->pfnCreateOut(pDrv->pConnector, pszDesc, pCfg, &pDrv->Out.pStrmOut);
- LogFlowFunc(("LUN#%RU8: Created output with rc=%Rrc\n", uLUN, rc));
- if (rc2 == VINF_SUCCESS) /* Note: Could return VWRN_ALREADY_EXISTS. */
- {
- AudioMixerRemoveStream(pThis->pSinkOutput, pDrv->Out.phStrmOut);
- rc = AudioMixerAddStreamOut(pThis->pSinkOutput,
- pDrv->pConnector, pDrv->Out.pStrmOut,
- 0 /* uFlags */,
- &pDrv->Out.phStrmOut);
- }
-
- RTStrFree(pszDesc);
-
- if (RT_FAILURE(rc2))
- {
- if (RT_SUCCESS(rc))
- rc = rc2;
- break;
- }
-
- uLUN++;
- }
-
- /* Ensure volume gets propagated. */
- AudioMixerInvalidate(pThis->pMixer);
-
- return rc;
-}
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnReset}
- */
-static DECLCALLBACK(void) sb16DevReset(PPDMDEVINS pDevIns)
-{
- PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
-
- /* Bring back the device to initial state, and especially make
- * sure there's no interrupt or DMA activity.
- */
- PDMDevHlpISASetIrq(pThis->pDevInsR3, pThis->irq, 0);
-
- pThis->mixer_regs[0x82] = 0;
- pThis->csp_regs[5] = 1;
- pThis->csp_regs[9] = 0xf8;
-
- pThis->dma_auto = 0;
- pThis->in_index = 0;
- pThis->out_data_len = 0;
- pThis->left_till_irq = 0;
- pThis->needed_bytes = 0;
- pThis->block_size = -1;
- pThis->nzero = 0;
- pThis->highspeed = 0;
- pThis->v2x6 = 0;
- pThis->cmd = -1;
-
- sb16MixerReset(pThis);
- sb16SpeakerControl(pThis, 0);
- sb16Control(pThis, 0);
- sb16ResetLegacy(pThis);
-}
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) sb16QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
-{
- PSB16STATE pThis = RT_FROM_MEMBER(pInterface, SB16STATE, IBase);
- Assert(&pThis->IBase == pInterface);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
- return NULL;
-}
-
-/**
- * @interface_method_impl{PDMDEVREG,pfnDestruct}
- */
-static DECLCALLBACK(int) sb16Destruct(PPDMDEVINS pDevIns)
-{
- PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
- PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
-
- PSB16DRIVER pDrv;
-
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- pDrv->Out.phStrmOut = NULL;
-
- pThis->pSinkOutput = NULL;
-
- if (pThis->pMixer)
- {
- AudioMixerDestroy(pThis->pMixer);
- pThis->pMixer = NULL;
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) sb16Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
-{
- RT_NOREF(iInstance);
- PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
- PSB16STATE pThis = PDMINS_2_DATA(pDevIns, PSB16STATE);
-
- /*
- * Validations.
- */
- Assert(iInstance == 0);
- if (!CFGMR3AreValuesValid(pCfg,
- "IRQ\0"
- "DMA\0"
- "DMA16\0"
- "Port\0"
- "Version\0"
- "TimerHz\0"))
- return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
- N_("Invalid configuration for SB16 device"));
-
- /*
- * Read config data.
- */
- int rc = CFGMR3QuerySIntDef(pCfg, "IRQ", &pThis->irq, 5);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("SB16 configuration error: Failed to get the \"IRQ\" value"));
- pThis->irqCfg = pThis->irq;
-
- rc = CFGMR3QuerySIntDef(pCfg, "DMA", &pThis->dma, 1);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("SB16 configuration error: Failed to get the \"DMA\" value"));
- pThis->dmaCfg = pThis->dma;
-
- rc = CFGMR3QuerySIntDef(pCfg, "DMA16", &pThis->hdma, 5);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("SB16 configuration error: Failed to get the \"DMA16\" value"));
- pThis->hdmaCfg = pThis->hdma;
-
- RTIOPORT Port;
- rc = CFGMR3QueryPortDef(pCfg, "Port", &Port, 0x220);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("SB16 configuration error: Failed to get the \"Port\" value"));
- pThis->port = Port;
- pThis->portCfg = Port;
-
- uint16_t u16Version;
- rc = CFGMR3QueryU16Def(pCfg, "Version", &u16Version, 0x0405);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("SB16 configuration error: Failed to get the \"Version\" value"));
-
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- uint16_t uTimerHz;
- rc = CFGMR3QueryU16Def(pCfg, "TimerHz", &uTimerHz, 200 /* Hz */);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("SB16 configuration error: failed to read Hertz (Hz) rate as unsigned integer"));
-#endif
-
- pThis->ver = u16Version;
- pThis->verCfg = u16Version;
-
- /*
- * Init instance data.
- */
- pThis->pDevInsR3 = pDevIns;
- pThis->IBase.pfnQueryInterface = sb16QueryInterface;
- pThis->cmd = -1;
-
- pThis->mixer_regs[0x80] = magic_of_irq (pThis->irq);
- pThis->mixer_regs[0x81] = (1 << pThis->dma) | (1 << pThis->hdma);
- pThis->mixer_regs[0x82] = 2 << 5;
-
- pThis->csp_regs[5] = 1;
- pThis->csp_regs[9] = 0xf8;
-
- RTListInit(&pThis->lstDrv);
-
- sb16MixerReset(pThis);
-
- /*
- * Create timer(s), register & attach stuff.
- */
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIRQ, pThis,
- TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IRQ timer", &pThis->pTimerIRQ);
- if (RT_FAILURE(rc))
- AssertMsgFailedReturn(("Error creating IRQ timer, rc=%Rrc\n", rc), rc);
-
- rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x04, 2, pThis,
- mixer_write, mixer_read, NULL, NULL, "SB16");
- if (RT_FAILURE(rc))
- return rc;
- rc = PDMDevHlpIOPortRegister(pDevIns, pThis->port + 0x06, 10, pThis,
- dsp_write, dsp_read, NULL, NULL, "SB16");
- if (RT_FAILURE(rc))
- return rc;
-
- rc = PDMDevHlpDMARegister(pDevIns, pThis->hdma, sb16DMARead, pThis);
- if (RT_FAILURE(rc))
- return rc;
- rc = PDMDevHlpDMARegister(pDevIns, pThis->dma, sb16DMARead, pThis);
- if (RT_FAILURE(rc))
- return rc;
-
- pThis->can_write = 1;
-
- rc = PDMDevHlpSSMRegister3(pDevIns, SB16_SAVE_STATE_VERSION, sizeof(SB16STATE), sb16LiveExec, sb16SaveExec, sb16LoadExec);
- if (RT_FAILURE(rc))
- return rc;
-
- /*
- * Attach driver.
- */
- uint8_t uLUN;
- for (uLUN = 0; uLUN < UINT8_MAX; ++uLUN)
- {
- LogFunc(("Trying to attach driver for LUN #%RU8 ...\n", uLUN));
- rc = sb16AttachInternal(pDevIns, NULL /* pDrv */, uLUN, 0 /* fFlags */);
- if (RT_FAILURE(rc))
- {
- if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
- rc = VINF_SUCCESS;
- else if (rc == VERR_AUDIO_BACKEND_INIT_FAILED)
- {
- sb16Reattach(pThis, NULL /* pDrv */, uLUN, "NullAudio");
- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
- N_("No audio devices could be opened. Selecting the NULL audio backend "
- "with the consequence that no sound is audible"));
- /* attaching to the NULL audio backend will never fail */
- rc = VINF_SUCCESS;
- }
- break;
- }
- }
-
- LogFunc(("cLUNs=%RU8, rc=%Rrc\n", uLUN, rc));
-
- sb16ResetLegacy(pThis);
-
- PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- /*
- * Only primary drivers are critical for the VM to run. Everything else
- * might not worth showing an own error message box in the GUI.
- */
- if (!(pDrv->Flags & PDMAUDIODRVFLAG_PRIMARY))
- continue;
-
- PPDMIAUDIOCONNECTOR pCon = pDrv->pConnector;
- AssertPtr(pCon);
-
- /* Note: No input streams available for SB16 yet. */
- bool fValidOut = pCon->pfnIsValidOut(pCon, pDrv->Out.pStrmOut);
- if (!fValidOut)
- {
- LogRel(("SB16: Falling back to NULL backend (no sound audible)\n"));
-
- sb16ResetLegacy(pThis);
- sb16Reattach(pThis, pDrv, pDrv->uLUN, "NullAudio");
-
- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "HostAudioNotResponding",
- N_("No audio devices could be opened. Selecting the NULL audio backend "
- "with the consequence that no sound is audible"));
- }
- }
-
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- if (RT_SUCCESS(rc))
- {
- rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, sb16TimerIO, pThis,
- TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "SB16 IO timer", &pThis->pTimerIO);
- if (RT_FAILURE(rc))
- AssertMsgFailedReturn(("Error creating I/O timer, rc=%Rrc\n", rc), rc);
- else
- {
- pThis->cTimerTicksIO = TMTimerGetFreq(pThis->pTimerIO) / uTimerHz;
- pThis->uTimerTSIO = TMTimerGet(pThis->pTimerIO);
- LogFunc(("Timer ticks=%RU64 (%RU16 Hz)\n", pThis->cTimerTicksIO, uTimerHz));
-
- /* Fire off timer. */
- TMTimerSet(pThis->pTimerIO, TMTimerGet(pThis->pTimerIO) + pThis->cTimerTicksIO);
- }
- }
-#else
- if (RT_SUCCESS(rc))
- {
- /** @todo Merge this callback registration with the validation block above once
- * this becomes the standard. */
- PSB16DRIVER pDrv;
- RTListForEach(&pThis->lstDrv, pDrv, SB16DRIVER, Node)
- {
- /* Only register primary driver.
- * The device emulation does the output multiplexing then. */
- if (pDrv->Flags != PDMAUDIODRVFLAG_PRIMARY)
- continue;
-
- PDMAUDIOCALLBACK AudioCallbacks[2];
-
- SB16CALLBACKCTX Ctx = { pThis, pDrv };
-
- AudioCallbacks[0].enmType = PDMAUDIOCALLBACKTYPE_INPUT;
- AudioCallbacks[0].pfnCallback = sb16CallbackInput;
- AudioCallbacks[0].pvCtx = &Ctx;
- AudioCallbacks[0].cbCtx = sizeof(SB16CALLBACKCTX);
-
- AudioCallbacks[1].enmType = PDMAUDIOCALLBACKTYPE_OUTPUT;
- AudioCallbacks[1].pfnCallback = sb16CallbackOutput;
- AudioCallbacks[1].pvCtx = &Ctx;
- AudioCallbacks[1].cbCtx = sizeof(SB16CALLBACKCTX);
-
- rc = pDrv->pConnector->pfnRegisterCallbacks(pDrv->pConnector, AudioCallbacks, RT_ELEMENTS(AudioCallbacks));
- if (RT_FAILURE(rc))
- break;
- }
- }
-#endif
-
- return VINF_SUCCESS;
-}
-
-const PDMDEVREG g_DeviceSB16 =
-{
- /* u32Version */
- PDM_DEVREG_VERSION,
- /* szName */
- "sb16",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Sound Blaster 16 Controller",
- /* fFlags */
- PDM_DEVREG_FLAGS_DEFAULT_BITS,
- /* fClass */
- PDM_DEVREG_CLASS_AUDIO,
- /* cMaxInstances */
- 1,
- /* cbInstance */
- sizeof(SB16STATE),
- /* pfnConstruct */
- sb16Construct,
- /* pfnDestruct */
- sb16Destruct,
- /* pfnRelocate */
- NULL,
- /* pfnMemSetup */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- sb16DevReset,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- sb16Attach,
- /* pfnDetach */
- sb16Detach,
- /* pfnQueryInterface */
- NULL,
- /* pfnInitComplete */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32VersionEnd */
- PDM_DEVREG_VERSION
-};
diff --git a/src/VBox/Devices/Audio_50/DrvAudio.cpp b/src/VBox/Devices/Audio_50/DrvAudio.cpp
deleted file mode 100644
index a7b8992..0000000
--- a/src/VBox/Devices/Audio_50/DrvAudio.cpp
+++ /dev/null
@@ -1,2627 +0,0 @@
-/* $Id: DrvAudio.cpp $ */
-/** @file
- * Intermediate audio driver header.
- *
- * @remarks Intermediate audio driver for connecting the audio device emulation
- * with the host backend.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- *
- * This code is based on: audio.c from QEMU AUDIO subsystem.
- *
- * QEMU Audio subsystem
- *
- * Copyright (c) 2003-2005 Vassili Karpov (malc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#define LOG_GROUP LOG_GROUP_DRV_AUDIO
-#include <VBox/log.h>
-#include <VBox/vmm/pdm.h>
-#include <VBox/err.h>
-#include <VBox/vmm/mm.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
-#include <iprt/alloc.h>
-#include <iprt/asm-math.h>
-#include <iprt/assert.h>
-#include <iprt/circbuf.h>
-#include <iprt/string.h>
-#include <iprt/uuid.h>
-
-#include "VBoxDD.h"
-
-#include <ctype.h>
-#include <stdlib.h>
-
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-
-typedef struct fixed_settings
-{
- int enabled;
- int cStreams;
- int greedy;
- PDMAUDIOSTREAMCFG settings;
-} fixed_settings;
-
-static struct {
- struct fixed_settings fixed_out;
- struct fixed_settings fixed_in;
- union {
- int hz;
- int64_t ticks;
- } period;
- int plive;
-} conf = {
-
- /* Fixed output settings. */
- { /* DAC fixed settings */
- 1, /* enabled */
- 1, /* cStreams */
- 1, /* greedy */
- {
- 44100, /* freq */
- 2, /* nchannels */
- AUD_FMT_S16, /* fmt */
- PDMAUDIOHOSTENDIANNESS
- }
- },
-
- /* Fixed input settings. */
- { /* ADC fixed settings */
- 1, /* enabled */
- 2, /* cStreams */
- 1, /* greedy */
- {
- 44100, /* freq */
- 2, /* nchannels */
- AUD_FMT_S16, /* fmt */
- PDMAUDIOHOSTENDIANNESS
- }
- },
-
- { 200 }, /* frequency (in Hz) */
- 0, /* plive */ /** @todo Disable pending live? */
-};
-
-static int drvAudioDestroyGstIn(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMIN pGstStrmIn);
-
-static int drvAudioAllocHstIn(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOHSTSTRMIN *ppHstStrmIn);
-static int drvAudioDestroyHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn);
-
-int drvAudioAddHstOut(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
-
- int rc;
- if ( conf.fixed_out.enabled /** @todo Get rid of these settings! */
- && conf.fixed_out.greedy)
- {
- rc = drvAudioAllocHstOut(pThis, pszName, pCfg, &pHstStrmOut);
- }
- else
- rc = VERR_NOT_FOUND;
-
- if (RT_FAILURE(rc))
- {
- pHstStrmOut = drvAudioFindSpecificOut(pThis, NULL, pCfg);
- if (!pHstStrmOut)
- {
- rc = drvAudioAllocHstOut(pThis, pszName, pCfg, &pHstStrmOut);
- if (RT_FAILURE(rc))
- pHstStrmOut = drvAudioFindAnyHstOut(pThis, NULL /* pHstStrmOut */);
- }
-
- rc = pHstStrmOut ? VINF_SUCCESS : rc;
- }
-
- if (RT_SUCCESS(rc))
- *ppHstStrmOut = pHstStrmOut;
-
- return rc;
-}
-
-static PDMAUDIOFMT drvAudioGetConfFormat(PCFGMNODE pCfgHandle, const char *pszKey,
- PDMAUDIOFMT enmDefault, bool *pfDefault)
-{
- if ( pCfgHandle == NULL
- || pszKey == NULL)
- {
- *pfDefault = true;
- return enmDefault;
- }
-
- char *pszValue = NULL;
- int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszKey, &pszValue);
- if (RT_FAILURE(rc))
- {
- *pfDefault = true;
- return enmDefault;
- }
-
- PDMAUDIOFMT fmt = drvAudioHlpStringToFormat(pszValue);
- if (fmt == AUD_FMT_INVALID)
- {
- *pfDefault = true;
- return enmDefault;
- }
-
- *pfDefault = false;
- return fmt;
-}
-
-static int drvAudioGetConfInt(PCFGMNODE pCfgHandle, const char *pszKey,
- int iDefault, bool *pfDefault)
-{
-
- if ( pCfgHandle == NULL
- || pszKey == NULL)
- {
- *pfDefault = true;
- return iDefault;
- }
-
- uint64_t u64Data = 0;
- int rc = CFGMR3QueryInteger(pCfgHandle, pszKey, &u64Data);
- if (RT_FAILURE(rc))
- {
- *pfDefault = true;
- return iDefault;
-
- }
-
- *pfDefault = false;
- return u64Data;
-}
-
-static const char *drvAudioGetConfStr(PCFGMNODE pCfgHandle, const char *pszKey,
- const char *pszDefault, bool *pfDefault)
-{
- if ( pCfgHandle == NULL
- || pszKey == NULL)
- {
- *pfDefault = true;
- return pszDefault;
- }
-
- char *pszValue = NULL;
- int rc = CFGMR3QueryStringAlloc(pCfgHandle, pszKey, &pszValue);
- if (RT_FAILURE(rc))
- {
- *pfDefault = true;
- return pszDefault;
- }
-
- *pfDefault = false;
- return pszValue;
-}
-
-static int drvAudioProcessOptions(PCFGMNODE pCfgHandle, const char *pszPrefix, struct audio_option *opt)
-{
- AssertPtrReturn(pCfgHandle, VERR_INVALID_POINTER);
- AssertPtrReturn(pszPrefix, VERR_INVALID_POINTER);
- AssertPtrReturn(opt, VERR_INVALID_POINTER);
-
- PCFGMNODE pCfgChildHandle = NULL;
- PCFGMNODE pCfgChildChildHandle = NULL;
-
- /* If pCfgHandle is NULL, let NULL be passed to get int and get string functions..
- * The getter function will return default values.
- */
- if (pCfgHandle != NULL)
- {
- /* If its audio general setting, need to traverse to one child node.
- * /Devices/ichac97/0/LUN#0/Config/Audio
- */
- if(!strncmp(pszPrefix, "AUDIO", 5)) /** @todo Use a \#define */
- {
- pCfgChildHandle = CFGMR3GetFirstChild(pCfgHandle);
- if(pCfgChildHandle)
- pCfgHandle = pCfgChildHandle;
- }
- else
- {
- /* If its driver specific configuration , then need to traverse two level deep child
- * child nodes. for eg. in case of DirectSoundConfiguration item
- * /Devices/ichac97/0/LUN#0/Config/Audio/DirectSoundConfig
- */
- pCfgChildHandle = CFGMR3GetFirstChild(pCfgHandle);
- if (pCfgChildHandle)
- {
- pCfgChildChildHandle = CFGMR3GetFirstChild(pCfgChildHandle);
- if (pCfgChildChildHandle)
- pCfgHandle = pCfgChildChildHandle;
- }
- }
- }
-
- for (; opt->name; opt++)
- {
- LogFlowFunc(("Option value pointer for `%s' is not set\n",
- opt->name));
- if (!opt->valp) {
- LogFlowFunc(("Option value pointer for `%s' is not set\n",
- opt->name));
- continue;
- }
-
- bool fUseDefault;
-
- switch (opt->tag)
- {
- case AUD_OPT_BOOL:
- case AUD_OPT_INT:
- {
- int *intp = (int *)opt->valp;
- *intp = drvAudioGetConfInt(pCfgHandle, opt->name, *intp, &fUseDefault);
-
- break;
- }
-
- case AUD_OPT_FMT:
- {
- PDMAUDIOFMT *fmtp = (PDMAUDIOFMT *)opt->valp;
- *fmtp = drvAudioGetConfFormat(pCfgHandle, opt->name, *fmtp, &fUseDefault);
-
- break;
- }
-
- case AUD_OPT_STR:
- {
- const char **strp = (const char **)opt->valp;
- *strp = drvAudioGetConfStr(pCfgHandle, opt->name, *strp, &fUseDefault);
-
- break;
- }
-
- default:
- LogFlowFunc(("Bad value tag for option `%s' - %d\n", opt->name, opt->tag));
- fUseDefault = false;
- break;
- }
-
- if (!opt->overridenp)
- opt->overridenp = &opt->overriden;
-
- *opt->overridenp = !fUseDefault;
- }
-
- return VINF_SUCCESS;
-}
-
-static bool drvAudioStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
-{
- bool fValid = ( pCfg->cChannels == 1
- || pCfg->cChannels == 2); /* Either stereo (2) or mono (1), per stream. */
-
- fValid |= ( pCfg->enmEndianness == PDMAUDIOENDIANNESS_LITTLE
- || pCfg->enmEndianness == PDMAUDIOENDIANNESS_BIG);
-
- if (fValid)
- {
- switch (pCfg->enmFormat)
- {
- case AUD_FMT_S8:
- case AUD_FMT_U8:
- case AUD_FMT_S16:
- case AUD_FMT_U16:
- case AUD_FMT_S32:
- case AUD_FMT_U32:
- break;
- default:
- fValid = false;
- break;
- }
- }
-
- /** @todo Check for defined frequencies supported. */
- fValid |= pCfg->uHz > 0;
-
-#ifdef DEBUG
- drvAudioStreamCfgPrint(pCfg);
-#endif
-
- LogFlowFunc(("pCfg=%p, fValid=%RTbool\n", pCfg, fValid));
- return fValid;
-}
-
-/**
- * Clears a sample buffer by the given amount of audio samples.
- *
- * @return IPRT status code.
- * @param pPCMProps PCM properties to use for the buffer to clear.
- * @param pvBuf Buffer to clear.
- * @param cbBuf Size (in bytes) of the buffer.
- * @param cSamples Number of audio samples to clear in the buffer.
- */
-void DrvAudioClearBuf(PPDMPCMPROPS pPCMProps, void *pvBuf, size_t cbBuf, uint32_t cSamples)
-{
- AssertPtrReturnVoid(pPCMProps);
- AssertPtrReturnVoid(pvBuf);
-
- if (!cbBuf || !cSamples)
- return;
-
- Log2Func(("pPCMInfo=%p, pvBuf=%p, cSamples=%RU32, fSigned=%RTbool, cBits=%RU8, cShift=%RU8\n",
- pPCMProps, pvBuf, cSamples, pPCMProps->fSigned, pPCMProps->cBits, pPCMProps->cShift));
-
- if (pPCMProps->fSigned)
- {
- memset(pvBuf, 0, cSamples << pPCMProps->cShift);
- }
- else
- {
- switch (pPCMProps->cBits)
- {
- case 8:
- {
- memset(pvBuf, 0x80, cSamples << pPCMProps->cShift);
- break;
- }
-
- case 16:
- {
- uint16_t *p = (uint16_t *)pvBuf;
- int shift = pPCMProps->cChannels - 1;
- short s = INT16_MAX;
-
- if (pPCMProps->fSwapEndian)
- s = RT_BSWAP_U16(s);
-
- for (unsigned i = 0; i < cSamples << shift; i++)
- p[i] = s;
-
- break;
- }
-
- case 32:
- {
- uint32_t *p = (uint32_t *)pvBuf;
- int shift = pPCMProps->cChannels - 1;
- int32_t s = INT32_MAX;
-
- if (pPCMProps->fSwapEndian)
- s = RT_BSWAP_U32(s);
-
- for (unsigned i = 0; i < cSamples << shift; i++)
- p[i] = s;
-
- break;
- }
-
- default:
- {
- AssertMsgFailed(("Invalid bits: %RU8\n", pPCMProps->cBits));
- break;
- }
- }
- }
-}
-
-static int drvAudioControlHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- int rc = RTCritSectEnter(&pHstStrmIn->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- {
- if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
- {
- rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_ENABLE);
- if (RT_SUCCESS(rc))
- {
- pHstStrmIn->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
- }
- else
- LogFlowFunc(("Backend reported an error when opening input stream, rc=%Rrc\n", rc));
- }
- else
- rc = VINF_SUCCESS;
-
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- {
- if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- {
- rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- {
- pHstStrmIn->fStatus = PDMAUDIOSTRMSTS_FLAG_NONE; /* Clear all. */
- AudioMixBufClear(&pHstStrmIn->MixBuf);
- }
- else
- LogFlowFunc(("Backend vetoed closing output stream, rc=%Rrc\n", rc));
- }
- else
- rc = VINF_SUCCESS;
-
- break;
- }
-
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- if (!(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED))
- {
- Assert(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
- rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_PAUSE);
- if (RT_SUCCESS(rc))
- {
- LogFunc(("[%s] Pausing stream\n", pHstStrmIn->MixBuf.pszName));
- pHstStrmIn->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
- }
- else
- LogFlowFunc(("Backend vetoed pausing input stream, rc=%Rrc\n", rc));
- }
- else
- rc = VINF_SUCCESS;
-
- break;
- }
-
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED)
- {
- Assert(pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
- rc = pThis->pHostDrvAudio->pfnControlIn(pThis->pHostDrvAudio, pHstStrmIn, PDMAUDIOSTREAMCMD_RESUME);
- if (RT_SUCCESS(rc))
- {
- pHstStrmIn->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
- LogFunc(("[%s] Resumed stream\n", pHstStrmIn->MixBuf.pszName));
- }
- else
- LogFlowFunc(("Backend vetoed resuming input stream, rc=%Rrc\n", rc));
- }
- else
- rc = VINF_SUCCESS;
-
- break;
- }
-
- default:
- AssertMsgFailed(("Command %ld not implemented\n", enmStreamCmd));
- rc = VERR_NOT_IMPLEMENTED;
- break;
- }
-
- int rc2 = RTCritSectLeave(&pHstStrmIn->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- return rc;
-}
-
-static int drvAudioControlHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- int rc = RTCritSectEnter(&pHstStrmOut->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- {
- if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED))
- {
- rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
- if (RT_SUCCESS(rc))
- {
- Assert(!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE));
- pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_ENABLED;
- LogFunc(("[%s] Enabled stream\n", pHstStrmOut->MixBuf.pszName));
- }
- else
- LogFlowFunc(("[%s] Backend reported an error when enabling output stream, rc=%Rrc\n",
- pHstStrmOut->MixBuf.pszName, rc));
- }
- else
- rc = VINF_SUCCESS;
-
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- {
- if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- {
- rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- {
- pHstStrmOut->fStatus = PDMAUDIOSTRMSTS_FLAG_NONE; /* Clear all. */
- AudioMixBufClear(&pHstStrmOut->MixBuf);
-
- LogFunc(("[%s] Disabled stream\n", pHstStrmOut->MixBuf.pszName));
- }
- else
- LogFlowFunc(("[%s] Backend vetoed disabling output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
- }
- else
- rc = VINF_SUCCESS;
-
- break;
- }
-
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED))
- {
- Assert(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
- rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_PAUSE);
- if (RT_SUCCESS(rc))
- {
- pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PAUSED;
- LogFunc(("[%s] Pausing stream\n", pHstStrmOut->MixBuf.pszName));
- }
- else
- LogFlowFunc(("[%s] Backend vetoed pausing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
- }
- else
- rc = VINF_SUCCESS;
-
- break;
- }
-
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PAUSED)
- {
- Assert(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED);
- rc = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_RESUME);
- if (RT_SUCCESS(rc))
- {
- pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PAUSED;
- LogFunc(("[%s] Resumed stream\n", pHstStrmOut->MixBuf.pszName));
- }
- else
- LogFlowFunc(("[%s] Backend vetoed resuming output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
- }
- else
- rc = VINF_SUCCESS;
-
- break;
- }
-
- default:
- AssertMsgFailed(("Command %ld not implemented\n", enmStreamCmd));
- rc = VERR_NOT_IMPLEMENTED;
- break;
- }
-
- int rc2 = RTCritSectLeave(&pHstStrmOut->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- return rc;
-}
-
-int drvAudioDestroyHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- LogFlowFunc(("%s\n", pHstStrmOut->MixBuf.pszName));
-
- int rc;
- if (RTListIsEmpty(&pHstStrmOut->lstGstStrmOut))
- {
- rc = pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
- if (RT_SUCCESS(rc))
- {
- drvAudioHstOutFreeRes(pHstStrmOut);
-
- /* Remove from driver instance list. */
- RTListNodeRemove(&pHstStrmOut->Node);
-
- if (RTCritSectIsInitialized(&pHstStrmOut->CritSect))
- {
- int rc2 = RTCritSectDelete(&pHstStrmOut->CritSect);
- AssertRC(rc2);
- }
-
- RTMemFree(pHstStrmOut);
- pThis->cFreeOutputStreams++;
- return VINF_SUCCESS;
- }
- }
- else
- {
- rc = VERR_ACCESS_DENIED;
- LogFlowFunc(("[%s] Still is being used, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc));
- }
-
- return rc;
-}
-
-int drvAudioDestroyGstOut(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- if (!pGstStrmOut)
- return VINF_SUCCESS;
-
- if (pGstStrmOut->State.cRefs > 1) /* Do other objects still have a reference to it? Bail out. */
- return VERR_WRONG_ORDER;
-
- drvAudioGstOutFreeRes(pGstStrmOut);
-
- if (pGstStrmOut->pHstStrmOut)
- {
- /* Unregister from parent first. */
- RTListNodeRemove(&pGstStrmOut->Node);
-
- /* Try destroying the associated host output stream. This could
- * be skipped if there are other guest output streams with this
- * host stream. */
- drvAudioDestroyHstOut(pThis, pGstStrmOut->pHstStrmOut);
- }
-
- RTMemFree(pGstStrmOut);
-
- return VINF_SUCCESS;
-}
-
-PPDMAUDIOHSTSTRMIN drvAudioFindNextHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- if (pHstStrmIn)
- {
- if (RTListNodeIsLast(&pThis->lstHstStrmIn, &pHstStrmIn->Node))
- return NULL;
-
- return RTListNodeGetNext(&pHstStrmIn->Node, PDMAUDIOHSTSTRMIN, Node);
- }
-
- return RTListGetFirst(&pThis->lstHstStrmIn, PDMAUDIOHSTSTRMIN, Node);
-}
-
-PPDMAUDIOHSTSTRMIN drvAudioFindNextEnabledHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
- if (pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- return pHstStrmIn;
-
- return NULL;
-}
-
-PPDMAUDIOHSTSTRMIN drvAudioFindNextEqHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PPDMAUDIOSTREAMCFG pCfg)
-{
- while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
- if (drvAudioPCMPropsAreEqual(&pHstStrmIn->Props, pCfg))
- return pHstStrmIn;
-
- return NULL;
-}
-
-static int drvAudioHstInAdd(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PDMAUDIORECSOURCE enmRecSource,
- PPDMAUDIOHSTSTRMIN *ppHstStrmIn)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- AssertPtrReturn(ppHstStrmIn, VERR_INVALID_POINTER);
-
- PPDMAUDIOHSTSTRMIN pHstStrmIn;
- int rc = drvAudioAllocHstIn(pThis, pszName, pCfg, enmRecSource, &pHstStrmIn);
- if (RT_SUCCESS(rc))
- *ppHstStrmIn = pHstStrmIn;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-int drvAudioGstOutInit(PPDMAUDIOGSTSTRMOUT pGstStrmOut, PPDMAUDIOHSTSTRMOUT pHostStrmOut,
- const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pGstStrmOut, VERR_INVALID_POINTER);
- AssertPtrReturn(pHostStrmOut, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- int rc = DrvAudioStreamCfgToProps(pCfg, &pGstStrmOut->Props);
- if (RT_SUCCESS(rc))
- {
- char *pszTemp;
- if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
- return VERR_NO_MEMORY;
-
- rc = AudioMixBufInit(&pGstStrmOut->MixBuf, pszTemp, &pGstStrmOut->Props, AudioMixBufSize(&pHostStrmOut->MixBuf));
- if (RT_SUCCESS(rc))
- rc = AudioMixBufLinkTo(&pGstStrmOut->MixBuf, &pHostStrmOut->MixBuf);
-
- RTStrFree(pszTemp);
-
- if (RT_SUCCESS(rc))
- {
- pGstStrmOut->State.cRefs = 1;
- pGstStrmOut->State.fActive = false;
- pGstStrmOut->State.fEmpty = true;
-
- pGstStrmOut->State.pszName = RTStrDup(pszName);
- if (!pGstStrmOut->State.pszName)
- return VERR_NO_MEMORY;
-
- pGstStrmOut->pHstStrmOut = pHostStrmOut;
- }
- }
-
- LogFlowFunc(("pszName=%s, rc=%Rrc\n", pszName, rc));
- return rc;
-}
-
-int drvAudioAllocHstOut(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- if (!pThis->cFreeOutputStreams)
- {
- LogFlowFunc(("Maximum number of host output streams reached\n"));
- return VERR_NO_MORE_HANDLES;
- }
-
- /* Validate backend configuration. */
- if (!pThis->BackendCfg.cbStreamOut)
- {
- LogFlowFunc(("Backend output configuration not valid, bailing out\n"));
- return VERR_INVALID_PARAMETER;
- }
-
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = (PPDMAUDIOHSTSTRMOUT)RTMemAllocZ(pThis->BackendCfg.cbStreamOut);
- if (!pHstStrmOut)
- {
- LogFlowFunc(("Error allocating host output stream with %zu bytes\n",
- pThis->BackendCfg.cbStreamOut));
- return VERR_NO_MEMORY;
- }
-
- int rc;
- bool fInitialized = false;
-
- do
- {
- RTListInit(&pHstStrmOut->lstGstStrmOut);
-
- /* Make the acquired configuration the requested configuration by default. */
- PDMAUDIOSTREAMCFG CfgAcq;
- memcpy(&CfgAcq, pCfg, sizeof(PDMAUDIOSTREAMCFG));
-
- uint32_t cSamples;
- rc = pThis->pHostDrvAudio->pfnInitOut(pThis->pHostDrvAudio, pHstStrmOut,
- pCfg /* pCfgReq */, &CfgAcq /* pCfgAcq */,
- &cSamples);
- if (RT_FAILURE(rc))
- {
- LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
- break;
- }
-
- fInitialized = true;
-
- char *pszTemp;
- if (RTStrAPrintf(&pszTemp, "%s (Host)", pszName) <= 0)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
-#ifdef DEBUG
- LogFunc(("%s: Requested format:\n", pszTemp));
- drvAudioStreamCfgPrint(pCfg);
- LogFunc(("%s: Acquired format:\n", pszTemp));
- drvAudioStreamCfgPrint(&CfgAcq);
-#else
- LogRel2(("Audio: Acquired output format for '%s': %RU32Hz, %s, %RU8 %s\n",
- pszTemp, CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
- CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
-#endif
- rc = DrvAudioStreamCfgToProps(&CfgAcq, &pHstStrmOut->Props);
- if (RT_SUCCESS(rc))
- {
- rc = AudioMixBufInit(&pHstStrmOut->MixBuf, pszTemp, &pHstStrmOut->Props, cSamples);
- if (RT_SUCCESS(rc))
- rc = RTCritSectInit(&pHstStrmOut->CritSect);
-
- if (RT_SUCCESS(rc))
- {
- RTListPrepend(&pThis->lstHstStrmOut, &pHstStrmOut->Node);
- pThis->cFreeOutputStreams--;
- }
- }
-
- RTStrFree(pszTemp);
-
- } while (0);
-
- if (RT_FAILURE(rc))
- {
- if (fInitialized)
- {
- int rc2 = pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
- AssertRC(rc2);
- }
-
- drvAudioHstOutFreeRes(pHstStrmOut);
- RTMemFree(pHstStrmOut);
- }
- else
- *ppHstStrmOut = pHstStrmOut;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-int drvAudioCreateStreamPairOut(PDRVAUDIO pThis, const char *pszName,
- PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- /*
- * Try figuring out which audio stream configuration this backend
- * should use. If fixed output is enabled the backend will be tied
- * to a fixed rate (in Hz, among other parameters), regardless of
- * what the backend could do else.
- */
- PPDMAUDIOSTREAMCFG pBackendCfg;
- if (conf.fixed_out.enabled)
- pBackendCfg = &conf.fixed_out.settings;
- else
- pBackendCfg = pCfg;
-
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
-
- LogFlowFunc(("Using fixed audio output settings: %RTbool\n",
- RT_BOOL(conf.fixed_out.enabled)));
-
- PPDMAUDIOGSTSTRMOUT pGstStrmOut =
- (PPDMAUDIOGSTSTRMOUT)RTMemAllocZ(sizeof(PDMAUDIOGSTSTRMOUT));
- if (!pGstStrmOut)
- {
- LogFlowFunc(("Failed to allocate memory for guest output stream \"%s\"\n", pszName));
- return VERR_NO_MEMORY;
- }
-
- /*
- * The host stream always will get the backend audio stream configuration.
- */
- PPDMAUDIOHSTSTRMOUT pHstStrmOut;
- int rc = drvAudioAddHstOut(pThis, pszName, pBackendCfg, &pHstStrmOut);
- if (RT_FAILURE(rc))
- {
- LogFlowFunc(("Error adding host output stream \"%s\", rc=%Rrc\n", pszName, rc));
-
- RTMemFree(pGstStrmOut);
- return rc;
- }
-
- /*
- * The guest stream always will get the audio stream configuration told
- * by the device emulation (which in turn was/could be set by the guest OS).
- */
- rc = drvAudioGstOutInit(pGstStrmOut, pHstStrmOut, pszName, pCfg);
- if (RT_SUCCESS(rc))
- {
- RTListPrepend(&pHstStrmOut->lstGstStrmOut, &pGstStrmOut->Node);
-
- if (ppGstStrmOut)
- *ppGstStrmOut = pGstStrmOut;
- }
-
- if (RT_FAILURE(rc))
- drvAudioDestroyGstOut(pThis, pGstStrmOut);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static int drvAudioCreateStreamPairIn(PDRVAUDIO pThis, const char *pszName, PDMAUDIORECSOURCE enmRecSource,
- PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
-
- /*
- * Try figuring out which audio stream configuration this backend
- * should use for the audio input data. If fixed input is enabled
- * the backend will be tied to a fixed rate (in Hz, among other parameters),
- * regardless of what the backend initially wanted to use.
- */
- PPDMAUDIOSTREAMCFG pBackendCfg;
- if (conf.fixed_in.enabled)
- pBackendCfg = &conf.fixed_in.settings;
- else
- pBackendCfg = pCfg;
-
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
-
- LogFlowFunc(("Using fixed audio input settings: %RTbool\n",
- RT_BOOL(conf.fixed_in.enabled)));
-
- PPDMAUDIOGSTSTRMIN pGstStrmIn = (PPDMAUDIOGSTSTRMIN)RTMemAllocZ(sizeof(PDMAUDIOGSTSTRMIN));
- if (!pGstStrmIn)
- return VERR_NO_MEMORY;
-
- /*
- * The host stream always will get the backend audio stream configuration.
- */
- PPDMAUDIOHSTSTRMIN pHstStrmIn;
- int rc = drvAudioHstInAdd(pThis, pszName, pBackendCfg, enmRecSource, &pHstStrmIn);
- if (RT_FAILURE(rc))
- {
- LogFunc(("Failed to add host audio input stream \"%s\", rc=%Rrc\n", pszName, rc));
-
- RTMemFree(pGstStrmIn);
- return rc;
- }
-
- /*
- * The guest stream always will get the audio stream configuration told
- * by the device emulation (which in turn was/could be set by the guest OS).
- */
- rc = drvAudioGstInInit(pGstStrmIn, pHstStrmIn, pszName, pCfg);
- if (RT_SUCCESS(rc))
- {
- pHstStrmIn->pGstStrmIn = pGstStrmIn;
-
- if (ppGstStrmIn)
- *ppGstStrmIn = pGstStrmIn;
- }
- else
- drvAudioDestroyGstIn(pThis, pGstStrmIn);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * Initializes a guest input stream.
- *
- * @return IPRT status code.
- * @param pGstStrmIn Pointer to guest stream to initialize.
- * @param pHstStrmIn Pointer to host input stream to associate this guest
- * stream with.
- * @param pszName Pointer to stream name to use for this stream.
- * @param pCfg Pointer to stream configuration to use.
- */
-int drvAudioGstInInit(PPDMAUDIOGSTSTRMIN pGstStrmIn, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- const char *pszName, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pGstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- int rc = DrvAudioStreamCfgToProps(pCfg, &pGstStrmIn->Props);
- if (RT_SUCCESS(rc))
- {
- char *pszTemp;
- if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
- return VERR_NO_MEMORY;
-
- rc = AudioMixBufInit(&pGstStrmIn->MixBuf, pszTemp, &pGstStrmIn->Props, AudioMixBufSize(&pHstStrmIn->MixBuf));
- if (RT_SUCCESS(rc))
- rc = AudioMixBufLinkTo(&pHstStrmIn->MixBuf, &pGstStrmIn->MixBuf);
-
- RTStrFree(pszTemp);
-
- if (RT_SUCCESS(rc))
- {
-#ifdef DEBUG
- drvAudioStreamCfgPrint(pCfg);
-#endif
- pGstStrmIn->State.cRefs = 1;
- pGstStrmIn->State.fActive = false;
- pGstStrmIn->State.fEmpty = true;
-
- pGstStrmIn->State.pszName = RTStrDup(pszName);
- if (!pGstStrmIn->State.pszName)
- return VERR_NO_MEMORY;
-
- pGstStrmIn->pHstStrmIn = pHstStrmIn;
- }
- }
-
- LogFlowFunc(("pszName=%s, rc=%Rrc\n", pszName, rc));
- return rc;
-}
-
-static int drvAudioAllocHstIn(PDRVAUDIO pThis, const char *pszName, PPDMAUDIOSTREAMCFG pCfg,
- PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOHSTSTRMIN *ppHstStrmIn)
-{
- if (!pThis->cFreeInputStreams)
- {
- LogFlowFunc(("No more input streams free to use, bailing out\n"));
- return VERR_NO_MORE_HANDLES;
- }
-
- /* Validate backend configuration. */
- if (!pThis->BackendCfg.cbStreamIn)
- {
- LogFlowFunc(("Backend input configuration not valid, bailing out\n"));
- return VERR_INVALID_PARAMETER;
- }
-
- PPDMAUDIOHSTSTRMIN pHstStrmIn =
- (PPDMAUDIOHSTSTRMIN)RTMemAllocZ(pThis->BackendCfg.cbStreamIn);
- if (!pHstStrmIn)
- {
- LogFlowFunc(("Error allocating host innput stream with %RU32 bytes\n",
- pThis->BackendCfg.cbStreamOut));
- return VERR_NO_MEMORY;
- }
-
- int rc;
- bool fInitialized = false;
-
- do
- {
- /* Make the acquired configuration the requested configuration by default. */
- PDMAUDIOSTREAMCFG CfgAcq;
- memcpy(&CfgAcq, pCfg, sizeof(PDMAUDIOSTREAMCFG));
-
-#ifndef DEBUG
- LogRel2(("Audio: Requested input format: %RU32Hz, %s, %RU8 %s\n",
- CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
- CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
-#endif
- uint32_t cSamples;
- rc = pThis->pHostDrvAudio->pfnInitIn(pThis->pHostDrvAudio, pHstStrmIn,
- pCfg /* pCfgReq */, &CfgAcq /* pCfgAcq */,
- enmRecSource, &cSamples);
- if (RT_FAILURE(rc))
- {
- LogFlowFunc(("Initializing host backend failed with rc=%Rrc\n", rc));
- break;
- }
-
- fInitialized = true;
-
- char *pszTemp;
- if (RTStrAPrintf(&pszTemp, "%s (Host)", pszName) <= 0)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
-#ifdef DEBUG
- LogFunc(("%s: Requested format:\n", pszTemp));
- drvAudioStreamCfgPrint(pCfg);
- LogFunc(("%s: Acquired format:\n", pszTemp));
- drvAudioStreamCfgPrint(&CfgAcq);
-#else
- LogRel2(("Audio: Acquired input format for '%s': %RU32Hz, %s, %RU8 %s\n",
- pszTemp, CfgAcq.uHz, drvAudioHlpFormatToString(CfgAcq.enmFormat),
- CfgAcq.cChannels, CfgAcq.cChannels == 0 ? "Channel" : "Channels"));
-#endif
- rc = DrvAudioStreamCfgToProps(&CfgAcq, &pHstStrmIn->Props);
- if (RT_SUCCESS(rc))
- {
- rc = AudioMixBufInit(&pHstStrmIn->MixBuf, pszTemp, &pHstStrmIn->Props, cSamples);
- if (RT_SUCCESS(rc))
- rc = RTCritSectInit(&pHstStrmIn->CritSect);
-
- if (RT_SUCCESS(rc))
- {
- RTListPrepend(&pThis->lstHstStrmIn, &pHstStrmIn->Node);
- pThis->cFreeInputStreams--;
- }
- }
-
- RTStrFree(pszTemp);
-
- } while (0);
-
- if (RT_FAILURE(rc))
- {
- if (fInitialized)
- {
- int rc2 = pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio,
- pHstStrmIn);
- AssertRC(rc2);
- }
-
- drvAudioHstInFreeRes(pHstStrmIn);
- RTMemFree(pHstStrmIn);
- }
- else
- *ppHstStrmIn = pHstStrmIn;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * Writes VM audio output data from the guest stream into the host stream.
- * The attached host driver backend then will play out the audio in a
- * later step then.
- *
- * @return IPRT status code.
- * @return int
- * @param pThis
- * @param pGstStrmOut
- * @param pvBuf
- * @param cbBuf
- * @param pcbWritten
- */
-static DECLCALLBACK(int) drvAudioWrite(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut,
- const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
-{
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- AssertPtrReturn(pGstStrmOut, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
- /* pcbWritten is optional. */
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
- {
- rc = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc);
-
- return VERR_NOT_AVAILABLE;
- }
-
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- AssertMsg(pGstStrmOut->pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
- ("Writing to disabled host output stream \"%s\" not possible\n",
- pHstStrmOut->MixBuf.pszName));
-
- if (!AudioMixBufFreeBytes(&pGstStrmOut->MixBuf))
- {
- if (pcbWritten)
- *pcbWritten = 0;
-
- return RTCritSectLeave(&pThis->CritSect);
- }
-
- /*
- * First, write data from the device emulation into our
- * guest mixing buffer.
- */
- uint32_t cWritten;
- rc = AudioMixBufWriteAt(&pGstStrmOut->MixBuf, 0 /* Offset in samples */, pvBuf, cbBuf, &cWritten);
-
- /*
- * Second, mix the guest mixing buffer with the host mixing
- * buffer so that the host backend can play the data lateron.
- */
- uint32_t cMixed;
- if ( RT_SUCCESS(rc)
- && cWritten)
- {
- rc = AudioMixBufMixToParent(&pGstStrmOut->MixBuf, cWritten, &cMixed);
- }
- else
- cMixed = 0;
-
- if (RT_SUCCESS(rc))
- {
- /*
- * Return the number of samples which actually have been mixed
- * down to the parent, regardless how much samples were written
- * into the children buffer.
- */
- if (pcbWritten)
- *pcbWritten = AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cMixed);
- }
-
- LogFlowFunc(("%s -> %s: Written pvBuf=%p, cbBuf=%RU32, cWritten=%RU32 (%RU32 bytes), cMixed=%RU32, rc=%Rrc\n",
- pGstStrmOut->MixBuf.pszName, pHstStrmOut->MixBuf.pszName, pvBuf, cbBuf, cWritten,
- AUDIOMIXBUF_S2B(&pGstStrmOut->MixBuf, cWritten), cMixed, rc));
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- return rc;
-}
-
-PPDMAUDIOHSTSTRMOUT drvAudioFindAnyHstOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- if (pHstStrmOut)
- {
- if (RTListNodeIsLast(&pThis->lstHstStrmOut, &pHstStrmOut->Node))
- return NULL;
-
- return RTListNodeGetNext(&pHstStrmOut->Node, PDMAUDIOHSTSTRMOUT, Node);
- }
-
- return RTListGetFirst(&pThis->lstHstStrmOut, PDMAUDIOHSTSTRMOUT, Node);
-}
-
-PPDMAUDIOHSTSTRMOUT drvAudioHstFindAnyEnabledOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHostStrmOut)
-{
- while ((pHostStrmOut = drvAudioFindAnyHstOut(pThis, pHostStrmOut)))
- {
- if (pHostStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- return pHostStrmOut;
- }
-
- return NULL;
-}
-
-PPDMAUDIOHSTSTRMOUT drvAudioFindSpecificOut(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PPDMAUDIOSTREAMCFG pCfg)
-{
- while ((pHstStrmOut = drvAudioFindAnyHstOut(pThis, pHstStrmOut)))
- {
- if (drvAudioPCMPropsAreEqual(&pHstStrmOut->Props, pCfg))
- return pHstStrmOut;
- }
-
- return NULL;
-}
-
-int drvAudioDestroyHstIn(PDRVAUDIO pThis, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- LogFlowFunc(("%s\n", pHstStrmIn->MixBuf.pszName));
-
- int rc;
- if (!pHstStrmIn->pGstStrmIn) /* No parent anymore? */
- {
- rc = pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio, pHstStrmIn);
- if (RT_SUCCESS(rc))
- {
- drvAudioHstInFreeRes(pHstStrmIn);
-
- if (RTCritSectIsInitialized(&pHstStrmIn->CritSect))
- {
- int rc2 = RTCritSectDelete(&pHstStrmIn->CritSect);
- AssertRC(rc2);
- }
-
- /* Remove from driver instance list. */
- RTListNodeRemove(&pHstStrmIn->Node);
-
- RTMemFree(pHstStrmIn);
- pThis->cFreeInputStreams++;
- }
- }
- else
- {
- rc = VERR_ACCESS_DENIED;
- LogFlowFunc(("[%s] Still is being used, rc=%Rrc\n", pHstStrmIn->MixBuf.pszName, rc));
- }
-
- return rc;
-}
-
-static int drvAudioDestroyGstIn(PDRVAUDIO pThis, PPDMAUDIOGSTSTRMIN pGstStrmIn)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- LogFlowFunc(("%s\n", pGstStrmIn->MixBuf.pszName));
-
- if (!pGstStrmIn)
- return VINF_SUCCESS;
-
- if (pGstStrmIn->State.cRefs > 1) /* Do other objects still have a reference to it? Bail out. */
- return VERR_WRONG_ORDER;
-
- drvAudioGstInFreeRes(pGstStrmIn);
-
- if (pGstStrmIn->pHstStrmIn)
- {
- /* Unlink child. */
- pGstStrmIn->pHstStrmIn->pGstStrmIn = NULL;
-
- /* Try destroying the associated host input stream. This could
- * be skipped if there are other guest input streams with this
- * host stream. */
- drvAudioDestroyHstIn(pThis, pGstStrmIn->pHstStrmIn);
- }
-
- RTMemFree(pGstStrmIn);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioQueryStatus(PPDMIAUDIOCONNECTOR pInterface,
- uint32_t *pcbAvailIn, uint32_t *pcbFreeOut,
- uint32_t *pcSamplesLive)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- /* pcbAvailIn is optional. */
- /* pcbFreeOut is optional. */
- /* pcSamplesLive is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- /*
- * Playback.
- */
- uint32_t cSamplesLive = 0;
- uint32_t cbFreeOut = UINT32_MAX;
-
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
- while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
- {
- cSamplesLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
-
- /* Has this stream marked as disabled but there still were guest streams relying
- * on it? Check if this stream now can be closed and do so, if possible. */
- if ( (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
- && !cSamplesLive)
- {
- /* Stop playing the current (pending) stream. */
- int rc2 = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc2))
- {
- pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
-
- LogFunc(("[%s] Disabling stream\n", pHstStrmOut->MixBuf.pszName));
- }
- else
- LogFunc(("[%s] Backend vetoed against closing output stream, rc=%Rrc\n", pHstStrmOut->MixBuf.pszName, rc2));
-
- continue;
- }
-
- LogFlowFunc(("[%s] cSamplesLive=%RU32\n", pHstStrmOut->MixBuf.pszName, cSamplesLive));
-
- /*
- * No live samples to play at the moment?
- *
- * Tell the device emulation for each connected guest stream how many
- * bytes are free so that the device emulation can continue writing data to
- * these streams.
- */
- PPDMAUDIOGSTSTRMOUT pGstStrmOut;
- uint32_t cbFree2 = UINT32_MAX;
- RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
- {
- if (pGstStrmOut->State.fActive)
- {
- /* Tell the sound device emulation how many samples are free
- * so that it can start writing PCM data to us. */
- cbFree2 = RT_MIN(cbFree2, AUDIOMIXBUF_S2B_RATIO(&pGstStrmOut->MixBuf,
- AudioMixBufFree(&pGstStrmOut->MixBuf)));
-#ifdef DEBUG_andy
- LogFlowFunc(("\t[%s] cbFreeOut=%RU32\n", pGstStrmOut->MixBuf.pszName, cbFree2));
-#endif
- }
- }
-
- cbFreeOut = RT_MIN(cbFreeOut, cbFree2);
- }
-
- /*
- * Recording.
- */
- uint32_t cbAvailIn = 0;
-
- PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
- while ((pHstStrmIn = drvAudioFindNextEnabledHstIn(pThis, pHstStrmIn)))
- {
- /* Call the host backend to capture the audio input data. */
- uint32_t cSamplesCaptured;
- int rc2 = pThis->pHostDrvAudio->pfnCaptureIn(pThis->pHostDrvAudio, pHstStrmIn,
- &cSamplesCaptured);
- if (RT_FAILURE(rc2))
- continue;
-
- PPDMAUDIOGSTSTRMIN pGstStrmIn = pHstStrmIn->pGstStrmIn;
- AssertPtrBreak(pGstStrmIn);
-
- if (pGstStrmIn->State.fActive)
- {
- cbAvailIn = RT_MAX(cbAvailIn, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf,
- AudioMixBufMixed(&pHstStrmIn->MixBuf)));
-#ifdef DEBUG_andy
- LogFlowFunc(("\t[%s] cbAvailIn=%RU32\n", pHstStrmIn->MixBuf.pszName, cbAvailIn));
-#endif
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- if (cbFreeOut == UINT32_MAX)
- cbFreeOut = 0;
-
- if (pcbAvailIn)
- *pcbAvailIn = cbAvailIn;
-
- if (pcbFreeOut)
- *pcbFreeOut = cbFreeOut;
-
- if (pcSamplesLive)
- *pcSamplesLive = cSamplesLive;
- }
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- if (RT_FAILURE(rc))
- LogFlowFuncLeaveRC(rc);
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioPlayOut(PPDMIAUDIOCONNECTOR pInterface, uint32_t *pcSamplesPlayed)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- /* pcSamplesPlayed is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- /* Backend output (temporarily) disabled / unavailable? */
- if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_OUT))
- {
- rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
- AssertRC(rc);
-
- if (!pThis->BackendCfg.cMaxHstStrmsOut)
- {
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- return VERR_NOT_AVAILABLE;
- }
- }
-
- /*
- * Process all enabled host output streams.
- */
- uint32_t cSamplesPlayedMax = 0;
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
- while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
- {
-#if 0
- uint32_t cStreamsLive;
- uint32_t cSamplesLive = drvAudioHstOutSamplesLive(pHstStrmOut, &cStreamsLive);
- if (!cStreamsLive)
- cSamplesLive = 0;
-
- /* Has this stream marked as disabled but there still were guest streams relying
- * on it? Check if this stream now can be closed and do so, if possible. */
- if ( pHstStrmOut->fPendingDisable
- && !cStreamsLive)
- {
- /* Stop playing the current (pending) stream. */
- int rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut,
- PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc2))
- {
- pHstStrmOut->fEnabled = false;
- pHstStrmOut->fPendingDisable = false;
-
- LogFunc(("\t%p: Disabling stream\n", pHstStrmOut));
- }
- else
- LogFunc(("\t%p: Backend vetoed against closing output stream, rc=%Rrc\n",
- pHstStrmOut, rc2));
-
- continue;
- }
-#endif
-
- uint32_t cSamplesPlayed = 0;
- int rc2 = pThis->pHostDrvAudio->pfnPlayOut(pThis->pHostDrvAudio, pHstStrmOut, &cSamplesPlayed);
- if (RT_FAILURE(rc2))
- {
- rc2 = pThis->pHostDrvAudio->pfnControlOut(pThis->pHostDrvAudio, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
- AssertRC(rc2);
- }
- else
- cSamplesPlayedMax = RT_MAX(cSamplesPlayed, cSamplesPlayedMax);
-
- LogFlowFunc(("\t[%s] cSamplesPlayed=%RU32, cSamplesPlayedMax=%RU32, rc=%Rrc\n",
- pHstStrmOut->MixBuf.pszName, cSamplesPlayed, cSamplesPlayedMax, rc2));
-
- bool fNeedsCleanup = false;
-
- PPDMAUDIOGSTSTRMOUT pGstStrmOut;
- RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
- {
- if ( !pGstStrmOut->State.fActive
- && pGstStrmOut->State.fEmpty)
- continue;
-
- if (AudioMixBufIsEmpty(&pGstStrmOut->MixBuf))
- {
- pGstStrmOut->State.fEmpty = true;
- fNeedsCleanup |= !pGstStrmOut->State.fActive;
- }
- }
-
- if (fNeedsCleanup)
- {
- RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
- {
- if (!pGstStrmOut->State.fActive)
- drvAudioDestroyGstOut(pThis, pGstStrmOut);
- }
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- if (pcSamplesPlayed)
- *pcSamplesPlayed = cSamplesPlayedMax;
- }
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- if (RT_FAILURE(rc))
- LogFlowFuncLeaveRC(rc);
-
- return rc;
-}
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
-static PPDMAUDIOCALLBACK drvAudioCallbackDuplicate(PPDMAUDIOCALLBACK pCB)
-{
- PPDMAUDIOCALLBACK pCBCopy = (PPDMAUDIOCALLBACK)RTMemDup((void *)pCB, sizeof(PDMAUDIOCALLBACK));
- if (!pCBCopy)
- return NULL;
-
- if (pCB->pvCtx)
- {
- pCBCopy->pvCtx = RTMemDup(pCB->pvCtx, pCB->cbCtx);
- if (!pCBCopy->pvCtx)
- {
- RTMemFree(pCBCopy);
- return NULL;
- }
-
- pCBCopy->cbCtx = pCB->cbCtx;
- }
-
- return pCBCopy;
-}
-
-static void drvAudioCallbackDestroy(PPDMAUDIOCALLBACK pCB)
-{
- if (!pCB)
- return;
-
- RTListNodeRemove(&pCB->Node);
- if (pCB->pvCtx)
- {
- Assert(pCB->cbCtx);
- RTMemFree(pCB->pvCtx);
- }
- RTMemFree(pCB);
-}
-
-static DECLCALLBACK(int) drvAudioRegisterCallbacks(PPDMIAUDIOCONNECTOR pInterface,
- PPDMAUDIOCALLBACK paCallbacks, size_t cCallbacks)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(paCallbacks, VERR_INVALID_POINTER);
- AssertReturn(cCallbacks, VERR_INVALID_PARAMETER);
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- for (size_t i = 0; i < cCallbacks; i++)
- {
- PPDMAUDIOCALLBACK pCB = drvAudioCallbackDuplicate(&paCallbacks[i]);
- if (!pCB)
- {
- rc = VERR_NO_MEMORY;
- break;
- }
-
- switch (pCB->enmType)
- {
- case PDMAUDIOCALLBACKTYPE_INPUT:
- RTListAppend(&pThis->lstCBIn, &pCB->Node);
- break;
-
- case PDMAUDIOCALLBACKTYPE_OUTPUT:
- RTListAppend(&pThis->lstCBOut, &pCB->Node);
- break;
-
- default:
- AssertMsgFailed(("Not supported\n"));
- break;
- }
- }
-
- /** @todo Undo allocations on error. */
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioCallback(PPDMIAUDIOCONNECTOR pInterface, PDMAUDIOCALLBACKTYPE enmType,
- void *pvUser, size_t cbUser)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
- AssertReturn(cbUser, VERR_INVALID_PARAMETER);
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
- PRTLISTANCHOR pListAnchor = NULL;
-
- switch (enmType)
- {
- case PDMAUDIOCALLBACKTYPE_INPUT:
- pListAnchor = &pThis->lstCBIn;
- break;
-
- case PDMAUDIOCALLBACKTYPE_OUTPUT:
- pListAnchor = &pThis->lstCBOut;
- break;
-
- default:
- AssertMsgFailed(("Not supported\n"));
- break;
- }
-
- if (pListAnchor)
- {
- PPDMAUDIOCALLBACK pCB;
- RTListForEach(pListAnchor, pCB, PDMAUDIOCALLBACK, Node)
- {
- Assert(pCB->enmType == enmType);
- pCB->pfnCallback(enmType, pCB->pvCtx, pCB->cbCtx, pvUser, cbUser);
- }
- }
-
- return VINF_SUCCESS;
-}
-#endif
-
-/**
- * Initializes the host backend and queries its initial configuration.
- * If the host backend fails, VERR_AUDIO_BACKEND_INIT_FAILED will be returned.
- *
- * Note: As this routine is called when attaching to the device LUN in the
- * device emulation, we either check for success or VERR_AUDIO_BACKEND_INIT_FAILED.
- * Everything else is considered as fatal and must be handled separately in
- * the device emulation!
- *
- * @return IPRT status code.
- * @param pThis Driver instance to be called.
- * @param pCfgHandle CFGM configuration handle to use for this driver.
- */
-static int drvAudioHostInit(PCFGMNODE pCfgHandle, PDRVAUDIO pThis)
-{
- /* pCfgHandle is optional. */
- RT_NOREF(pCfgHandle);
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
-
- AssertPtr(pThis->pHostDrvAudio);
- int rc = pThis->pHostDrvAudio->pfnInit(pThis->pHostDrvAudio);
- if (RT_FAILURE(rc))
- {
- LogFlowFunc(("Initialization of lower driver failed with rc=%Rrc\n", rc));
- return VERR_AUDIO_BACKEND_INIT_FAILED;
- }
-
- /* Get the configuration data from backend. */
- rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, &pThis->BackendCfg);
- if (RT_FAILURE(rc))
- {
- LogFlowFunc(("Getting backend configuration failed with rc=%Rrc\n", rc));
- return VERR_AUDIO_BACKEND_INIT_FAILED;
- }
-
- uint32_t cMaxHstStrmsOut = pThis->BackendCfg.cMaxHstStrmsOut;
- size_t cbHstStrmsOut = pThis->BackendCfg.cbStreamOut;
-
- if (cbHstStrmsOut)
- {
- pThis->cFreeOutputStreams = cMaxHstStrmsOut;
- }
- else
- pThis->cFreeOutputStreams = 0;
-
- uint32_t cMaxHstStrmsIn = pThis->BackendCfg.cMaxHstStrmsIn;
- size_t cbHstStrmIn = pThis->BackendCfg.cbStreamIn;
-
- if (cbHstStrmIn)
- {
- /*
- * Note:
- * - Our AC'97 emulation has two inputs, line (ac97.pi) and microphone (ac97.mc).
- * - Our HDA emulation currently has only line input (hda.pi).
- */
- pThis->cFreeInputStreams = cMaxHstStrmsIn;
- }
- else
- pThis->cFreeInputStreams = 0;
-
- LogFlowFunc(("cMaxHstStrmsOut=%RU32 (cb=%zu), cMaxHstStrmsIn=%RU32 (cb=%zu)\n",
- cMaxHstStrmsOut, cbHstStrmsOut, cMaxHstStrmsIn, cbHstStrmIn));
-
- LogFlowFunc(("cFreeInputStreams=%RU8, cFreeOutputStreams=%RU8\n",
- pThis->cFreeInputStreams, pThis->cFreeOutputStreams));
-
- LogRel(("Audio: Host audio backend supports %RU32 output streams and %RU32 input streams at once\n",
- /* Clamp for logging. Unlimited streams are defined by UINT32_MAX. */
- RT_MIN(64, cMaxHstStrmsOut), RT_MIN(64, cMaxHstStrmsIn)));
-
- LogFlowFuncLeave();
- return VINF_SUCCESS;
-}
-
-static void drvAudioStateHandler(PPDMDRVINS pDrvIns, PDMAUDIOSTREAMCMD enmCmd)
-{
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
- PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
-
- LogFlowFunc(("enmCmd=%RU32\n", enmCmd));
-
- if (!pThis->pHostDrvAudio)
- return;
-
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
- while ((pHstStrmOut = drvAudioHstFindAnyEnabledOut(pThis, pHstStrmOut)))
- drvAudioControlHstOut(pThis, pHstStrmOut, enmCmd);
-
- PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
- while ((pHstStrmIn = drvAudioFindNextEnabledHstIn(pThis, pHstStrmIn)))
- drvAudioControlHstIn(pThis, pHstStrmIn, enmCmd);
-}
-
-static struct audio_option audio_options[] =
-{
- /* DAC */
- {"DACFixedSettings", AUD_OPT_BOOL, &conf.fixed_out.enabled,
- "Use fixed settings for host DAC", NULL, 0},
-
- {"DACFixedFreq", AUD_OPT_INT, &conf.fixed_out.settings.uHz,
- "Frequency for fixed host DAC", NULL, 0},
-
- {"DACFixedFmt", AUD_OPT_FMT, &conf.fixed_out.settings.enmFormat,
- "Format for fixed host DAC", NULL, 0},
-
- {"DACFixedChannels", AUD_OPT_INT, &conf.fixed_out.settings.cChannels,
- "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
-
- {"DACVoices", AUD_OPT_INT, &conf.fixed_out.cStreams, /** @todo Rename! */
- "Number of streams for DAC", NULL, 0},
-
- /* ADC */
- {"ADCFixedSettings", AUD_OPT_BOOL, &conf.fixed_in.enabled,
- "Use fixed settings for host ADC", NULL, 0},
-
- {"ADCFixedFreq", AUD_OPT_INT, &conf.fixed_in.settings.uHz,
- "Frequency for fixed host ADC", NULL, 0},
-
- {"ADCFixedFmt", AUD_OPT_FMT, &conf.fixed_in.settings.enmFormat,
- "Format for fixed host ADC", NULL, 0},
-
- {"ADCFixedChannels", AUD_OPT_INT, &conf.fixed_in.settings.cChannels,
- "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
-
- {"ADCVoices", AUD_OPT_INT, &conf.fixed_in.cStreams, /** @todo Rename! */
- "Number of streams for ADC", NULL, 0},
-
- /* Misc */
- {"TimerFreq", AUD_OPT_INT, &conf.period.hz,
- "Timer frequency in Hz (0 - use lowest possible)", NULL, 0},
-
- {"PLIVE", AUD_OPT_BOOL, &conf.plive,
- "(undocumented)", NULL, 0}, /** @todo What is this? */
-
- {NULL, AUD_OPT_INT, NULL, NULL, NULL, 0}
-};
-
-static DECLCALLBACK(int) drvAudioInit(PCFGMNODE pCfgHandle, PPDMDRVINS pDrvIns)
-{
- AssertPtrReturn(pCfgHandle, VERR_INVALID_POINTER);
- AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
-
- LogRel(("Audio: Using VBox 5.0.x audio code!\n"));
-
- PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
- LogFlowFunc(("pDrvAudio=%p, pDrvIns=%p\n", pThis, pDrvIns));
-
- RTListInit(&pThis->lstHstStrmIn);
- RTListInit(&pThis->lstHstStrmOut);
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- RTListInit(&pThis->lstCBIn);
- RTListInit(&pThis->lstCBOut);
-#endif
-
- int rc = RTCritSectInit(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- {
- rc = drvAudioProcessOptions(pCfgHandle, "AUDIO", audio_options);
- /** @todo Check for invalid options? */
-
- pThis->cFreeOutputStreams = conf.fixed_out.cStreams;
- pThis->cFreeInputStreams = conf.fixed_in.cStreams;
-
- if (!pThis->cFreeOutputStreams)
- pThis->cFreeOutputStreams = 1;
-
- if (!pThis->cFreeInputStreams)
- pThis->cFreeInputStreams = 1;
- }
-
- /*
- * If everything went well, initialize the lower driver.
- */
- if (RT_SUCCESS(rc))
- rc = drvAudioHostInit(pCfgHandle, pThis);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioRead(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn,
- void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
-{
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- AssertPtrReturn(pGstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
- AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
- /* pcbWritten is optional. */
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- if (!pThis->pHostDrvAudio->pfnIsEnabled(pThis->pHostDrvAudio, PDMAUDIODIR_IN))
- {
- if (pcbRead)
- *pcbRead = 0;
-
- return RTCritSectLeave(&pThis->CritSect);
- }
-
- PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- AssertMsg(pGstStrmIn->pHstStrmIn->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED,
- ("Reading from disabled host input stream \"%s\" not possible\n", pGstStrmIn->MixBuf.pszName));
-
- /*
- * Read from the parent buffer (that is, the guest buffer) which
- * should have the audio data in the format the guest needs.
- */
- uint32_t cRead;
- rc = AudioMixBufReadCirc(&pGstStrmIn->MixBuf, pvBuf, cbBuf, &cRead);
- if (RT_SUCCESS(rc))
- {
- AudioMixBufFinish(&pGstStrmIn->MixBuf, cRead);
-
- if (pcbRead)
- *pcbRead = AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead);
- }
-
- LogFlowFunc(("cRead=%RU32 (%RU32 bytes), rc=%Rrc\n",
- cRead, AUDIOMIXBUF_S2B(&pGstStrmIn->MixBuf, cRead), rc));
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioEnableOut(PPDMIAUDIOCONNECTOR pInterface,
- PPDMAUDIOGSTSTRMOUT pGstStrmOut, bool fEnable)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- /* pGstStrmOut is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc = VINF_SUCCESS;
-
- if (pGstStrmOut)
- {
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
- AssertPtr(pHstStrmOut);
-
- if (fEnable)
- {
- /* Is a pending disable outstanding? Then disable first. */
- if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE)
- {
- rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- pHstStrmOut->fStatus &= ~PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
- }
-
- if (RT_SUCCESS(rc))
- rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
- }
- else /* Disable */
- {
- if (pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_ENABLED)
- {
- uint32_t cGstStrmsActive = 0;
-
- /*
- * Check if there are any active guest streams assigned
- * to this host stream which still are being marked as active.
- *
- * In that case we have to defer closing the host stream and
- * wait until all guest streams have been finished.
- */
- PPDMAUDIOGSTSTRMOUT pIter;
- RTListForEach(&pHstStrmOut->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
- {
- if (pIter->State.fActive)
- {
- cGstStrmsActive++;
- break; /* At least one assigned & active guest stream is enough. */
- }
- }
-
- /* Do we need to defer closing the host stream? */
- if (cGstStrmsActive >= 1)
- pHstStrmOut->fStatus |= PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE;
-
- /* Can we close the host stream now instead of deferring it? */
- if (!(pHstStrmOut->fStatus & PDMAUDIOSTRMSTS_FLAG_PENDING_DISABLE))
- rc = drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
- }
- }
-
- if (RT_SUCCESS(rc))
- pGstStrmOut->State.fActive = fEnable;
-
- LogFlowFunc(("%s: fEnable=%RTbool, fStatus=0x%x, rc=%Rrc\n",
- pGstStrmOut->MixBuf.pszName, fEnable, pHstStrmOut->fStatus, rc));
- }
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioEnableIn(PPDMIAUDIOCONNECTOR pInterface,
- PPDMAUDIOGSTSTRMIN pGstStrmIn, bool fEnable)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- /* pGstStrmIn is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc = VINF_SUCCESS;
-
- if (pGstStrmIn)
- {
- PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
- AssertPtr(pHstStrmIn);
-
- LogFlowFunc(("%s: fEnable=%RTbool\n", pGstStrmIn->MixBuf.pszName, fEnable));
-
- rc = drvAudioControlHstIn(pThis, pHstStrmIn,
- fEnable ? PDMAUDIOSTREAMCMD_ENABLE : PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- pGstStrmIn->State.fActive = fEnable;
-
- LogFlowFunc(("%s: fEnable=%RTbool, rc=%Rrc\n", pGstStrmIn->MixBuf.pszName, fEnable, rc));
- }
-
- return rc;
-}
-
-static DECLCALLBACK(bool) drvAudioIsValidIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn)
-{
- RT_NOREF(pInterface);
- return (pGstStrmIn != NULL);
-}
-
-static DECLCALLBACK(bool) drvAudioIsValidOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
-{
- RT_NOREF(pInterface);
- return (pGstStrmOut != NULL);
-}
-
-static DECLCALLBACK(int) drvAudioCreateIn(PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
- PDMAUDIORECSOURCE enmRecSource, PPDMAUDIOSTREAMCFG pCfg,
- PPDMAUDIOGSTSTRMIN *ppGstStrmIn)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(ppGstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- AssertPtrReturn(ppGstStrmIn, VERR_INVALID_POINTER);
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- LogFlowFunc(("pszName=%s, pCfg=%p\n", pszName, pCfg));
-
- if (!drvAudioStreamCfgIsValid(pCfg))
- {
- LogFunc(("Input stream configuration is not valid, bailing out\n"));
- rc = VERR_INVALID_PARAMETER;
- }
-
- PPDMAUDIOGSTSTRMIN pGstStrmIn = *ppGstStrmIn;
- if ( RT_SUCCESS(rc)
- && pGstStrmIn
- && drvAudioPCMPropsAreEqual(&pGstStrmIn->Props, pCfg))
- {
- LogFunc(("[%s] Exists and matches required configuration, skipping creation\n",
- pGstStrmIn->MixBuf.pszName));
- rc = VWRN_ALREADY_EXISTS;
- }
-
- if (rc != VINF_SUCCESS) /* Note: Can be VWRN_ALREADY_EXISTS, so don't use VINF_SUCCESS here. */
- {
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- return rc;
- }
-
- if ( !conf.fixed_in.enabled
- && pGstStrmIn)
- {
- drvAudioDestroyGstIn(pThis, pGstStrmIn);
- pGstStrmIn = NULL;
- }
-
- if (pGstStrmIn)
- {
- PPDMAUDIOHSTSTRMIN pHstStrmIn = pGstStrmIn->pHstStrmIn;
- AssertPtr(pHstStrmIn);
-
- drvAudioGstInFreeRes(pGstStrmIn);
-
- char *pszTemp;
- if (RTStrAPrintf(&pszTemp, "%s (Guest)", pszName) <= 0)
- {
- RTMemFree(pGstStrmIn);
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- return VERR_NO_MEMORY;
- }
-
- rc = drvAudioGstInInit(pGstStrmIn, pHstStrmIn, pszName, pCfg);
-
- RTStrFree(pszTemp);
- }
- else
- rc = drvAudioCreateStreamPairIn(pThis, pszName, enmRecSource, pCfg, &pGstStrmIn);
-
- if (RT_SUCCESS(rc))
- {
- if (pGstStrmIn)
- *ppGstStrmIn = pGstStrmIn;
- }
- else
- {
- switch (rc)
- {
- case VERR_NO_MORE_HANDLES: /** @todo Find a better rc. */
- LogRel(("Audio: Skipping to create input stream \"%s\", " \
- "as the host audio backend reached its maximum of concurrent audio input streams\n", pszName));
- break;
-
- default:
- break;
- }
- }
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioCreateOut(PPDMIAUDIOCONNECTOR pInterface, const char *pszName,
- PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- AssertPtrReturn(ppGstStrmOut, VERR_INVALID_POINTER);
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- LogFlowFunc(("pszName=%s, pCfg=%p\n", pszName, pCfg));
-
- if (!drvAudioStreamCfgIsValid(pCfg))
- {
- LogFunc(("Output stream configuration is not valid, bailing out\n"));
- rc = VERR_INVALID_PARAMETER;
- }
-
- PPDMAUDIOGSTSTRMOUT pGstStrmOut = *ppGstStrmOut;
- if ( RT_SUCCESS(rc)
- && pGstStrmOut
- && drvAudioPCMPropsAreEqual(&pGstStrmOut->Props, pCfg))
- {
- LogFunc(("[%s] Exists and matches required configuration, skipping creation\n",
- pGstStrmOut->MixBuf.pszName));
-
- rc = VWRN_ALREADY_EXISTS;
- }
-
- if (rc != VINF_SUCCESS) /* Note: Can be VWRN_ALREADY_EXISTS, so don't use VINF_SUCCESS here. */
- {
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- return rc;
- }
-
-#if 0
- /* Any live samples that need to be updated after
- * we set the new parameters? */
- PPDMAUDIOGSTSTRMOUT pOldGstStrmOut = NULL;
- uint32_t cLiveSamples = 0;
-
- if ( conf.plive
- && pGstStrmOut
- && ( !pGstStrmOut->State.fActive
- && !pGstStrmOut->State.fEmpty))
- {
- cLiveSamples = pGstStrmOut->cTotalSamplesWritten;
- if (cLiveSamples)
- {
- pOldGstStrmOut = pGstStrmOut;
- pGstStrmOut = NULL;
- }
- }
-#endif
-
- if ( pGstStrmOut
- && !conf.fixed_out.enabled)
- {
- drvAudioDestroyGstOut(pThis, pGstStrmOut);
- pGstStrmOut = NULL;
- }
-
- if (pGstStrmOut)
- {
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = pGstStrmOut->pHstStrmOut;
- AssertPtr(pHstStrmOut);
-
- drvAudioGstOutFreeRes(pGstStrmOut);
-
- rc = drvAudioGstOutInit(pGstStrmOut, pHstStrmOut, pszName, pCfg);
- }
- else
- {
- rc = drvAudioCreateStreamPairOut(pThis, pszName, pCfg, &pGstStrmOut);
- if (RT_FAILURE(rc))
- LogFunc(("Failed to create output stream \"%s\", rc=%Rrc\n", pszName, rc));
- }
-
- if (RT_SUCCESS(rc))
- {
- if (pGstStrmOut)
- *ppGstStrmOut = pGstStrmOut;
-#if 0
- /* Update remaining live samples with new rate. */
- if (cLiveSamples)
- {
- AssertPtr(pOldGstStrmOut);
-
- uint32_t cSamplesMixed =
- (cLiveSamples << pOldGstStrmOut->Props.cShift)
- * pOldGstStrmOut->Props.cbPerSec
- / (*ppGstStrmOut)->Props.cbPerSec;
-
- pGstStrmOut->cTotalSamplesWritten += cSamplesMixed;
- }
-#endif
- }
- else
- {
- switch (rc)
- {
- case VERR_NO_MORE_HANDLES: /** @todo Find a better rc. */
- LogRel(("Audio: Skipping to create output stream \"%s\", " \
- "as the host audio backend reached its maximum of concurrent audio output streams\n", pszName));
- break;
-
- default:
- break;
- }
- }
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioGetConfiguration(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc = RTCritSectEnter(&pThis->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- rc = pThis->pHostDrvAudio->pfnGetConf(pThis->pHostDrvAudio, pCfg);
-
- int rc2 = RTCritSectLeave(&pThis->CritSect);
- if (RT_SUCCESS(rc))
- rc = rc2;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(bool) drvAudioIsActiveIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn)
-{
- AssertPtrReturn(pInterface, false);
- /* pGstStrmIn is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc2 = RTCritSectEnter(&pThis->CritSect);
- AssertRC(rc2);
-
- bool fRet = pGstStrmIn ? pGstStrmIn->State.fActive : false;
-
- rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- return fRet;
-}
-
-static DECLCALLBACK(bool) drvAudioIsActiveOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
-{
- AssertPtrReturn(pInterface, false);
- /* pGstStrmOut is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc2 = RTCritSectEnter(&pThis->CritSect);
- AssertRC(rc2);
-
- bool fRet = pGstStrmOut ? pGstStrmOut->State.fActive : false;
-
- rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-
- return fRet;
-}
-
-static DECLCALLBACK(void) drvAudioDestroyIn(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMIN pGstStrmIn)
-{
- AssertPtrReturnVoid(pInterface);
- /* pGstStrmIn is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc2 = RTCritSectEnter(&pThis->CritSect);
- AssertRC(rc2);
-
- if (pGstStrmIn)
- drvAudioDestroyGstIn(pThis, pGstStrmIn);
-
- rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-}
-
-static DECLCALLBACK(void) drvAudioDestroyOut(PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOGSTSTRMOUT pGstStrmOut)
-{
- AssertPtrReturnVoid(pInterface);
- /* pGstStrmOut is optional. */
-
- PDRVAUDIO pThis = PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface);
-
- int rc2 = RTCritSectEnter(&pThis->CritSect);
- AssertRC(rc2);
-
- if (pGstStrmOut)
- drvAudioDestroyGstOut(pThis, pGstStrmOut);
-
- rc2 = RTCritSectLeave(&pThis->CritSect);
- AssertRC(rc2);
-}
-
-/********************************************************************/
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- LogFlowFunc(("pInterface=%p, pszIID=%s\n", pInterface, pszIID));
-
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIAUDIOCONNECTOR, &pThis->IAudioConnector);
-
- return NULL;
-}
-
-/**
- * Power Off notification.
- *
- * @param pDrvIns The driver instance data.
- */
-static DECLCALLBACK(void) drvAudioPowerOff(PPDMDRVINS pDrvIns)
-{
- LogFlowFuncEnter();
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
-
- PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
-
- if (!pThis->pHostDrvAudio)
- return;
-
- /* Tear down all host output streams. */
- PPDMAUDIOHSTSTRMOUT pHstStrmOut = NULL;
- while ((pHstStrmOut = drvAudioFindAnyHstOut(pThis, pHstStrmOut)))
- {
- drvAudioControlHstOut(pThis, pHstStrmOut, PDMAUDIOSTREAMCMD_DISABLE);
- pThis->pHostDrvAudio->pfnFiniOut(pThis->pHostDrvAudio, pHstStrmOut);
- }
-
- /* Tear down all host input streams. */
- PPDMAUDIOHSTSTRMIN pHstStrmIn = NULL;
- while ((pHstStrmIn = drvAudioFindNextHstIn(pThis, pHstStrmIn)))
- {
- drvAudioControlHstIn(pThis, pHstStrmIn, PDMAUDIOSTREAMCMD_DISABLE);
- pThis->pHostDrvAudio->pfnFiniIn(pThis->pHostDrvAudio, pHstStrmIn);
- }
-
- if (pThis->pHostDrvAudio->pfnShutdown)
- pThis->pHostDrvAudio->pfnShutdown(pThis->pHostDrvAudio);
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- PPDMAUDIOCALLBACK pCB, pCBNext;
- RTListForEachSafe(&pThis->lstCBIn, pCB, pCBNext, PDMAUDIOCALLBACK, Node)
- drvAudioCallbackDestroy(pCB);
-
- RTListForEachSafe(&pThis->lstCBOut, pCB, pCBNext, PDMAUDIOCALLBACK, Node)
- drvAudioCallbackDestroy(pCB);
-#endif
-
- LogFlowFuncLeave();
-}
-
-/**
- * Constructs an audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
-{
- LogFlowFunc(("pDrvIns=%#p, pCfgHandle=%#p, fFlags=%x\n", pDrvIns, pCfgHandle, fFlags));
-
- PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
-
- /*
- * Init the static parts.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase. */
- pDrvIns->IBase.pfnQueryInterface = drvAudioQueryInterface;
- /* IAudioConnector. */
- pThis->IAudioConnector.pfnQueryStatus = drvAudioQueryStatus;
- pThis->IAudioConnector.pfnRead = drvAudioRead;
- pThis->IAudioConnector.pfnWrite = drvAudioWrite;
- pThis->IAudioConnector.pfnGetConfiguration = drvAudioGetConfiguration;
- pThis->IAudioConnector.pfnIsActiveIn = drvAudioIsActiveIn;
- pThis->IAudioConnector.pfnIsActiveOut = drvAudioIsActiveOut;
- pThis->IAudioConnector.pfnIsValidIn = drvAudioIsValidIn;
- pThis->IAudioConnector.pfnIsValidOut = drvAudioIsValidOut;
- pThis->IAudioConnector.pfnEnableOut = drvAudioEnableOut;
- pThis->IAudioConnector.pfnEnableIn = drvAudioEnableIn;
- pThis->IAudioConnector.pfnDestroyIn = drvAudioDestroyIn;
- pThis->IAudioConnector.pfnDestroyOut = drvAudioDestroyOut;
- pThis->IAudioConnector.pfnCreateIn = drvAudioCreateIn;
- pThis->IAudioConnector.pfnCreateOut = drvAudioCreateOut;
- pThis->IAudioConnector.pfnPlayOut = drvAudioPlayOut;
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- pThis->IAudioConnector.pfnRegisterCallbacks = drvAudioRegisterCallbacks;
- pThis->IAudioConnector.pfnCallback = drvAudioCallback;
-#endif
-
- /*
- * Attach driver below and query its connector interface.
- */
- PPDMIBASE pDownBase;
- int rc = PDMDrvHlpAttach(pDrvIns, fFlags, &pDownBase);
- if (RT_FAILURE(rc))
- {
- LogRel(("Audio: Failed to attach to driver %p below (flags=0x%x), rc=%Rrc\n",
- pDrvIns, fFlags, rc));
- return rc;
- }
-
- pThis->pHostDrvAudio = PDMIBASE_QUERY_INTERFACE(pDownBase, PDMIHOSTAUDIO);
- if (!pThis->pHostDrvAudio)
- {
- LogRel(("Audio: Failed to query interface for underlying host driver\n"));
- return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_BELOW,
- N_("Host audio backend missing or invalid"));
- }
-
-#ifdef DEBUG_andy
- CFGMR3Dump(pCfgHandle);
-#endif
-
- rc = drvAudioInit(pCfgHandle, pDrvIns);
- if (RT_SUCCESS(rc))
- {
- pThis->fTerminate = false;
- pThis->pDrvIns = pDrvIns;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * Destructs an audio driver instance.
- *
- * @copydoc FNPDMDRVDESTRUCT
- */
-static DECLCALLBACK(void) drvAudioDestruct(PPDMDRVINS pDrvIns)
-{
- LogFlowFuncEnter();
-
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
- PDRVAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIO);
-
- if (RTCritSectIsInitialized(&pThis->CritSect))
- {
- int rc2 = RTCritSectDelete(&pThis->CritSect);
- AssertRC(rc2);
- }
-}
-
-/**
- * Suspend notification.
- *
- * @param pDrvIns The driver instance data.
- */
-static DECLCALLBACK(void) drvAudioSuspend(PPDMDRVINS pDrvIns)
-{
- drvAudioStateHandler(pDrvIns, PDMAUDIOSTREAMCMD_PAUSE);
-}
-
-/**
- * Resume notification.
- *
- * @param pDrvIns The driver instance data.
- */
-static DECLCALLBACK(void) drvAudioResume(PPDMDRVINS pDrvIns)
-{
- drvAudioStateHandler(pDrvIns, PDMAUDIOSTREAMCMD_RESUME);
-}
-
-/**
- * Audio driver registration record.
- */
-const PDMDRVREG g_DrvAUDIO =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "AUDIO",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Audio connector driver",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- 2,
- /* cbInstance */
- sizeof(DRVAUDIO),
- /* pfnConstruct */
- drvAudioConstruct,
- /* pfnDestruct */
- drvAudioDestruct,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- drvAudioSuspend,
- /* pfnResume */
- drvAudioResume,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- drvAudioPowerOff,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
diff --git a/src/VBox/Devices/Audio_50/DrvAudio.h b/src/VBox/Devices/Audio_50/DrvAudio.h
deleted file mode 100644
index e48c62a..0000000
--- a/src/VBox/Devices/Audio_50/DrvAudio.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/* $Id: DrvAudio.h $ */
-/** @file
- * Intermediate audio driver header.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- *
- * This code is based on: audio.h
- *
- * QEMU Audio subsystem header
- *
- * Copyright (c) 2003-2005 Vassili Karpov (malc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#ifndef DRV_AUDIO_H
-#define DRV_AUDIO_H
-
-#include <limits.h>
-
-#include <iprt/circbuf.h>
-#include <iprt/critsect.h>
-
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/vmm/pdm.h>
-#include <VBox/vmm/pdmaudioifs.h>
-
-typedef enum
-{
- AUD_OPT_INT,
- AUD_OPT_FMT,
- AUD_OPT_STR,
- AUD_OPT_BOOL
-} audio_option_tag_e;
-
-typedef struct audio_option
-{
- const char *name;
- audio_option_tag_e tag;
- void *valp;
- const char *descr;
- int *overridenp;
- int overriden;
-} audio_option;
-
-/**
- * Audio driver instance data.
- *
- * @implements PDMIAUDIOCONNECTOR
- */
-typedef struct DRVAUDIO
-{
- /** Input/output processing thread. */
- RTTHREAD hThread;
- /** Critical section for serializing access. */
- RTCRITSECT CritSect;
- /** Shutdown indicator. */
- bool fTerminate;
- /** Our audio connector interface. */
- PDMIAUDIOCONNECTOR IAudioConnector;
- /** Pointer to the driver instance. */
- PPDMDRVINS pDrvIns;
- /** Pointer to audio driver below us. */
- PPDMIHOSTAUDIO pHostDrvAudio;
- /** List of host input streams. */
- RTLISTANCHOR lstHstStrmIn;
- /** List of host output streams. */
- RTLISTANCHOR lstHstStrmOut;
- /** Max. number of free input streams.
- * UINT32_MAX for unlimited streams. */
- uint32_t cFreeInputStreams;
- /** Max. number of free output streams.
- * UINT32_MAX for unlimited streams. */
- uint32_t cFreeOutputStreams;
- /** Audio configuration settings retrieved from the backend. */
- PDMAUDIOBACKENDCFG BackendCfg;
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- /** @todo Use a map with primary key set to the callback type? */
- RTLISTANCHOR lstCBIn;
- RTLISTANCHOR lstCBOut;
-#endif
-} DRVAUDIO, *PDRVAUDIO;
-
-/** Makes a PDRVAUDIO out of a PPDMIAUDIOCONNECTOR. */
-#define PDMIAUDIOCONNECTOR_2_DRVAUDIO(pInterface) \
- ( (PDRVAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVAUDIO, IAudioConnector)) )
-
-const char *drvAudioHlpFormatToString(PDMAUDIOFMT enmFormat);
-const char *drvAudioRecSourceToString(PDMAUDIORECSOURCE enmRecSource);
-PDMAUDIOFMT drvAudioHlpStringToFormat(const char *pszFormat);
-
-bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS info, PPDMAUDIOSTREAMCFG pCfg);
-void drvAudioStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg);
-
-/* AUDIO IN function declarations. */
-void drvAudioHlpPcmSwFreeResourcesIn(PPDMAUDIOGSTSTRMIN pGstStrmIn);
-void drvAudioGstInFreeRes(PPDMAUDIOGSTSTRMIN pGstStrmIn);
-void drvAudioGstInRemove(PPDMAUDIOGSTSTRMIN pGstStrmIn);
-uint32_t drvAudioHstInFindMinCaptured(PPDMAUDIOHSTSTRMIN pHstStrmIn);
-void drvAudioHstInFreeRes(PPDMAUDIOHSTSTRMIN pHstStrmIn);
-uint32_t drvAudioHstInGetFree(PPDMAUDIOHSTSTRMIN pHstStrmIn);
-uint32_t drvAudioHstInGetLive(PPDMAUDIOHSTSTRMIN pHstStrmIn);
-void drvAudioGstInRemove(PPDMAUDIOGSTSTRMIN pGstStrmIn);
-int drvAudioGstInInit(PPDMAUDIOGSTSTRMIN pGstStrmIn, PPDMAUDIOHSTSTRMIN pHstStrmIn, const char *pszName, PPDMAUDIOSTREAMCFG pCfg);
-
-PPDMAUDIOHSTSTRMIN drvAudioFindNextHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn);
-PPDMAUDIOHSTSTRMIN drvAudioFindNextEnabledHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn);
-PPDMAUDIOHSTSTRMIN drvAudioFindNextEqHstIn(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg);
-
-/* AUDIO OUT function declarations. */
-int drvAudioGstOutAlloc(PPDMAUDIOGSTSTRMOUT pGstStrmOut);
-void drvAudioGstOutFreeRes(PPDMAUDIOGSTSTRMOUT pGstStrmOut);
-void drvAudioHstOutFreeRes(PPDMAUDIOHSTSTRMOUT pHstStrmOut);
-int drvAudioDestroyGstOut(PDRVAUDIO pDrvAudio, PPDMAUDIOGSTSTRMOUT pGstStrmOut);
-void drvAudioDestroyHstOut(PDRVAUDIO pDrvAudio, PDMAUDIOHSTSTRMOUT pHstStrmOut);
-int drvAudioGstOutInit(PPDMAUDIOGSTSTRMOUT pGstStrmOut, PPDMAUDIOHSTSTRMOUT pHstStrmOut, const char *pszName, PPDMAUDIOSTREAMCFG pCfg);
-
-PPDMAUDIOHSTSTRMOUT drvAudioFindAnyHstOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
-PPDMAUDIOHSTSTRMOUT drvAudioHstFindAnyEnabledOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
-PPDMAUDIOHSTSTRMOUT drvAudioFindSpecificOut(PDRVAUDIO pDrvAudio, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg);
-int drvAudioAllocHstOut(PDRVAUDIO pDrvAudio, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut);
-int drvAudioHlpPcmHwAddOut(PDRVAUDIO pDrvAudio, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOHSTSTRMOUT *ppHstStrmOut);
-int drvAudioHlpPcmCreateVoicePairOut(PDRVAUDIO pDrvAudio, const char *pszName, PPDMAUDIOSTREAMCFG pCfg, PPDMAUDIOGSTSTRMOUT *ppGstStrmOut);
-
-/* Common functions between DrvAudio and backends (host audio drivers). */
-void DrvAudioClearBuf(PPDMPCMPROPS pPCMInfo, void *pvBuf, size_t cbBuf, uint32_t cSamples);
-int DrvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps);
-
-#endif /* DRV_AUDIO_H */
diff --git a/src/VBox/Devices/Audio_50/DrvAudioCommon.cpp b/src/VBox/Devices/Audio_50/DrvAudioCommon.cpp
deleted file mode 100644
index 12c1e2c..0000000
--- a/src/VBox/Devices/Audio_50/DrvAudioCommon.cpp
+++ /dev/null
@@ -1,413 +0,0 @@
-/* $Id: DrvAudioCommon.cpp $ */
-/** @file
- * Intermedia audio driver, common routines. These are also used
- * in the drivers which are bound to Main, e.g. the VRDE or the
- * video audio recording drivers.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- *
- * This code is based on: audio_template.h from QEMU AUDIO subsystem.
- *
- * QEMU Audio subsystem header
- *
- * Copyright (c) 2005 Vassili Karpov (malc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#define LOG_GROUP LOG_GROUP_DRV_AUDIO
-#include <VBox/log.h>
-#include <iprt/asm-math.h>
-#include <iprt/assert.h>
-#include <iprt/uuid.h>
-#include <iprt/string.h>
-#include <iprt/alloc.h>
-
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/vmm/pdm.h>
-#include <VBox/err.h>
-#include <VBox/vmm/mm.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-
-bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg);
-
-const char *drvAudioRecSourceToString(PDMAUDIORECSOURCE enmRecSource)
-{
- switch (enmRecSource)
- {
- case PDMAUDIORECSOURCE_MIC: return "Microphone In";
- case PDMAUDIORECSOURCE_CD: return "CD";
- case PDMAUDIORECSOURCE_VIDEO: return "Video";
- case PDMAUDIORECSOURCE_AUX: return "AUX";
- case PDMAUDIORECSOURCE_LINE_IN: return "Line In";
- case PDMAUDIORECSOURCE_PHONE: return "Phone";
- default:
- break;
- }
-
- AssertMsgFailed(("Bogus recording source %ld\n", enmRecSource));
- return "Unknown";
-}
-
-const char *drvAudioHlpFormatToString(PDMAUDIOFMT enmFormat)
-{
- switch (enmFormat)
- {
- case AUD_FMT_U8:
- return "U8";
-
- case AUD_FMT_U16:
- return "U16";
-
- case AUD_FMT_U32:
- return "U32";
-
- case AUD_FMT_S8:
- return "S8";
-
- case AUD_FMT_S16:
- return "S16";
-
- case AUD_FMT_S32:
- return "S32";
-
- default:
- break;
- }
-
- AssertMsgFailed(("Bogus audio format %ld\n", enmFormat));
- return "Invalid";
-}
-
-PDMAUDIOFMT drvAudioHlpStringToFormat(const char *pszFormat)
-{
- if (!RTStrICmp(pszFormat, "u8"))
- return AUD_FMT_U8;
- else if (!RTStrICmp(pszFormat, "u16"))
- return AUD_FMT_U16;
- else if (!RTStrICmp(pszFormat, "u32"))
- return AUD_FMT_U32;
- else if (!RTStrICmp(pszFormat, "s8"))
- return AUD_FMT_S8;
- else if (!RTStrICmp(pszFormat, "s16"))
- return AUD_FMT_S16;
- else if (!RTStrICmp(pszFormat, "s32"))
- return AUD_FMT_S32;
-
- AssertMsgFailed(("Bogus audio format \"%s\"\n", pszFormat));
- return AUD_FMT_INVALID;
-}
-
-/*********************************** In Stream Functions **********************************************/
-
-void drvAudioGstInFreeRes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
-{
- AssertPtrReturnVoid(pGstStrmIn);
-
- if (pGstStrmIn->State.pszName)
- {
- RTStrFree(pGstStrmIn->State.pszName);
- pGstStrmIn->State.pszName = NULL;
- }
-
- AudioMixBufDestroy(&pGstStrmIn->MixBuf);
-}
-
-void drvAudioHstInFreeRes(PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- AssertPtrReturnVoid(pHstStrmIn);
- AudioMixBufDestroy(&pHstStrmIn->MixBuf);
-}
-
-void drvAudioGstOutFreeRes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
-{
- if (!pGstStrmOut)
- return;
-
- if (pGstStrmOut->State.pszName)
- {
- RTStrFree(pGstStrmOut->State.pszName);
- pGstStrmOut->State.pszName = NULL;
- }
-
- AudioMixBufDestroy(&pGstStrmOut->MixBuf);
-}
-
-#if 0
-
-/**
- * Finds the minimum number of not yet captured samples of all
- * attached guest input streams for a certain host input stream.
- *
- * @return uint32_t Minimum number of not yet captured samples.
- * UINT32_MAX if none found.
- * @param pHstStrmIn Host input stream to check for.
- */
-inline uint32_t drvAudioHstInFindMinCaptured(PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- AssertPtrReturn(pHstStrmIn, 0);
- uint32_t cMinSamples = UINT32_MAX;
-
- PPDMAUDIOGSTSTRMIN pGstStrmIn;
- RTListForEach(&pHstStrmIn->lstGstStrmIn, pGstStrmIn, PDMAUDIOGSTSTRMIN, Node)
- {
- if (pGstStrmIn->State.fActive)
- cMinSamples = RT_MIN(cMinSamples, audioMixBufMixed(&pGstStrmIn->MixBuf));
- }
-
-#ifdef DEBUG_andy
- LogFlowFunc(("cMinSamples=%RU32\n", cMinSamples));
-#endif
- return cMinSamples;
-}
-
-uint32_t drvAudioHstInGetFree(PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- AssertPtrReturn(pHstStrmIn, 0);
-
- return audioMixBufSize(&pHstStrmIn->MixBuf) - drvAudioHstInGetLive(pHstStrmIn);
-}
-
-uint32_t drvAudioHstInGetLive(PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- AssertPtrReturn(pHstStrmIn, 0);
-
- uint32_t cMinSamplesCaptured = drvAudioHstInFindMinCaptured(pHstStrmIn);
- uint32_t cSamplesCaptured = audioMixBufMixed(&pHstStrmIn->MixBuf);
-
- Assert(cSamplesCaptured >= cMinSamplesCaptured);
- uint32_t cSamplesLive = cSamplesCaptured - cMinSamplesCaptured;
- Assert(cSamplesLive <= audioMixBufSize(&pHstStrmIn->MixBuf));
-
-#ifdef DEBUG_andy
- LogFlowFunc(("cSamplesLive=%RU32\n", cSamplesLive));
-#endif
- return cSamplesLive;
-}
-#endif
-
-void drvAudioHstOutFreeRes(PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- AssertPtrReturnVoid(pHstStrmOut);
- AudioMixBufDestroy(&pHstStrmOut->MixBuf);
-}
-
-#if 0
-/**
- * Returns the number of live sample data (in bytes) of a certain
- * guest input stream.
- *
- * @return uint32_t Live sample data (in bytes), 0 if none.
- * @param pGstStrmIn Guest input stream to check for.
- */
-uint32_t drvAudioGstInGetLiveBytes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
-{
- AssertPtrReturn(pGstStrmIn, 0);
- AssertPtrReturn(pGstStrmIn->pHstStrmIn, 0);
-
- Assert(pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured >= pGstStrmIn->cTotalHostSamplesRead);
- uint32_t cSamplesLive = pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured - pGstStrmIn->cTotalHostSamplesRead;
- if (!cSamplesLive)
- return 0;
- Assert(cSamplesLive <= pGstStrmIn->pHstStrmIn->cSamples);
-
- /** @todo Document / refactor this! */
- return (((int64_t) cSamplesLive << 32) / pGstStrmIn->State.uFreqRatio) << pGstStrmIn->Props.cShift;
-}
-
-
-/**
- * Returns the total number of unused sample data (in bytes) of a certain
- * guest output stream.
- *
- * @return uint32_t Number of unused sample data (in bytes), 0 if all used up.
- * @param pGstStrmOut Guest output stream to check for.
- */
-uint32_t drvAudioGstOutGetFreeBytes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
-{
- AssertPtrReturn(pGstStrmOut, 0);
-
- Assert(pGstStrmOut->cTotalSamplesWritten <= pGstStrmOut->pHstStrmOut->cSamples);
- uint32_t cSamplesFree = pGstStrmOut->pHstStrmOut->cSamples
- - pGstStrmOut->cTotalSamplesWritten;
- if (!cSamplesFree)
- return 0;
-
- /** @todo Document / refactor this! */
- return (((int64_t) cSamplesFree << 32) / pGstStrmOut->State.uFreqRatio) << pGstStrmOut->Props.cShift;
-}
-#endif
-
-bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
-{
- int cBits = 8;
- bool fSigned = false;
-
- switch (pCfg->enmFormat)
- {
- case AUD_FMT_S8:
- fSigned = true;
- case AUD_FMT_U8:
- break;
-
- case AUD_FMT_S16:
- fSigned = true;
- case AUD_FMT_U16:
- cBits = 16;
- break;
-
- case AUD_FMT_S32:
- fSigned = true;
- case AUD_FMT_U32:
- cBits = 32;
- break;
-
- default:
- AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
- break;
- }
-
- bool fEqual = pProps->uHz == pCfg->uHz
- && pProps->cChannels == pCfg->cChannels
- && pProps->fSigned == fSigned
- && pProps->cBits == cBits
- && pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANNESS);
-
- LogFlowFunc(("fEqual=%RTbool\n", fEqual));
- return fEqual;
-}
-
-/**
- * Converts an audio stream configuration to matching PCM properties.
- *
- * @return IPRT status code.
- * @param pCfg Audio stream configuration to convert.
- * @param pProps PCM properties to save result to.
- */
-int DrvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps)
-{
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- AssertPtrReturn(pProps, VERR_INVALID_POINTER);
-
- int rc = VINF_SUCCESS;
-
- int cBits = 8, cShift = 0;
- bool fSigned = false;
-
- switch (pCfg->enmFormat)
- {
- case AUD_FMT_S8:
- fSigned = true;
- case AUD_FMT_U8:
- break;
-
- case AUD_FMT_S16:
- fSigned = true;
- case AUD_FMT_U16:
- cBits = 16;
- cShift = 1;
- break;
-
- case AUD_FMT_S32:
- fSigned = true;
- case AUD_FMT_U32:
- cBits = 32;
- cShift = 2;
- break;
-
- default:
- AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- if (RT_SUCCESS(rc))
- {
- pProps->uHz = pCfg->uHz;
- pProps->cBits = cBits;
- pProps->fSigned = fSigned;
- pProps->cChannels = pCfg->cChannels;
- pProps->cShift = (pCfg->cChannels == 2) + cShift;
- pProps->uAlign = (1 << pProps->cShift) - 1;
- pProps->cbPerSec = pProps->uHz << pProps->cShift;
- pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
- }
-
- return rc;
-}
-
-void drvAudioStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
-{
- LogFlowFunc(("uHz=%RU32, cChannels=%RU8, enmFormat=",
- pCfg->uHz, pCfg->cChannels));
-
- switch (pCfg->enmFormat)
- {
- case AUD_FMT_S8:
- LogFlow(("S8"));
- break;
- case AUD_FMT_U8:
- LogFlow(("U8"));
- break;
- case AUD_FMT_S16:
- LogFlow(("S16"));
- break;
- case AUD_FMT_U16:
- LogFlow(("U16"));
- break;
- case AUD_FMT_S32:
- LogFlow(("S32"));
- break;
- case AUD_FMT_U32:
- LogFlow(("U32"));
- break;
- default:
- LogFlow(("invalid(%d)", pCfg->enmFormat));
- break;
- }
-
- LogFlow((", endianness="));
- switch (pCfg->enmEndianness)
- {
- case PDMAUDIOENDIANNESS_LITTLE:
- LogFlow(("little\n"));
- break;
- case PDMAUDIOENDIANNESS_BIG:
- LogFlow(("big\n"));
- break;
- default:
- LogFlow(("invalid\n"));
- break;
- }
-}
diff --git a/src/VBox/Devices/Audio_50/DrvHostALSAAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostALSAAudio.cpp
deleted file mode 100644
index 23b4c3a..0000000
--- a/src/VBox/Devices/Audio_50/DrvHostALSAAudio.cpp
+++ /dev/null
@@ -1,1425 +0,0 @@
-/* $Id: DrvHostALSAAudio.cpp $ */
-/** @file
- * VBox audio devices: ALSA audio driver.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- *
- * This code is based on: alsaaudio.c
- *
- * QEMU ALSA audio driver
- *
- * Copyright (c) 2005 Vassili Karpov (malc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <VBox/log.h>
-#include <iprt/alloc.h>
-#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
-#include <VBox/vmm/pdmaudioifs.h>
-
-RT_C_DECLS_BEGIN
- #include "alsa_stubs.h"
- #include "alsa_mangling.h"
-RT_C_DECLS_END
-
-#include <alsa/asoundlib.h>
-
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-
-#include "VBoxDD.h"
-
-typedef struct ALSAAUDIOSTREAMIN
-{
- PDMAUDIOHSTSTRMIN pStreamIn;
- snd_pcm_t *phPCM;
- void *pvBuf;
- size_t cbBuf;
-} ALSAAUDIOSTREAMIN, *PALSAAUDIOSTREAMIN;
-
-typedef struct ALSAAUDIOSTREAMOUT
-{
- PDMAUDIOHSTSTRMOUT pStreamOut;
- snd_pcm_t *phPCM;
- void *pvBuf;
- size_t cbBuf;
-} ALSAAUDIOSTREAMOUT, *PALSAAUDIOSTREAMOUT;
-
-/* latency = period_size * periods / (rate * bytes_per_frame) */
-
-typedef struct ALSAAUDIOCFG
-{
- int size_in_usec_in;
- int size_in_usec_out;
- const char *pcm_name_in;
- const char *pcm_name_out;
- unsigned int buffer_size_in;
- unsigned int period_size_in;
- unsigned int buffer_size_out;
- unsigned int period_size_out;
- unsigned int threshold;
-
- int buffer_size_in_overriden;
- int period_size_in_overriden;
-
- int buffer_size_out_overriden;
- int period_size_out_overriden;
-
-} ALSAAUDIOCFG, *PALSAAUDIOCFG;
-
-static int drvHostALSAAudioRecover(snd_pcm_t *phPCM);
-
-static ALSAAUDIOCFG s_ALSAConf =
-{
-#ifdef HIGH_LATENCY
- 1,
- 1,
-#else
- 0,
- 0,
-#endif
- "default",
- "default",
-#ifdef HIGH_LATENCY
- 400000,
- 400000 / 4,
- 400000,
- 400000 / 4,
-#else
-# define DEFAULT_BUFFER_SIZE 1024
-# define DEFAULT_PERIOD_SIZE 256
- DEFAULT_BUFFER_SIZE * 4,
- DEFAULT_PERIOD_SIZE * 4,
- DEFAULT_BUFFER_SIZE,
- DEFAULT_PERIOD_SIZE,
-#endif
- 0,
- 0,
- 0,
- 0,
- 0
-};
-
-/**
- * Host Alsa audio driver instance data.
- * @implements PDMIAUDIOCONNECTOR
- */
-typedef struct DRVHOSTALSAAUDIO
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
- /** Error count for not flooding the release log.
- * UINT32_MAX for unlimited logging. */
- uint32_t cLogErrors;
-} DRVHOSTALSAAUDIO, *PDRVHOSTALSAAUDIO;
-
-/** Maximum number of tries to recover a broken pipe. */
-#define ALSA_RECOVERY_TRIES_MAX 5
-
-typedef struct ALSAAUDIOSTREAMCFG
-{
- unsigned int freq;
- snd_pcm_format_t fmt;
- int nchannels;
- unsigned long buffer_size;
- unsigned long period_size;
- snd_pcm_uframes_t samples;
-} ALSAAUDIOSTREAMCFG, *PALSAAUDIOSTREAMCFG;
-
-static int drvHostALSAAudioClose(snd_pcm_t **pphPCM)
-{
- if (!pphPCM || !*pphPCM)
- return VINF_SUCCESS;
-
- int rc;
- int rc2 = snd_pcm_close(*pphPCM);
- if (rc2)
- {
- LogRel(("ALSA: Closing PCM descriptor failed: %s\n", snd_strerror(rc2)));
- rc = VERR_GENERAL_FAILURE; /** @todo */
- }
- else
- {
- *pphPCM = NULL;
- rc = VINF_SUCCESS;
- }
-
- return rc;
-}
-
-static snd_pcm_format_t drvHostALSAAudioFmtToALSA(PDMAUDIOFMT fmt)
-{
- switch (fmt)
- {
- case AUD_FMT_S8:
- return SND_PCM_FORMAT_S8;
-
- case AUD_FMT_U8:
- return SND_PCM_FORMAT_U8;
-
- case AUD_FMT_S16:
- return SND_PCM_FORMAT_S16_LE;
-
- case AUD_FMT_U16:
- return SND_PCM_FORMAT_U16_LE;
-
- case AUD_FMT_S32:
- return SND_PCM_FORMAT_S32_LE;
-
- case AUD_FMT_U32:
- return SND_PCM_FORMAT_U32_LE;
-
- default:
- break;
- }
-
- AssertMsgFailed(("Format %ld not supported\n", fmt));
- return SND_PCM_FORMAT_U8;
-}
-
-static int drvHostALSAAudioALSAToFmt(snd_pcm_format_t fmt,
- PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
-{
- AssertPtrReturn(pFmt, VERR_INVALID_POINTER);
- /* pEndianness is optional. */
-
- switch (fmt)
- {
- case SND_PCM_FORMAT_S8:
- *pFmt = AUD_FMT_S8;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case SND_PCM_FORMAT_U8:
- *pFmt = AUD_FMT_U8;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case SND_PCM_FORMAT_S16_LE:
- *pFmt = AUD_FMT_S16;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case SND_PCM_FORMAT_U16_LE:
- *pFmt = AUD_FMT_U16;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case SND_PCM_FORMAT_S16_BE:
- *pFmt = AUD_FMT_S16;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_BIG;
- break;
-
- case SND_PCM_FORMAT_U16_BE:
- *pFmt = AUD_FMT_U16;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_BIG;
- break;
-
- case SND_PCM_FORMAT_S32_LE:
- *pFmt = AUD_FMT_S32;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case SND_PCM_FORMAT_U32_LE:
- *pFmt = AUD_FMT_U32;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case SND_PCM_FORMAT_S32_BE:
- *pFmt = AUD_FMT_S32;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_BIG;
- break;
-
- case SND_PCM_FORMAT_U32_BE:
- *pFmt = AUD_FMT_U32;
- if (pEndianness)
- *pEndianness = PDMAUDIOENDIANNESS_BIG;
- break;
-
- default:
- AssertMsgFailed(("Format %ld not supported\n", fmt));
- return VERR_NOT_SUPPORTED;
- }
-
- return VINF_SUCCESS;
-}
-
-static int drvHostALSAAudioALSAGetShift(snd_pcm_format_t fmt, unsigned *puShift)
-{
- AssertPtrReturn(puShift, VERR_INVALID_POINTER);
-
- switch (fmt)
- {
- case SND_PCM_FORMAT_S8:
- case SND_PCM_FORMAT_U8:
- *puShift = 0;
- break;
-
- case SND_PCM_FORMAT_S16_LE:
- case SND_PCM_FORMAT_U16_LE:
- case SND_PCM_FORMAT_S16_BE:
- case SND_PCM_FORMAT_U16_BE:
- *puShift = 1;
- break;
-
- case SND_PCM_FORMAT_S32_LE:
- case SND_PCM_FORMAT_U32_LE:
- case SND_PCM_FORMAT_S32_BE:
- case SND_PCM_FORMAT_U32_BE:
- *puShift = 2;
- break;
-
- default:
- AssertMsgFailed(("Format %ld not supported\n", fmt));
- return VERR_NOT_SUPPORTED;
- }
-
- return VINF_SUCCESS;
-}
-
-static int drvHostALSAAudioSetThreshold(snd_pcm_t *phPCM,
- snd_pcm_uframes_t threshold)
-{
- snd_pcm_sw_params_t *pSWParms = NULL;
- snd_pcm_sw_params_alloca(&pSWParms);
- if (!pSWParms)
- return VERR_NO_MEMORY;
-
- int rc;
- do
- {
- int err = snd_pcm_sw_params_current(phPCM, pSWParms);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to get current software parameters for threshold: %s\n",
- snd_strerror(err)));
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- err = snd_pcm_sw_params_set_start_threshold(phPCM, pSWParms, threshold);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set software threshold to %ld: %s\n",
- threshold, snd_strerror(err)));
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- err = snd_pcm_sw_params(phPCM, pSWParms);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set new software parameters for threshold: %s\n",
- snd_strerror(err)));
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- LogFlowFunc(("Setting threshold to %RU32\n", threshold));
- rc = VINF_SUCCESS;
- }
- while (0);
-
- return rc;
-}
-
-static int drvHostALSAAudioOpen(bool fIn,
- PALSAAUDIOSTREAMCFG pCfgReq,
- PALSAAUDIOSTREAMCFG pCfgObt,
- snd_pcm_t **pphPCM)
-{
- snd_pcm_t *phPCM = NULL;
- int rc;
-
- unsigned int cChannels = pCfgReq->nchannels;
- unsigned int uFreq = pCfgReq->freq;
- snd_pcm_uframes_t obt_buffer_size;
-
- do
- {
- const char *pszDev = fIn ? s_ALSAConf.pcm_name_in : s_ALSAConf.pcm_name_out;
- if (!pszDev)
- {
- LogRel(("ALSA: Invalid or no %s device name set\n", fIn ? "input" : "output"));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- int err = snd_pcm_open(&phPCM, pszDev,
- fIn ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
- SND_PCM_NONBLOCK);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to open \"%s\" as %s device: %s\n", pszDev, fIn ? "input" : "output", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- LogRel(("ALSA: Using %s device \"%s\"\n", fIn ? "input" : "output", pszDev));
-
- snd_pcm_hw_params_t *pHWParms;
- snd_pcm_hw_params_alloca(&pHWParms); /** @todo Check for successful allocation? */
- err = snd_pcm_hw_params_any(phPCM, pHWParms);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to initialize hardware parameters: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- err = snd_pcm_hw_params_set_access(phPCM, pHWParms,
- SND_PCM_ACCESS_RW_INTERLEAVED);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set access type: %s\n", snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- err = snd_pcm_hw_params_set_format(phPCM, pHWParms, pCfgReq->fmt);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set audio format to %d: %s\n", pCfgReq->fmt, snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- err = snd_pcm_hw_params_set_rate_near(phPCM, pHWParms, &uFreq, 0);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set frequency to %uHz: %s\n", pCfgReq->freq, snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- err = snd_pcm_hw_params_set_channels_near(phPCM, pHWParms, &cChannels);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set number of channels to %d\n", pCfgReq->nchannels));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- if ( cChannels != 1
- && cChannels != 2)
- {
- LogRel(("ALSA: Number of audio channels (%u) not supported\n", cChannels));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- unsigned int period_size = pCfgReq->period_size;
- unsigned int buffer_size = pCfgReq->buffer_size;
-
- if ( !((fIn && s_ALSAConf.size_in_usec_in)
- || (!fIn && s_ALSAConf.size_in_usec_out)))
- {
- if (!buffer_size)
- {
- buffer_size = DEFAULT_BUFFER_SIZE;
- period_size = DEFAULT_PERIOD_SIZE;
- }
- }
-
- if (buffer_size)
- {
- if ( ( fIn && s_ALSAConf.size_in_usec_in)
- || (!fIn && s_ALSAConf.size_in_usec_out))
- {
- if (period_size)
- {
- err = snd_pcm_hw_params_set_period_time_near(phPCM, pHWParms,
- &period_size, 0);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set period time %d\n", pCfgReq->period_size));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- }
-
- err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pHWParms,
- &buffer_size, 0);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set buffer time %d\n", pCfgReq->buffer_size));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- }
- else
- {
- snd_pcm_uframes_t period_size_f = (snd_pcm_uframes_t)period_size;
- snd_pcm_uframes_t buffer_size_f = (snd_pcm_uframes_t)buffer_size;
-
- snd_pcm_uframes_t minval;
-
- if (period_size_f)
- {
- minval = period_size_f;
-
- int dir = 0;
- err = snd_pcm_hw_params_get_period_size_min(pHWParms,
- &minval, &dir);
- if (err < 0)
- {
- LogRel(("ALSA: Could not determine minimal period size\n"));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- else
- {
- LogFunc(("Minimal period size is: %ld\n", minval));
- if (period_size_f < minval)
- {
- if ( ( fIn && s_ALSAConf.period_size_in_overriden)
- || (!fIn && s_ALSAConf.period_size_out_overriden))
- {
- LogFunc(("Period size %RU32 is less than minimal period size %RU32\n",
- period_size_f, minval));
- }
-
- period_size_f = minval;
- }
- }
-
- err = snd_pcm_hw_params_set_period_size_near(phPCM, pHWParms,
- &period_size_f, 0);
- LogFunc(("Period size is: %RU32\n", period_size_f));
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set period size %d (%s)\n",
- period_size_f, snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- }
-
- /* Calculate default buffer size here since it might have been changed
- * in the _near functions */
- buffer_size_f = 4 * period_size_f;
-
- minval = buffer_size_f;
- err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval);
- if (err < 0)
- {
- LogRel(("ALSA: Could not retrieve minimal buffer size\n"));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- else
- {
- LogFunc(("Minimal buffer size is: %RU32\n", minval));
- if (buffer_size_f < minval)
- {
- if ( ( fIn && s_ALSAConf.buffer_size_in_overriden)
- || (!fIn && s_ALSAConf.buffer_size_out_overriden))
- {
- LogFunc(("Buffer size %RU32 is less than minimal buffer size %RU32\n",
- buffer_size_f, minval));
- }
-
- buffer_size_f = minval;
- }
- }
-
- err = snd_pcm_hw_params_set_buffer_size_near(phPCM,
- pHWParms, &buffer_size_f);
- LogFunc(("Buffer size is: %RU32\n", buffer_size_f));
- if (err < 0)
- {
- LogRel(("ALSA: Failed to set buffer size %d: %s\n",
- buffer_size_f, snd_strerror(err)));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- }
- }
- else
- LogFunc(("Warning: Buffer size is not set\n"));
-
- err = snd_pcm_hw_params(phPCM, pHWParms);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to apply audio parameters\n"));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to get buffer size\n"));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- snd_pcm_uframes_t obt_period_size;
- int dir = 0;
- err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir);
- if (err < 0)
- {
- LogRel(("ALSA: Failed to get period size\n"));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- LogFunc(("Freq=%dHz, period size=%RU32, buffer size=%RU32\n",
- pCfgReq->freq, obt_period_size, obt_buffer_size));
-
- err = snd_pcm_prepare(phPCM);
- if (err < 0)
- {
- LogRel(("ALSA: Could not prepare hPCM %p\n", (void *)phPCM));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- if ( !fIn
- && s_ALSAConf.threshold)
- {
- unsigned uShift;
- rc = drvHostALSAAudioALSAGetShift(pCfgReq->fmt, &uShift);
- if (RT_SUCCESS(rc))
- {
- int bytes_per_sec = uFreq
- << (cChannels == 2)
- << uShift;
-
- snd_pcm_uframes_t threshold
- = (s_ALSAConf.threshold * bytes_per_sec) / 1000;
-
- rc = drvHostALSAAudioSetThreshold(phPCM, threshold);
- }
- }
- else
- rc = VINF_SUCCESS;
- }
- while (0);
-
- if (RT_SUCCESS(rc))
- {
- pCfgObt->fmt = pCfgReq->fmt;
- pCfgObt->nchannels = cChannels;
- pCfgObt->freq = uFreq;
- pCfgObt->samples = obt_buffer_size;
-
- *pphPCM = phPCM;
- }
- else
- drvHostALSAAudioClose(&phPCM);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-#ifdef DEBUG
-static void drvHostALSAAudioErrorHandler(const char *file, int line, const char *function,
- int err, const char *fmt, ...)
-{
- RT_NOREF(file, line, function, err, fmt);
- /** @todo Implement me! */
-}
-#endif
-
-static int drvHostALSAAudioGetAvail(snd_pcm_t *phPCM, snd_pcm_sframes_t *pFramesAvail)
-{
- AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
- AssertPtrReturn(pFramesAvail, VERR_INVALID_POINTER);
-
- int rc;
-
- snd_pcm_sframes_t framesAvail;
- framesAvail = snd_pcm_avail_update(phPCM);
- if (framesAvail < 0)
- {
- if (framesAvail == -EPIPE)
- {
- rc = drvHostALSAAudioRecover(phPCM);
- if (RT_SUCCESS(rc))
- framesAvail = snd_pcm_avail_update(phPCM);
- }
- else
- rc = VERR_ACCESS_DENIED; /** @todo Find a better rc. */
- }
- else
- rc = VINF_SUCCESS;
-
- if (framesAvail >= 0)
- *pFramesAvail = framesAvail;
-
- return rc;
-}
-
-static int drvHostALSAAudioRecover(snd_pcm_t *phPCM)
-{
- AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
-
- int err = snd_pcm_prepare(phPCM);
- if (err < 0)
- {
- LogFunc(("Failed to recover stream %p: %s\n", phPCM, snd_strerror(err)));
- return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
- }
-
- return VINF_SUCCESS;
-}
-
-static int drvHostALSAAudioResume(snd_pcm_t *phPCM)
-{
- AssertPtrReturn(phPCM, VERR_INVALID_POINTER);
-
- int err = snd_pcm_resume(phPCM);
- if (err < 0)
- {
- LogFunc(("Failed to resume stream %p: %s\n", phPCM, snd_strerror(err)));
- return VERR_ACCESS_DENIED; /** @todo Find a better rc. */
- }
-
- return VINF_SUCCESS;
-}
-
-static int drvHostALSAAudioStreamCtl(snd_pcm_t *phPCM, bool fPause)
-{
- int err;
- if (fPause)
- {
- err = snd_pcm_drop(phPCM);
- if (err < 0)
- {
- LogRel(("ALSA: Error stopping stream %p: %s\n", phPCM, snd_strerror(err)));
- return VERR_ACCESS_DENIED;
- }
- }
- else
- {
- err = snd_pcm_prepare(phPCM);
- if (err < 0)
- {
- LogRel(("ALSA: Error preparing stream %p: %s\n", phPCM, snd_strerror(err)));
- return VERR_ACCESS_DENIED;
- }
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioInit(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-
- LogFlowFuncEnter();
-
- int rc = audioLoadAlsaLib();
- if (RT_FAILURE(rc))
- LogRel(("ALSA: Failed to load the ALSA shared library, rc=%Rrc\n", rc));
- else
- {
-#ifdef DEBUG
- snd_lib_error_set_handler(drvHostALSAAudioErrorHandler);
-#endif
- }
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- uint32_t *pcSamplesCaptured)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
-
- snd_pcm_sframes_t cAvail;
- int rc = drvHostALSAAudioGetAvail(pThisStrmIn->phPCM, &cAvail);
- if (RT_FAILURE(rc))
- {
- LogFunc(("Error getting number of captured frames, rc=%Rrc\n", rc));
- return rc;
- }
-
- if (!cAvail) /* No data yet? */
- {
- snd_pcm_state_t state = snd_pcm_state(pThisStrmIn->phPCM);
- switch (state)
- {
- case SND_PCM_STATE_PREPARED:
- cAvail = AudioMixBufFree(&pHstStrmIn->MixBuf);
- break;
-
- case SND_PCM_STATE_SUSPENDED:
- {
- rc = drvHostALSAAudioResume(pThisStrmIn->phPCM);
- if (RT_FAILURE(rc))
- break;
-
- LogFlow(("Resuming suspended input stream\n"));
- break;
- }
-
- default:
- LogFlow(("No frames available, state=%d\n", state));
- break;
- }
-
- if (!cAvail)
- {
- if (pcSamplesCaptured)
- *pcSamplesCaptured = 0;
- return VINF_SUCCESS;
- }
- }
-
- /*
- * Check how much we can read from the capture device without overflowing
- * the mixer buffer.
- */
- Assert(cAvail);
- size_t cbMixFree = AudioMixBufFreeBytes(&pHstStrmIn->MixBuf);
- size_t cbToRead = RT_MIN((size_t)AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cAvail), cbMixFree);
-
- LogFlowFunc(("cbToRead=%zu, cAvail=%RI32\n", cbToRead, cAvail));
-
- uint32_t cWrittenTotal = 0;
- snd_pcm_uframes_t cToRead;
- snd_pcm_sframes_t cRead;
-
- while ( cbToRead
- && RT_SUCCESS(rc))
- {
- cToRead = RT_MIN(AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbToRead),
- AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, pThisStrmIn->cbBuf));
- AssertBreakStmt(cToRead, rc = VERR_NO_DATA);
- cRead = snd_pcm_readi(pThisStrmIn->phPCM, pThisStrmIn->pvBuf, cToRead);
- if (cRead <= 0)
- {
- switch (cRead)
- {
- case 0:
- {
- LogFunc(("No input frames available\n"));
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- case -EAGAIN:
- {
- /*
- * Don't set error here because EAGAIN means there are no further frames
- * available at the moment, try later. As we might have read some frames
- * already these need to be processed instead.
- */
- cbToRead = 0;
- break;
- }
-
- case -EPIPE:
- {
- rc = drvHostALSAAudioRecover(pThisStrmIn->phPCM);
- if (RT_FAILURE(rc))
- break;
-
- LogFlowFunc(("Recovered from capturing\n"));
- continue;
- }
-
- default:
- {
- LogFunc(("Failed to read input frames: %s\n", snd_strerror(cRead)));
- rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
- break;
- }
- }
- }
- else
- {
- uint32_t cWritten;
- rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
- pThisStrmIn->pvBuf, AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cRead),
- &cWritten);
- if (RT_FAILURE(rc))
- break;
-
- /*
- * We should not run into a full mixer buffer or we loose samples and
- * run into an endless loop if ALSA keeps producing samples ("null"
- * capture device for example).
- */
- AssertLogRelMsgBreakStmt(cWritten > 0, ("Mixer buffer shouldn't be full at this point!\n"),
- rc = VERR_INTERNAL_ERROR);
- uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
-
- Assert(cbToRead >= cbWritten);
- cbToRead -= cbWritten;
- cWrittenTotal += cWritten;
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cProcessed = 0;
- if (cWrittenTotal)
- rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
- &cProcessed);
-
- if (pcSamplesCaptured)
- *pcSamplesCaptured = cWrittenTotal;
-
- LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
- cWrittenTotal, cProcessed, rc));
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- uint32_t *pcSamplesPlayed)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
-
- int rc = VINF_SUCCESS;
- uint32_t cbReadTotal = 0;
-
- do
- {
- snd_pcm_sframes_t cAvail;
- rc = drvHostALSAAudioGetAvail(pThisStrmOut->phPCM, &cAvail);
- if (RT_FAILURE(rc))
- {
- LogFunc(("Error getting number of playback frames, rc=%Rrc\n", rc));
- break;
- }
-
- size_t cbToRead = RT_MIN(AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
- (uint32_t)cAvail), /* cAvail is always >= 0 */
- AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf,
- AudioMixBufAvail(&pHstStrmOut->MixBuf)));
- LogFlowFunc(("cbToRead=%zu, cbAvail=%zu\n",
- cbToRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cAvail)));
-
- uint32_t cRead, cbRead;
- snd_pcm_sframes_t cWritten;
- while (cbToRead)
- {
- rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvBuf, cbToRead, &cRead);
- if (RT_FAILURE(rc))
- break;
-
- cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
- AssertBreak(cbRead);
-
- /* Don't try infinitely on recoverable errors. */
- unsigned iTry;
- for (iTry = 0; iTry < ALSA_RECOVERY_TRIES_MAX; iTry++)
- {
- cWritten = snd_pcm_writei(pThisStrmOut->phPCM, pThisStrmOut->pvBuf, cRead);
- if (cWritten <= 0)
- {
- switch (cWritten)
- {
- case 0:
- {
- LogFunc(("Failed to write %RI32 frames\n", cRead));
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- case -EPIPE:
- {
- rc = drvHostALSAAudioRecover(pThisStrmOut->phPCM);
- if (RT_FAILURE(rc))
- break;
-
- LogFlowFunc(("Recovered from playback\n"));
- continue;
- }
-
- case -ESTRPIPE:
- {
- /* Stream was suspended and waiting for a recovery. */
- rc = drvHostALSAAudioResume(pThisStrmOut->phPCM);
- if (RT_FAILURE(rc))
- {
- LogRel(("ALSA: Failed to resume output stream\n"));
- break;
- }
-
- LogFlowFunc(("Resumed suspended output stream\n"));
- continue;
- }
-
- default:
- LogFlowFunc(("Failed to write %RI32 output frames, rc=%Rrc\n",
- cRead, rc));
- rc = VERR_GENERAL_FAILURE; /** @todo */
- break;
- }
- }
- else
- break;
- } /* For number of tries. */
-
- if ( iTry == ALSA_RECOVERY_TRIES_MAX
- && cWritten <= 0)
- rc = VERR_BROKEN_PIPE;
-
- if (RT_FAILURE(rc))
- break;
-
- Assert(cbToRead >= cbRead);
- cbToRead -= cbRead;
- cbReadTotal += cbRead;
- }
- }
- while (0);
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
- if (cReadTotal)
- AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
-
- if (pcSamplesPlayed)
- *pcSamplesPlayed = cReadTotal;
-
- LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
- cReadTotal, cbReadTotal, rc));
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
-
- drvHostALSAAudioClose(&pThisStrmIn->phPCM);
-
- if (pThisStrmIn->pvBuf)
- {
- RTMemFree(pThisStrmIn->pvBuf);
- pThisStrmIn->pvBuf = NULL;
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
-
- drvHostALSAAudioClose(&pThisStrmOut->phPCM);
-
- if (pThisStrmOut->pvBuf)
- {
- RTMemFree(pThisStrmOut->pvBuf);
- pThisStrmOut->pvBuf = NULL;
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioInitOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- uint32_t *pcSamples)
-{
- RT_NOREF(pInterface, pCfgAcq);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
-
- PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
- snd_pcm_t *phPCM = NULL;
-
- int rc;
-
- do
- {
- ALSAAUDIOSTREAMCFG req;
- req.fmt = drvHostALSAAudioFmtToALSA(pCfgReq->enmFormat);
- req.freq = pCfgReq->uHz;
- req.nchannels = pCfgReq->cChannels;
- req.period_size = s_ALSAConf.period_size_out;
- req.buffer_size = s_ALSAConf.buffer_size_out;
-
- ALSAAUDIOSTREAMCFG obt;
- rc = drvHostALSAAudioOpen(false /* false */, &req, &obt, &phPCM);
- if (RT_FAILURE(rc))
- break;
-
- PDMAUDIOFMT enmFormat;
- PDMAUDIOENDIANNESS enmEnd;
- rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
- if (RT_FAILURE(rc))
- break;
-
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = obt.freq;
- streamCfg.cChannels = obt.nchannels;
- streamCfg.enmFormat = enmFormat;
- streamCfg.enmEndianness = enmEnd;
-
- rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
- if (RT_FAILURE(rc))
- break;
-
- AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
- size_t cbBuf = obt.samples * (1 << pHstStrmOut->Props.cShift);
- AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
- pThisStrmOut->pvBuf = RTMemAlloc(cbBuf);
- if (!pThisStrmOut->pvBuf)
- {
- LogRel(("ALSA: Not enough memory for output DAC buffer (%RU32 samples, each %d bytes)\n",
- obt.samples, 1 << pHstStrmOut->Props.cShift));
- rc = VERR_NO_MEMORY;
- break;
- }
-
- pThisStrmOut->cbBuf = cbBuf;
- pThisStrmOut->phPCM = phPCM;
-
- if (pcSamples)
- *pcSamples = obt.samples;
- }
- while (0);
-
- if (RT_FAILURE(rc))
- drvHostALSAAudioClose(&phPCM);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioInitIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
-{
- RT_NOREF(pInterface, pCfgAcq, enmRecSource);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
-
- int rc;
-
- PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
- snd_pcm_t *phPCM = NULL;
-
- do
- {
- ALSAAUDIOSTREAMCFG req;
- req.fmt = drvHostALSAAudioFmtToALSA(pCfgReq->enmFormat);
- req.freq = pCfgReq->uHz;
- req.nchannels = pCfgReq->cChannels;
- req.period_size = s_ALSAConf.period_size_in;
- req.buffer_size = s_ALSAConf.buffer_size_in;
-
- ALSAAUDIOSTREAMCFG obt;
- rc = drvHostALSAAudioOpen(true /* fIn */, &req, &obt, &phPCM);
- if (RT_FAILURE(rc))
- break;
-
- PDMAUDIOFMT enmFormat;
- PDMAUDIOENDIANNESS enmEnd;
- rc = drvHostALSAAudioALSAToFmt(obt.fmt, &enmFormat, &enmEnd);
- if (RT_FAILURE(rc))
- break;
-
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.uHz = obt.freq;
- streamCfg.cChannels = obt.nchannels;
- streamCfg.enmFormat = enmFormat;
- streamCfg.enmEndianness = enmEnd;
-
- rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
- if (RT_FAILURE(rc))
- break;
-
- AssertBreakStmt(obt.samples, rc = VERR_INVALID_PARAMETER);
- size_t cbBuf = obt.samples * (1 << pHstStrmIn->Props.cShift);
- AssertBreakStmt(cbBuf, rc = VERR_INVALID_PARAMETER);
- pThisStrmIn->pvBuf = RTMemAlloc(cbBuf);
- if (!pThisStrmIn->pvBuf)
- {
- LogRel(("ALSA: Not enough memory for input ADC buffer (%RU32 samples, each %d bytes)\n",
- obt.samples, 1 << pHstStrmIn->Props.cShift));
- rc = VERR_NO_MEMORY;
- break;
- }
-
- pThisStrmIn->cbBuf = cbBuf;
- pThisStrmIn->phPCM = phPCM;
-
- if (pcSamples)
- *pcSamples = obt.samples;
- }
- while (0);
-
- if (RT_FAILURE(rc))
- drvHostALSAAudioClose(&phPCM);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(bool) drvHostALSAAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- NOREF(pInterface);
- NOREF(enmDir);
- return true; /* Always all enabled. */
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- PALSAAUDIOSTREAMIN pThisStrmIn = (PALSAAUDIOSTREAMIN)pHstStrmIn;
-
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-
- int rc;
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, false /* fStop */);
- break;
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- case PDMAUDIOSTREAMCMD_PAUSE:
- rc = drvHostALSAAudioStreamCtl(pThisStrmIn->phPCM, true /* fStop */);
- break;
-
- default:
- AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- PALSAAUDIOSTREAMOUT pThisStrmOut = (PALSAAUDIOSTREAMOUT)pHstStrmOut;
-
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-
- int rc;
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, false /* fStop */);
- break;
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- case PDMAUDIOSTREAMCMD_PAUSE:
- rc = drvHostALSAAudioStreamCtl(pThisStrmOut->phPCM, true /* fStop */);
- break;
-
- default:
- AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostALSAAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
- NOREF(pInterface);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- pCfg->cbStreamIn = sizeof(ALSAAUDIOSTREAMIN);
- pCfg->cbStreamOut = sizeof(ALSAAUDIOSTREAMOUT);
-
- /* ALSA only allows one input and one output used at a time for
- * the selected device. */
- pCfg->cMaxHstStrmsIn = 1;
- pCfg->cMaxHstStrmsOut = 1;
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(void) drvHostALSAAudioShutdown(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-}
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvHostALSAAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
-
- return NULL;
-}
-
-/**
- * Construct a DirectSound Audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvHostAlsaAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(pCfg, fFlags);
- PDRVHOSTALSAAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTALSAAUDIO);
- LogRel(("Audio: Initializing ALSA driver\n"));
-
- /*
- * Init the static parts.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvHostALSAAudioQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostALSAAudio);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Char driver registration record.
- */
-const PDMDRVREG g_DrvHostALSAAudio =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "ALSAAudio",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "ALSA host audio driver",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVHOSTALSAAUDIO),
- /* pfnConstruct */
- drvHostAlsaAudioConstruct,
- /* pfnDestruct */
- NULL,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
-
-#if 0 // unused
-static struct audio_option alsa_options[] =
-{
- {"DACSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_out,
- "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
- {"DACPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_out,
- "DAC period size", &s_ALSAConf.period_size_out_overriden, 0},
- {"DACBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_out,
- "DAC buffer size", &s_ALSAConf.buffer_size_out_overriden, 0},
-
- {"ADCSizeInUsec", AUD_OPT_BOOL, &s_ALSAConf.size_in_usec_in,
- "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
- {"ADCPeriodSize", AUD_OPT_INT, &s_ALSAConf.period_size_in,
- "ADC period size", &s_ALSAConf.period_size_in_overriden, 0},
- {"ADCBufferSize", AUD_OPT_INT, &s_ALSAConf.buffer_size_in,
- "ADC buffer size", &s_ALSAConf.buffer_size_in_overriden, 0},
-
- {"Threshold", AUD_OPT_INT, &s_ALSAConf.threshold,
- "(undocumented)", NULL, 0},
-
- {"DACDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_out,
- "DAC device name (for instance dmix)", NULL, 0},
-
- {"ADCDev", AUD_OPT_STR, &s_ALSAConf.pcm_name_in,
- "ADC device name", NULL, 0},
-
- NULL
-};
-#endif
diff --git a/src/VBox/Devices/Audio_50/DrvHostCoreAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostCoreAudio.cpp
deleted file mode 100644
index 11daedf..0000000
--- a/src/VBox/Devices/Audio_50/DrvHostCoreAudio.cpp
+++ /dev/null
@@ -1,2260 +0,0 @@
-/* $Id: DrvHostCoreAudio.cpp $ */
-/** @file
- * VBox audio devices: Mac OS X CoreAudio audio driver.
- */
-
-/*
- * Copyright (C) 2010-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <VBox/log.h>
-
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-
-#include "VBoxDD.h"
-
-#include <iprt/asm.h>
-#include <iprt/cdefs.h>
-#include <iprt/circbuf.h>
-#include <iprt/mem.h>
-
-#include <iprt/uuid.h>
-
-#include <CoreAudio/CoreAudio.h>
-#include <CoreServices/CoreServices.h>
-#include <AudioToolbox/AudioConverter.h>
-#include <AudioToolbox/AudioToolbox.h>
-
-/* Audio Queue buffer configuration. */
-#define AQ_BUF_COUNT 32 /* Number of buffers. */
-#define AQ_BUF_SIZE 512 /* Size of each buffer in bytes. */
-#define AQ_BUF_TOTAL (AQ_BUF_COUNT * AQ_BUF_SIZE)
-#define AQ_BUF_SAMPLES (AQ_BUF_TOTAL / 4) /* Hardcoded 4 bytes per sample! */
-
-#if 0
-# include <iprt/file.h>
-# define DEBUG_DUMP_PCM_DATA
-# ifdef RT_OS_WINDOWS
-# define DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
-# else
-# define DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
-# endif
-#endif
-
-/* Enables utilizing the Core Audio converter unit for converting
- * input / output from/to our requested formats. That might be more
- * performant than using our own routines later down the road. */
-/** @todo Needs more investigation and testing first before enabling. */
-//# define VBOX_WITH_AUDIO_CA_CONVERTER
-
-#ifdef DEBUG_andy
-# undef DEBUG_DUMP_PCM_DATA_PATH
-# define DEBUG_DUMP_PCM_DATA_PATH "/Users/anloeffl/Documents/"
-# undef VBOX_WITH_AUDIO_CA_CONVERTER
-#endif
-
-/* TODO:
- * - Maybe make sure the threads are immediately stopped if playing/recording stops.
- */
-
-/*
- * Most of this is based on:
- * http://developer.apple.com/mac/library/technotes/tn2004/tn2097.html
- * http://developer.apple.com/mac/library/technotes/tn2002/tn2091.html
- * http://developer.apple.com/mac/library/qa/qa2007/qa1533.html
- * http://developer.apple.com/mac/library/qa/qa2001/qa1317.html
- */
-
-/**
- * Host Coreaudio driver instance data.
- * @implements PDMIAUDIOCONNECTOR
- */
-typedef struct DRVHOSTCOREAUDIO
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
-} DRVHOSTCOREAUDIO, *PDRVHOSTCOREAUDIO;
-
-/*******************************************************************************
- *
- * Helper function section
- *
- ******************************************************************************/
-
-static void drvHostCoreAudioPrintASBD(const char *pszDesc, const AudioStreamBasicDescription *pASBD)
-{
- char pszSampleRate[32];
- LogRel2(("CoreAudio: %s description:\n", pszDesc));
- LogRel2(("CoreAudio:\tFormat ID: %RU32 (%c%c%c%c)\n", pASBD->mFormatID,
- RT_BYTE4(pASBD->mFormatID), RT_BYTE3(pASBD->mFormatID),
- RT_BYTE2(pASBD->mFormatID), RT_BYTE1(pASBD->mFormatID)));
- LogRel2(("CoreAudio:\tFlags: %RU32", pASBD->mFormatFlags));
- if (pASBD->mFormatFlags & kAudioFormatFlagIsFloat)
- LogRel2((" Float"));
- if (pASBD->mFormatFlags & kAudioFormatFlagIsBigEndian)
- LogRel2((" BigEndian"));
- if (pASBD->mFormatFlags & kAudioFormatFlagIsSignedInteger)
- LogRel2((" SignedInteger"));
- if (pASBD->mFormatFlags & kAudioFormatFlagIsPacked)
- LogRel2((" Packed"));
- if (pASBD->mFormatFlags & kAudioFormatFlagIsAlignedHigh)
- LogRel2((" AlignedHigh"));
- if (pASBD->mFormatFlags & kAudioFormatFlagIsNonInterleaved)
- LogRel2((" NonInterleaved"));
- if (pASBD->mFormatFlags & kAudioFormatFlagIsNonMixable)
- LogRel2((" NonMixable"));
- if (pASBD->mFormatFlags & kAudioFormatFlagsAreAllClear)
- LogRel2((" AllClear"));
- LogRel2(("\n"));
- snprintf(pszSampleRate, 32, "%.2f", (float)pASBD->mSampleRate); /** @todo r=andy Use RTStrPrint*. */
- LogRel2(("CoreAudio:\tSampleRate : %s\n", pszSampleRate));
- LogRel2(("CoreAudio:\tChannelsPerFrame: %RU32\n", pASBD->mChannelsPerFrame));
- LogRel2(("CoreAudio:\tFramesPerPacket : %RU32\n", pASBD->mFramesPerPacket));
- LogRel2(("CoreAudio:\tBitsPerChannel : %RU32\n", pASBD->mBitsPerChannel));
- LogRel2(("CoreAudio:\tBytesPerFrame : %RU32\n", pASBD->mBytesPerFrame));
- LogRel2(("CoreAudio:\tBytesPerPacket : %RU32\n", pASBD->mBytesPerPacket));
-}
-
-static int drvHostCoreAudioPCMPropsToASBD(PPDMPCMPROPS pPCMProps, AudioStreamBasicDescription *pASBD)
-{
- AssertPtrReturn(pPCMProps, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
-
- RT_BZERO(pASBD, sizeof(AudioStreamBasicDescription));
-
- pASBD->mFormatID = kAudioFormatLinearPCM;
- pASBD->mFormatFlags = kAudioFormatFlagIsPacked;
- pASBD->mFramesPerPacket = 1; /* For uncompressed audio, set this to 1. */
- pASBD->mSampleRate = (Float64)pPCMProps->uHz;
- pASBD->mChannelsPerFrame = pPCMProps->cChannels;
- pASBD->mBitsPerChannel = pPCMProps->cBits;
- if (pPCMProps->fSigned)
- pASBD->mFormatFlags |= kAudioFormatFlagIsSignedInteger;
- pASBD->mBytesPerFrame = pASBD->mChannelsPerFrame * (pASBD->mBitsPerChannel / 8);
- pASBD->mBytesPerPacket = pASBD->mFramesPerPacket * pASBD->mBytesPerFrame;
-
- return VINF_SUCCESS;
-}
-
-static int drvHostCoreAudioStreamCfgToASBD(PPDMAUDIOSTREAMCFG pCfg, AudioStreamBasicDescription *pASBD)
-{
- AssertPtrReturn(pCfg, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
-
- PDMPCMPROPS Props;
- int rc = DrvAudioStreamCfgToProps(pCfg, &Props);
- if (RT_SUCCESS(rc))
- rc = drvHostCoreAudioPCMPropsToASBD(&Props, pASBD);
-
- return rc;
-}
-
-static int drvHostCoreAudioASBDToStreamCfg(AudioStreamBasicDescription *pASBD, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pASBD, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pCfg, VERR_INVALID_PARAMETER);
-
- pCfg->cChannels = pASBD->mChannelsPerFrame;
- pCfg->uHz = (uint32_t)pASBD->mSampleRate;
- pCfg->enmEndianness = PDMAUDIOENDIANNESS_LITTLE;
-
- int rc = VINF_SUCCESS;
-
- if (pASBD->mFormatFlags & kAudioFormatFlagIsSignedInteger)
- {
- switch (pASBD->mBitsPerChannel)
- {
- case 8: pCfg->enmFormat = AUD_FMT_S8; break;
- case 16: pCfg->enmFormat = AUD_FMT_S16; break;
- case 32: pCfg->enmFormat = AUD_FMT_S32; break;
- default: rc = VERR_NOT_SUPPORTED; break;
- }
- }
- else
- {
- switch (pASBD->mBitsPerChannel)
- {
- case 8: pCfg->enmFormat = AUD_FMT_U8; break;
- case 16: pCfg->enmFormat = AUD_FMT_U16; break;
- case 32: pCfg->enmFormat = AUD_FMT_U32; break;
- default: rc = VERR_NOT_SUPPORTED; break;
- }
- }
-
- AssertRC(rc);
- return rc;
-}
-
-#if 0 // unused
-static AudioDeviceID drvHostCoreAudioDeviceUIDtoID(const char* pszUID)
-{
- /* Create a CFString out of our CString. */
- CFStringRef strUID = CFStringCreateWithCString(NULL, pszUID, kCFStringEncodingMacRoman);
-
- /* Fill the translation structure. */
- AudioDeviceID deviceID;
-
- AudioValueTranslation translation;
- translation.mInputData = &strUID;
- translation.mInputDataSize = sizeof(CFStringRef);
- translation.mOutputData = &deviceID;
- translation.mOutputDataSize = sizeof(AudioDeviceID);
-
- /* Fetch the translation from the UID to the device ID. */
- AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDeviceForUID, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-
- UInt32 uSize = sizeof(AudioValueTranslation);
- OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize, &translation);
-
- /* Release the temporary CFString */
- CFRelease(strUID);
-
- if (RT_LIKELY(err == noErr))
- return deviceID;
-
- /* Return the unknown device on error. */
- return kAudioDeviceUnknown;
-}
-#endif
-
-/*******************************************************************************
- *
- * Global structures section
- *
- ******************************************************************************/
-
-/* Initialization status indicator used for device (re)initialization. */
-#define CA_STATUS_UNINIT UINT32_C(0) /* The device is uninitialized */
-#define CA_STATUS_IN_INIT UINT32_C(1) /* The device is currently initializing */
-#define CA_STATUS_INIT UINT32_C(2) /* The device is initialized */
-#define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
-#define CA_STATUS_REINIT UINT32_C(4) /* The device has to be reinitialized */
-
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
-/* Error code which indicates "End of data" */
-static const OSStatus caConverterEOFDErr = 0x656F6664; /* 'eofd' */
-#endif
-
-/* Prototypes needed for COREAUDIOSTREAMCBCTX. */
-struct COREAUDIOSTREAMIN;
-typedef struct COREAUDIOSTREAMIN *PCOREAUDIOSTREAMIN;
-struct COREAUDIOSTREAMOUT;
-typedef struct COREAUDIOSTREAMOUT *PCOREAUDIOSTREAMOUT;
-
-typedef struct COREAUDIOSTREAM
-{
- /** The stream's direction. */
- PDMAUDIODIR enmDir;
- union
- {
- /** Pointer to self, if it's an input stream. */
- PCOREAUDIOSTREAMIN pIn;
- /** Pointer to self, if it's an output stream. */
- PCOREAUDIOSTREAMOUT pOut;
- /** @todo Add attributes here as soon as COREAUDIOSTREAMIN / COREAUDIOSTREAMOUT are unified. */
- };
- /** The stream's thread handle for maintaining the audio queue. */
- RTTHREAD hThread;
- /** Flag indicating to start a stream's data processing. */
- bool fRun;
- /** Whether the stream is in a running (active) state or not.
- * For playback streams this means that audio data can be (or is being) played,
- * for capturing streams this means that audio data is being captured (if available). */
- bool fIsRunning;
- /** Thread shutdown indicator. */
- bool fShutdown;
- /** Critical section for serializing access between thread + callbacks. */
- RTCRITSECT CritSect;
- /** The actual audio queue being used. */
- AudioQueueRef audioQueue;
- /** The audio buffers which are used with the above audio queue. */
- AudioQueueBufferRef audioBuffer[AQ_BUF_COUNT];
- /** The acquired (final) audio format for this stream. */
- AudioStreamBasicDescription asbdStream;
- /** The device' UUID. */
- CFStringRef UUID;
- /** An internal ring buffer for transferring data from/to the rendering callbacks. */
- PRTCIRCBUF pCircBuf;
-} COREAUDIOSTREAM, *PCOREAUDIOSTREAM;
-
-/**
- * Simple structure for maintaining a stream's callback context.
- */
-typedef struct COREAUDIOSTREAMCBCTX
-{
- /** Pointer to driver instance. */
- PDRVHOSTCOREAUDIO pThis;
- /** Pointer to the stream being handled. Can be NULL if not used. */
- PCOREAUDIOSTREAM pStream;
-} COREAUDIOSTREAMCBCTX, *PCOREAUDIOSTREAMCBCTX;
-
-/**
- * Structure for keeping a conversion callback context.
- * This is needed when using an audio converter during input/output processing.
- */
-typedef struct COREAUDIOCONVCBCTX
-{
- /** Pointer to stream context this converter callback context
- * is bound to. */
- /** @todo Remove this as soon as we have unified input/output streams in this backend. */
- PCOREAUDIOSTREAMCBCTX pStreamCtx;
- /** Source stream description. */
- AudioStreamBasicDescription asbdSrc;
- /** Destination stream description. */
- AudioStreamBasicDescription asbdDst;
- /** Pointer to native buffer list used for rendering the source audio data into. */
- AudioBufferList *pBufLstSrc;
- /** Total packet conversion count. */
- UInt32 uPacketCnt;
- /** Current packet conversion index. */
- UInt32 uPacketIdx;
- /** Error count, for limiting the logging. */
- UInt32 cErrors;
-} COREAUDIOCONVCBCTX, *PCOREAUDIOCONVCBCTX;
-
-/** @todo Unify COREAUDIOSTREAMOUT / COREAUDIOSTREAMIN. */
-typedef struct COREAUDIOSTREAMOUT
-{
- /** Host output stream.
- * Note: Always must come first in this structure! */
- PDMAUDIOHSTSTRMOUT streamOut;
- /** The audio device ID of the currently used device. */
- AudioDeviceID deviceID;
- /** A ring buffer for transferring data to the playback thread. */
- PRTCIRCBUF pCircBuf;
- /** Initialization status tracker. Used when some of the device parameters
- * or the device itself is changed during the runtime. */
- volatile uint32_t status;
- /** Flag whether the "default device changed" listener was registered. */
- bool fDefDevChgListReg;
- /** Flag whether the "device state changed" listener was registered. */
- bool fDevStateChgListReg;
- /** Unified attribtues. */
- /** @todo Remove this as soon as we have unified input/output streams in this backend. */
- COREAUDIOSTREAM Stream;
- /** Callback context for this stream for handing this stream in an CoreAudio callback.
- ** @todo Remove this as soon as we have unified input/output streams in this backend. */
- COREAUDIOSTREAMCBCTX cbCtx;
-} COREAUDIOSTREAMOUT, *PCOREAUDIOSTREAMOUT;
-
-typedef struct COREAUDIOSTREAMIN
-{
- /** Host input stream.
- * Note: Always must come first in this structure! */
- PDMAUDIOHSTSTRMIN streamIn;
- /** The audio device ID of the currently used device. */
- AudioDeviceID deviceID;
- /** A ring buffer for transferring data from the recording thread. */
- PRTCIRCBUF pCircBuf;
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- /** The audio converter if necessary. NULL if no converter is being used. */
- AudioConverterRef ConverterRef;
- /** Callback context for the audio converter. */
- COREAUDIOCONVCBCTX convCbCtx;
-#endif
- /** Initialization status tracker. Used when some of the device parameters
- * or the device itself is changed during the runtime. */
- volatile uint32_t status;
- /** Flag whether the "default device changed" listener was registered. */
- bool fDefDevChgListReg;
- /** Flag whether the "device state changed" listener was registered. */
- bool fDevStateChgListReg;
- /** Unified attribtues. */
- /** @todo Remove this as soon as we have unified input/output streams in this backend. */
- COREAUDIOSTREAM Stream;
- /** Callback context for this stream for handing this stream in an CoreAudio callback.
- ** @todo Remove this as soon as we have unified input/output streams in this backend. */
- COREAUDIOSTREAMCBCTX cbCtx;
-} COREAUDIOSTREAMIN, *PCOREAUDIOSTREAMIN;
-
-static int drvHostCoreAudioReinitInput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn);
-static int drvHostCoreAudioReinitOutput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
-
-static int drvHostCoreAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd);
-static int drvHostCoreAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd);
-static int drvHostCoreAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn);
-static int drvHostCoreAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut);
-
-static OSStatus drvHostCoreAudioDevPropChgCb(AudioObjectID propertyID, UInt32 nAddresses, const AudioObjectPropertyAddress properties[], void *pvUser);
-
-static void coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer, const AudioTimeStamp *pAudioTS, UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc);
-static void coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer);
-
-
-/**
- * Does a (Re-)enumeration of the host's playback + recording devices.
- *
- * @return IPRT status code.
- * @param pThis Host audio driver instance.
- * @param pCfg Where to store the enumeration results.
- * @param fEnum Enumeration flags.
- */
-static int drvHostCoreAudioDevicesEnumerate(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, bool fIn, uint32_t fEnum)
-{
- RT_NOREF(fEnum);
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- /* pCfg is optional. */
-
- int rc = VINF_SUCCESS;
-
- uint8_t cDevs = 0;
-
- do
- {
- AudioObjectPropertyAddress propAdrDevList = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- UInt32 uSize = 0;
- OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propAdrDevList, 0, NULL, &uSize);
- if (err != kAudioHardwareNoError)
- break;
-
- AudioDeviceID *pDevIDs = (AudioDeviceID *)alloca(uSize);
- if (pDevIDs == NULL)
- break;
-
- err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdrDevList, 0, NULL, &uSize, pDevIDs);
- if (err != kAudioHardwareNoError)
- break;
-
- UInt32 cDevices = uSize / sizeof (AudioDeviceID);
- for (UInt32 i = 0; i < cDevices; i++)
- {
- AudioDeviceID curDevID = pDevIDs[i];
-
- /* Check if the device is valid. */
- AudioObjectPropertyAddress propAddrCfg = { kAudioDevicePropertyStreamConfiguration,
- fIn ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster };
-
- err = AudioObjectGetPropertyDataSize(curDevID, &propAddrCfg, 0, NULL, &uSize);
- if (err != noErr)
- continue;
-
- AudioBufferList *pBufList = (AudioBufferList *)RTMemAlloc(uSize);
- if (!pBufList)
- continue;
-
- bool fIsValid = false;
- uint16_t cChannels = 0;
-
- err = AudioObjectGetPropertyData(curDevID, &propAddrCfg, 0, NULL, &uSize, pBufList);
- if (err == noErr)
- {
- for (UInt32 a = 0; a < pBufList->mNumberBuffers; a++)
- cChannels += pBufList->mBuffers[a].mNumberChannels;
-
- fIsValid = cChannels > 0;
- }
-
- if (pBufList)
- {
- RTMemFree(pBufList);
- pBufList = NULL;
- }
-
- if (!fIsValid)
- continue;
-
- /* Resolve the device's name. */
- AudioObjectPropertyAddress propAddrName = { kAudioObjectPropertyName,
- fIn ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster };
- uSize = sizeof(CFStringRef);
- CFStringRef pcfstrName = NULL;
-
- err = AudioObjectGetPropertyData(curDevID, &propAddrName, 0, NULL, &uSize, &pcfstrName);
- if (err != kAudioHardwareNoError)
- continue;
-
- CFIndex uMax = CFStringGetMaximumSizeForEncoding(CFStringGetLength(pcfstrName), kCFStringEncodingUTF8) + 1;
- if (uMax)
- {
- char *pszName = (char *)RTStrAlloc(uMax);
- if ( pszName
- && CFStringGetCString(pcfstrName, pszName, uMax, kCFStringEncodingUTF8))
- {
- LogRel2(("CoreAudio: Found %s device '%s' (%RU16 channels max)\n",
- fIn ? "recording" : "playback", pszName, cChannels));
- cDevs++;
- }
-
- if (pszName)
- {
- RTStrFree(pszName);
- pszName = NULL;
- }
- }
-
- CFRelease(pcfstrName);
- }
-
- } while (0);
-
- if (fIn)
- LogRel2(("CoreAudio: Found %RU8 recording device(s)\n", cDevs));
- else
- LogRel2(("CoreAudio: Found %RU8 playback device(s)\n", cDevs));
-
- if (pCfg)
- {
- if (fIn)
- pCfg->cMaxHstStrmsIn = cDevs;
- else
- pCfg->cMaxHstStrmsOut = cDevs;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/**
- * Updates this host driver's internal status, according to the global, overall input/output
- * state and all connected (native) audio streams.
- *
- * @param pThis Host audio driver instance.
- * @param pCfg Where to store the backend configuration. Optional.
- * @param fEnum Enumeration flags.
- */
-int coreAudioUpdateStatusInternalEx(PDRVHOSTCOREAUDIO pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
-{
- RT_NOREF(fEnum);
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- /* pCfg is optional. */
-
- PDMAUDIOBACKENDCFG Cfg;
- RT_ZERO(Cfg);
-
- Cfg.cbStreamOut = sizeof(COREAUDIOSTREAMOUT);
- Cfg.cbStreamIn = sizeof(COREAUDIOSTREAMIN);
-
- int rc = drvHostCoreAudioDevicesEnumerate(pThis, &Cfg, false /* fIn */, 0 /* fEnum */);
- AssertRC(rc);
- rc = drvHostCoreAudioDevicesEnumerate(pThis, &Cfg, true /* fIn */, 0 /* fEnum */);
- AssertRC(rc);
-
- if (pCfg)
- memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(OSStatus) drvHostCoreAudioDeviceStateChangedCb(AudioObjectID propertyID,
- UInt32 nAddresses,
- const AudioObjectPropertyAddress properties[],
- void *pvUser)
-{
- RT_NOREF(propertyID, nAddresses, properties);
- LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
-
- PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
- AssertPtr(pCbCtx);
- AssertPtr(pCbCtx->pStream);
-
- UInt32 uAlive = 1;
- UInt32 uSize = sizeof(UInt32);
-
- AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-
- AudioDeviceID deviceID = pCbCtx->pStream->enmDir == PDMAUDIODIR_IN
- ? pCbCtx->pStream->pIn->deviceID : pCbCtx->pStream->pOut->deviceID;
-
- OSStatus err = AudioObjectGetPropertyData(deviceID, &propAdr, 0, NULL, &uSize, &uAlive);
-
- bool fIsDead = false;
-
- if (err == kAudioHardwareBadDeviceError)
- fIsDead = true; /* Unplugged. */
- else if ((err == kAudioHardwareNoError) && (!RT_BOOL(uAlive)))
- fIsDead = true; /* Something else happened. */
-
- if (fIsDead)
- {
- switch (pCbCtx->pStream->enmDir)
- {
- case PDMAUDIODIR_IN:
- {
- PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
-
- /* We move the reinitialization to the next output event.
- * This make sure this thread isn't blocked and the
- * reinitialization is done when necessary only. */
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
-
- LogRel(("CoreAudio: Recording device stopped functioning\n"));
- break;
- }
-
- case PDMAUDIODIR_OUT:
- {
- PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
-
- /* We move the reinitialization to the next output event.
- * This make sure this thread isn't blocked and the
- * reinitialization is done when necessary only. */
- ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
-
- LogRel(("CoreAudio: Playback device stopped functioning\n"));
- break;
- }
-
- default:
- AssertMsgFailed(("Not implemented\n"));
- break;
- }
- }
-
- int rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
- AssertRC(rc2);
- rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
- AssertRC(rc2);
-
- return noErr;
-}
-
-/* Callback for getting notified when the default recording/playback device has been changed. */
-static DECLCALLBACK(OSStatus) drvHostCoreAudioDefaultDeviceChangedCb(AudioObjectID propertyID,
- UInt32 nAddresses,
- const AudioObjectPropertyAddress properties[],
- void *pvUser)
-{
- RT_NOREF(propertyID);
- OSStatus err = noErr;
-
- LogFlowFunc(("propertyID=%u, nAddresses=%u, pvUser=%p\n", propertyID, nAddresses, pvUser));
-
- PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
- AssertPtr(pCbCtx);
- AssertPtr(pCbCtx->pStream);
-
- for (UInt32 idxAddress = 0; idxAddress < nAddresses; idxAddress++)
- {
- const AudioObjectPropertyAddress *pProperty = &properties[idxAddress];
-
- switch (pProperty->mSelector)
- {
- case kAudioHardwarePropertyDefaultInputDevice:
- {
- PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
- AssertPtr(pStreamIn);
-
- /* This listener is called on every change of the hardware
- * device. So check if the default device has really changed. */
- UInt32 uSize = sizeof(pStreamIn->deviceID);
- UInt32 uResp;
- err = AudioObjectGetPropertyData(kAudioObjectSystemObject, pProperty, 0, NULL, &uSize, &uResp);
-
- if (err == noErr)
- {
- if (pStreamIn->deviceID != uResp)
- {
- LogRel(("CoreAudio: Default device for recording has changed\n"));
-
- /* We move the reinitialization to the next input event.
- * This make sure this thread isn't blocked and the
- * reinitialization is done when necessary only. */
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
- }
- }
- break;
- }
-
- case kAudioHardwarePropertyDefaultOutputDevice:
- {
- PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
- AssertPtr(pStreamOut);
-
- /* This listener is called on every change of the hardware
- * device. So check if the default device has really changed. */
- AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice,
- kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
-
- UInt32 uSize = sizeof(pStreamOut->deviceID);
- UInt32 uResp;
- err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdr, 0, NULL, &uSize, &uResp);
-
- if (err == noErr)
- {
- if (pStreamOut->deviceID != uResp)
- {
- LogRel(("CoreAudio: Default device for playback has changed\n"));
-
- /* We move the reinitialization to the next input event.
- * This make sure this thread isn't blocked and the
- * reinitialization is done when necessary only. */
- ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
- }
- }
- break;
- }
-
- default:
- break;
- }
- }
-
- int rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, false /* fIn */, 0 /* fEnum */);
- AssertRC(rc2);
- rc2 = drvHostCoreAudioDevicesEnumerate(pCbCtx->pThis, NULL /* pCfg */, true /* fIn */, 0 /* fEnum */);
- AssertRC(rc2);
-
- /** @todo Implement callback notification here to let the audio connector / device emulation
- * know that something has changed. */
-
- return noErr;
-}
-
-/**
- * Thread for a Core Audio stream's audio queue handling.
- * This thread is required per audio queue to pump data to/from the Core Audio stream and
- * handling its callbacks.
- *
- * @returns IPRT status code.
- * @param hThreadSelf Thread handle.
- * @param pvUser User argument.
- */
-static DECLCALLBACK(int) coreAudioQueueThread(RTTHREAD hThreadSelf, void *pvUser)
-{
- NOREF(hThreadSelf);
-
- PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
- AssertPtr(pCAStream);
-
- LogFunc(("Starting pCAStream=%p\n", pCAStream));
-
- /*
- * Create audio queue.
- */
- OSStatus err;
- if (pCAStream->enmDir == PDMAUDIODIR_IN)
- err = AudioQueueNewInput(&pCAStream->asbdStream, coreAudioInputQueueCb, pCAStream /* pvData */,
- CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
- else
- err = AudioQueueNewOutput(&pCAStream->asbdStream, coreAudioOutputQueueCb, pCAStream /* pvData */,
- CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &pCAStream->audioQueue);
-
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to create audio queue (%RI32)\n", err));
- return VERR_GENERAL_FAILURE; /** @todo Fudge! */
- }
-
- ///@todo: The following code may cause subsequent AudioQueueStart to fail
- // with !dev error (560227702). If we skip it entirely, we end up using the
- // default device, which is what we're doing anyway.
-#if 0
- /*
- * Assign device to queue.
- */
- UInt32 uSize = sizeof(pCAStream->UUID);
- err = AudioQueueSetProperty(pCAStream->audioQueue, kAudioQueueProperty_CurrentDevice, &pCAStream->UUID, uSize);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to set queue device UUID (%d)\n", err));
- return VERR_GENERAL_FAILURE; /** @todo Fudge! */
- }
-#endif
-
- const size_t cbBufSize = AQ_BUF_SIZE; /** @todo Make this configurable! */
-
- /*
- * Allocate audio buffers.
- */
- for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
- {
- err = AudioQueueAllocateBuffer(pCAStream->audioQueue, cbBufSize, &pCAStream->audioBuffer[i]);
- if (err != noErr)
- break;
- }
-
- if (err != noErr)
- return VERR_GENERAL_FAILURE; /** @todo Fudge! */
-
- /* Signal the main thread before entering the main loop. */
- RTThreadUserSignal(RTThreadSelf());
-
- /*
- * Enter the main loop.
- */
- const bool fIn = pCAStream->enmDir == PDMAUDIODIR_IN;
-
- while (!ASMAtomicReadBool(&pCAStream->fShutdown))
- {
- CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
- }
-
- /*
- * Cleanup.
- */
- if (fIn)
- {
- AudioQueueStop(pCAStream->audioQueue, 1);
- }
- else
- {
- AudioQueueStop(pCAStream->audioQueue, 0);
- }
-
- for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
- {
- if (pCAStream->audioBuffer[i])
- AudioQueueFreeBuffer(pCAStream->audioQueue, pCAStream->audioBuffer[i]);
- }
-
- AudioQueueDispose(pCAStream->audioQueue, 1);
- pCAStream->audioQueue = NULL;
-
- LogFunc(("Ended pCAStream=%p\n", pCAStream));
- return VINF_SUCCESS;
-}
-
-/**
- * Processes input data of an audio queue buffer and stores it into a Core Audio stream.
- *
- * @returns IPRT status code.
- * @param pCAStream Core Audio stream to store input data into.
- * @param audioBuffer Audio buffer to process input data from.
- */
-int coreAudioInputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRef audioBuffer)
-{
- PRTCIRCBUF pCircBuf = pCAStream->pCircBuf;
- AssertPtr(pCircBuf);
-
- UInt8 *pvSrc = (UInt8 *)audioBuffer->mAudioData;
- UInt8 *pvDst = NULL;
-
- size_t cbWritten = 0;
-
- size_t cbToWrite = audioBuffer->mAudioDataByteSize;
- size_t cbLeft = cbToWrite;
-
- while (cbLeft)
- {
- /* Try to acquire the necessary block from the ring buffer. */
- RTCircBufAcquireWriteBlock(pCircBuf, cbLeft, (void **)&pvDst, &cbToWrite);
-
- if (!cbToWrite)
- break;
-
- /* Copy the data from our ring buffer to the core audio buffer. */
- memcpy((UInt8 *)pvDst, pvSrc + cbWritten, cbToWrite);
-
- /* Release the read buffer, so it could be used for new data. */
- RTCircBufReleaseWriteBlock(pCircBuf, cbToWrite);
-
- cbWritten += cbToWrite;
-
- Assert(cbLeft >= cbToWrite);
- cbLeft -= cbToWrite;
- }
-
- Log3Func(("pCAStream=%p, cbBuffer=%RU32/%zu, cbWritten=%zu\n",
- pCAStream, audioBuffer->mAudioDataByteSize, audioBuffer->mAudioDataBytesCapacity, cbWritten));
-
- return VINF_SUCCESS;
-}
-
-/**
- * Input audio queue callback. Called whenever input data from the audio queue becomes available.
- *
- * @param pvUser User argument.
- * @param audioQueue Audio queue to process input data from.
- * @param audioBuffer Audio buffer to process input data from. Must be part of audio queue.
- * @param pAudioTS Audio timestamp.
- * @param cPacketDesc Number of packet descriptors.
- * @param paPacketDesc Array of packet descriptors.
- */
-static DECLCALLBACK(void) coreAudioInputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer,
- const AudioTimeStamp *pAudioTS,
- UInt32 cPacketDesc, const AudioStreamPacketDescription *paPacketDesc)
-{
- NOREF(pAudioTS);
- NOREF(cPacketDesc);
- NOREF(paPacketDesc);
-
- PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
- AssertPtr(pCAStream);
-
- int rc = RTCritSectEnter(&pCAStream->CritSect);
- AssertRC(rc);
-
- rc = coreAudioInputQueueProcBuffer(pCAStream, audioBuffer);
- if (RT_SUCCESS(rc))
- AudioQueueEnqueueBuffer(audioQueue, audioBuffer, 0, NULL);
-
- rc = RTCritSectLeave(&pCAStream->CritSect);
- AssertRC(rc);
-}
-
-/**
- * Processes output data of a Core Audio stream into an audio queue buffer.
- *
- * @returns IPRT status code.
- * @param pCAStream Core Audio stream to process output data for.
- * @param audioBuffer Audio buffer to store data into.
- */
-int coreAudioOutputQueueProcBuffer(PCOREAUDIOSTREAM pCAStream, AudioQueueBufferRef audioBuffer)
-{
- PRTCIRCBUF pCircBuf = pCAStream->pCircBuf;
- AssertPtr(pCircBuf);
-
- size_t cbRead = 0;
-
- UInt8 *pvSrc = NULL;
- UInt8 *pvDst = (UInt8 *)audioBuffer->mAudioData;
-
- size_t cbToRead = RT_MIN(RTCircBufUsed(pCircBuf), audioBuffer->mAudioDataBytesCapacity);
- size_t cbLeft = cbToRead;
-
- while (cbLeft)
- {
- /* Try to acquire the necessary block from the ring buffer. */
- RTCircBufAcquireReadBlock(pCircBuf, cbLeft, (void **)&pvSrc, &cbToRead);
-
- if (cbToRead)
- {
- /* Copy the data from our ring buffer to the core audio buffer. */
- memcpy((UInt8 *)pvDst + cbRead, pvSrc, cbToRead);
- }
-
- /* Release the read buffer, so it could be used for new data. */
- RTCircBufReleaseReadBlock(pCircBuf, cbToRead);
-
- if (!cbToRead)
- break;
-
- /* Move offset. */
- cbRead += cbToRead;
- Assert(cbRead <= audioBuffer->mAudioDataBytesCapacity);
-
- Assert(cbToRead <= cbLeft);
- cbLeft -= cbToRead;
- }
-
- audioBuffer->mAudioDataByteSize = cbRead;
-
- if (audioBuffer->mAudioDataByteSize < audioBuffer->mAudioDataBytesCapacity)
- {
- RT_BZERO((UInt8 *)audioBuffer->mAudioData + audioBuffer->mAudioDataByteSize,
- audioBuffer->mAudioDataBytesCapacity - audioBuffer->mAudioDataByteSize);
-
- audioBuffer->mAudioDataByteSize = audioBuffer->mAudioDataBytesCapacity;
- }
-
- Log3Func(("pCAStream=%p, cbCapacity=%RU32, cbRead=%zu\n",
- pCAStream, audioBuffer->mAudioDataBytesCapacity, cbRead));
-
- return VINF_SUCCESS;
-}
-
-/**
- * Output audio queue callback. Called whenever an audio queue is ready to process more output data.
- *
- * @param pvUser User argument.
- * @param audioQueue Audio queue to process output data for.
- * @param audioBuffer Audio buffer to store output data in. Must be part of audio queue.
- */
-static DECLCALLBACK(void) coreAudioOutputQueueCb(void *pvUser, AudioQueueRef audioQueue, AudioQueueBufferRef audioBuffer)
-{
- PCOREAUDIOSTREAM pCAStream = (PCOREAUDIOSTREAM)pvUser;
- AssertPtr(pCAStream);
-
- int rc = RTCritSectEnter(&pCAStream->CritSect);
- AssertRC(rc);
-
- rc = coreAudioOutputQueueProcBuffer(pCAStream, audioBuffer);
- if (RT_SUCCESS(rc))
- AudioQueueEnqueueBuffer(audioQueue, audioBuffer, 0, NULL);
-
- rc = RTCritSectLeave(&pCAStream->CritSect);
- AssertRC(rc);
-}
-
-/**
- * Invalidates a Core Audio stream's audio queue.
- *
- * @returns IPRT status code.
- * @param pCAStream Core Audio stream to invalidate its queue for.
- */
-static int coreAudioStreamInvalidateQueue(PCOREAUDIOSTREAM pCAStream)
-{
- int rc = VINF_SUCCESS;
-
- for (size_t i = 0; i < RT_ELEMENTS(pCAStream->audioBuffer); i++)
- {
- AudioQueueBufferRef pBuf = pCAStream->audioBuffer[i];
-
- if (pCAStream->enmDir == PDMAUDIODIR_IN)
- {
- int rc2 = coreAudioInputQueueProcBuffer(pCAStream, pBuf);
- if (RT_SUCCESS(rc2))
- {
- AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL);
- }
- }
- else if (pCAStream->enmDir == PDMAUDIODIR_OUT)
- {
- int rc2 = coreAudioOutputQueueProcBuffer(pCAStream, pBuf);
- if ( RT_SUCCESS(rc2)
- && pBuf->mAudioDataByteSize)
- {
- AudioQueueEnqueueBuffer(pCAStream->audioQueue, pBuf, 0, NULL);
- }
-
- if (RT_SUCCESS(rc))
- rc = rc2;
- }
- else
- AssertFailed();
- }
-
- return rc;
-}
-
-/**
- * Initializes a Core Audio stream's audio queue.
- *
- * @returns IPRT status code.
- * @param pCAStream Core Audio stream to initialize audio queue for.
- * @param fIn Whether this is an input or output queue.
- * @param pCfgReq Requested stream configuration.
- * @param pCfgAcq Acquired stream configuration on success.
- */
-static int coreAudioStreamInitQueue(PCOREAUDIOSTREAM pCAStream, bool fIn, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- RT_NOREF(pCfgAcq);
- LogFunc(("pCAStream=%p, pCfgReq=%p, pCfgAcq=%p\n", pCAStream, pCfgReq, pCfgAcq));
-
- AudioDeviceID deviceID = kAudioDeviceUnknown;
-
- /* Fetch the default audio device currently in use. */
- AudioObjectPropertyAddress propAdrDefaultDev = { fIn
- ? kAudioHardwarePropertyDefaultInputDevice
- : kAudioHardwarePropertyDefaultOutputDevice,
- kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- UInt32 uSize = sizeof(deviceID);
- OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propAdrDefaultDev, 0, NULL, &uSize, &deviceID);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Unable to determine default %s device (%RI32)\n",
- fIn ? "capturing" : "playback", err));
- return VERR_NOT_FOUND;
- }
-
- /* Get the device UUID. */
- AudioObjectPropertyAddress propAdrDevUUID = { kAudioDevicePropertyDeviceUID,
- fIn ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster };
- uSize = sizeof(pCAStream->UUID);
- err = AudioObjectGetPropertyData(deviceID, &propAdrDevUUID, 0, NULL, &uSize, &pCAStream->UUID);
- if (err != noErr)
- {
- LogRel(("CoreAudio: Failed to retrieve device UUID for device %RU32 (%RI32)\n", deviceID, err));
- return VERR_NOT_FOUND;
- }
-
- /* Create the recording device's out format based on our required audio settings. */
- int rc = drvHostCoreAudioStreamCfgToASBD(pCfgReq, &pCAStream->asbdStream);
- if (RT_FAILURE(rc))
- {
- LogRel(("CoreAudio: Failed to convert requested %s format to native format (%Rrc)\n",
- fIn ? "input" : "output", rc));
- return rc;
- }
-
- pCAStream->enmDir = fIn ? PDMAUDIODIR_IN : PDMAUDIODIR_OUT;
-
- /* Assign device ID. */
- if (fIn)
- {
- AssertPtr(pCAStream->pIn);
- pCAStream->pIn->deviceID = deviceID;
- }
- else
- {
- AssertPtr(pCAStream->pOut);
- pCAStream->pOut->deviceID = deviceID;
- }
-
- drvHostCoreAudioPrintASBD( fIn
- ? "Capturing queue format"
- : "Playback queue format", &pCAStream->asbdStream);
-
- rc = RTCircBufCreate(&pCAStream->pCircBuf, 8096 << 1 /*pHstStrmIn->Props.cShift*/); /** @todo FIX THIS !!! */
- if (RT_FAILURE(rc))
- return rc;
-
- /*
- * Start the thread.
- */
- pCAStream->fShutdown = false;
- rc = RTThreadCreate(&pCAStream->hThread, coreAudioQueueThread,
- pCAStream /* pvUser */, 0 /* Default stack size */,
- RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "CAQUEUE");
- if (RT_SUCCESS(rc))
- rc = RTThreadUserWait(pCAStream->hThread, 10 * 1000 /* 10s timeout */);
-
- LogFunc(("Returning %Rrc\n", rc));
- return rc;
-}
-
-/**
- * Unitializes a Core Audio stream's audio queue.
- *
- * @returns IPRT status code.
- * @param pCAStream Core Audio stream to unitialize audio queue for.
- */
-static int coreAudioStreamUninitQueue(PCOREAUDIOSTREAM pCAStream)
-{
- LogFunc(("pCAStream=%p\n", pCAStream));
-
- int rc;
-
- if (pCAStream->hThread != NIL_RTTHREAD)
- {
- LogFunc(("Waiting for thread ...\n"));
-
- ASMAtomicXchgBool(&pCAStream->fShutdown, true);
-
- int rcThread;
- rc = RTThreadWait(pCAStream->hThread, 30 * 1000, &rcThread);
- if (RT_FAILURE(rc))
- return rc;
-
- NOREF(rcThread);
- LogFunc(("Thread stopped with %Rrc\n", rcThread));
-
- pCAStream->hThread = NIL_RTTHREAD;
- }
-
- if (pCAStream->pCircBuf)
- {
- RTCircBufDestroy(pCAStream->pCircBuf);
- pCAStream->pCircBuf = NULL;
- }
-
- LogFunc(("Returning\n"));
- return VINF_SUCCESS;
-}
-
-#if 0 // unused
-/**
- * Unitializes a Core Audio stream.
- *
- * @returns IPRT status code.
- * @param pCAStream Core Audio stream to uninitialize.
- */
-static int coreAudioStreamUninit(PCOREAUDIOSTREAM pCAStream)
-{
- LogFunc(("pCAStream=%p\n", pCAStream));
-
- int rc = coreAudioStreamUninitQueue(pCAStream);
- return rc;
-}
-#endif
-
-static int drvHostCoreAudioReinitInput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- int rc = drvHostCoreAudioFiniIn(pInterface, pHstStrmIn);
- if (RT_SUCCESS(rc))
- {
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
-
- PDMAUDIOSTREAMCFG CfgAcq;
- rc = drvHostCoreAudioASBDToStreamCfg(&pStreamIn->cbCtx.pStream->asbdStream, &CfgAcq);
- if (RT_SUCCESS(rc))
- {
- int rc2;
- rc2 = RTCritSectInit(&pStreamIn->cbCtx.pStream->CritSect);
- AssertRC(rc2);
-
- rc = coreAudioStreamInitQueue(pStreamIn->cbCtx.pStream, true /* fInput */, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
- if (RT_SUCCESS(rc))
- {
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_INIT);
- rc = drvHostCoreAudioControlIn(pInterface, pHstStrmIn, PDMAUDIOSTREAMCMD_ENABLE);
- }
-
- if (RT_FAILURE(rc))
- {
- rc2 = drvHostCoreAudioFiniIn(pInterface, pHstStrmIn);
- AssertRC(rc2);
- }
- }
- }
-
- if (RT_FAILURE(rc))
- LogRel(("CoreAudio: Unable to re-init input stream: %Rrc\n", rc));
-
- return rc;
-}
-
-static int drvHostCoreAudioReinitOutput(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- int rc = drvHostCoreAudioFiniOut(pInterface, pHstStrmOut);
- if (RT_SUCCESS(rc))
- {
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
-
- PDMAUDIOSTREAMCFG CfgAcq;
- rc = drvHostCoreAudioASBDToStreamCfg(&pStreamOut->cbCtx.pStream->asbdStream, &CfgAcq);
- if (RT_SUCCESS(rc))
- {
- int rc2;
- rc2 = RTCritSectInit(&pStreamOut->cbCtx.pStream->CritSect);
- AssertRC(rc2);
-
- rc = coreAudioStreamInitQueue(pStreamOut->cbCtx.pStream, false /* fInput */, &CfgAcq /* pCfgReq */, NULL /* pCfgAcq */);
- if (RT_SUCCESS(rc))
- {
- ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_INIT);
- rc = drvHostCoreAudioControlOut(pInterface, pHstStrmOut, PDMAUDIOSTREAMCMD_ENABLE);
- }
-
- if (RT_FAILURE(rc))
- {
- rc2 = drvHostCoreAudioFiniOut(pInterface, pHstStrmOut);
- AssertRC(rc2);
- }
- }
- }
-
- if (RT_FAILURE(rc))
- LogRel(("CoreAudio: Unable to re-init output stream: %Rrc\n", rc));
-
- return rc;
-}
-
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
-/* Callback to convert audio input data from one format to another. */
-static DECLCALLBACK(OSStatus) drvHostCoreAudioConverterCb(AudioConverterRef inAudioConverter,
- UInt32 *ioNumberDataPackets,
- AudioBufferList *ioData,
- AudioStreamPacketDescription **ppASPD,
- void *pvUser)
-{
- RT_NOREF(inAudioConverter);
- AssertPtrReturn(ioNumberDataPackets, caConverterEOFDErr);
- AssertPtrReturn(ioData, caConverterEOFDErr);
-
- PCOREAUDIOCONVCBCTX pConvCbCtx = (PCOREAUDIOCONVCBCTX)pvUser;
- AssertPtr(pConvCbCtx);
-
- /* Initialize values. */
- ioData->mBuffers[0].mNumberChannels = 0;
- ioData->mBuffers[0].mDataByteSize = 0;
- ioData->mBuffers[0].mData = NULL;
-
- if (ppASPD)
- {
- Log3Func(("Handling packet description not implemented\n"));
- }
- else
- {
- /** @todo Check converter ID? */
-
- /** @todo Handled non-interleaved data by going through the full buffer list,
- * not only through the first buffer like we do now. */
- Log3Func(("ioNumberDataPackets=%RU32\n", *ioNumberDataPackets));
-
- UInt32 cNumberDataPackets = *ioNumberDataPackets;
- Assert(pConvCbCtx->uPacketIdx + cNumberDataPackets <= pConvCbCtx->uPacketCnt);
-
- if (cNumberDataPackets)
- {
- AssertPtr(pConvCbCtx->pBufLstSrc);
- Assert(pConvCbCtx->pBufLstSrc->mNumberBuffers == 1); /* Only one buffer for the source supported atm. */
-
- AudioStreamBasicDescription *pSrcASBD = &pConvCbCtx->asbdSrc;
- AudioBuffer *pSrcBuf = &pConvCbCtx->pBufLstSrc->mBuffers[0];
-
- size_t cbOff = pConvCbCtx->uPacketIdx * pSrcASBD->mBytesPerPacket;
-
- cNumberDataPackets = RT_MIN((pSrcBuf->mDataByteSize - cbOff) / pSrcASBD->mBytesPerPacket,
- cNumberDataPackets);
-
- void *pvAvail = (uint8_t *)pSrcBuf->mData + cbOff;
- size_t cbAvail = RT_MIN(pSrcBuf->mDataByteSize - cbOff, cNumberDataPackets * pSrcASBD->mBytesPerPacket);
-
- Log3Func(("cNumberDataPackets=%RU32, cbOff=%zu, cbAvail=%zu\n", cNumberDataPackets, cbOff, cbAvail));
-
- /* Set input data for the converter to use.
- * Note: For VBR (Variable Bit Rates) or interleaved data handling we need multiple buffers here. */
- ioData->mNumberBuffers = 1;
-
- ioData->mBuffers[0].mNumberChannels = pSrcBuf->mNumberChannels;
- ioData->mBuffers[0].mDataByteSize = cbAvail;
- ioData->mBuffers[0].mData = pvAvail;
-
-#ifdef DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- int rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-converter-cb-input.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- if (RT_SUCCESS(rc))
- {
- RTFileWrite(fh, pvAvail, cbAvail, NULL);
- RTFileClose(fh);
- }
- else
- AssertFailed();
-#endif
- pConvCbCtx->uPacketIdx += cNumberDataPackets;
- Assert(pConvCbCtx->uPacketIdx <= pConvCbCtx->uPacketCnt);
-
- *ioNumberDataPackets = cNumberDataPackets;
- }
- }
-
- Log3Func(("%RU32 / %RU32 -> ioNumberDataPackets=%RU32\n",
- pConvCbCtx->uPacketIdx, pConvCbCtx->uPacketCnt, *ioNumberDataPackets));
-
- return noErr;
-}
-#endif /* VBOX_WITH_AUDIO_CA_CONVERTER */
-
-
-/* Callback for getting notified when some of the properties of an audio device have changed. */
-static DECLCALLBACK(OSStatus) drvHostCoreAudioDevPropChgCb(AudioObjectID propertyID,
- UInt32 cAddresses,
- const AudioObjectPropertyAddress properties[],
- void *pvUser)
-{
- RT_NOREF(cAddresses, properties);
- PCOREAUDIOSTREAMCBCTX pCbCtx = (PCOREAUDIOSTREAMCBCTX)pvUser;
- AssertPtr(pCbCtx);
- AssertPtr(pCbCtx->pStream);
-
- LogFlowFunc(("propertyID=%u, nAddresses=%u, pCbCtx=%p\n", propertyID, cAddresses, pCbCtx));
-
- if (pCbCtx->pStream->enmDir == PDMAUDIODIR_IN)
- {
- PCOREAUDIOSTREAMIN pStreamIn = pCbCtx->pStream->pIn;
- AssertPtr(pStreamIn);
-
- switch (propertyID)
- {
-#ifdef DEBUG
- case kAudioDeviceProcessorOverload:
- {
- LogFunc(("Processor overload detected!\n"));
- break;
- }
-#endif /* DEBUG */
- case kAudioDevicePropertyNominalSampleRate:
- {
- LogRel2(("CoreAudio: Recording sample rate changed\n"));
-
- /* We move the reinitialization to the next input event.
- * This make sure this thread isn't blocked and the
- * reinitialization is done when necessary only. */
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_REINIT);
- break;
- }
-
- default:
- break;
- }
- }
- else
- {
- PCOREAUDIOSTREAMOUT pStreamOut = pCbCtx->pStream->pOut;
- AssertPtr(pStreamOut);
-
- switch (propertyID)
- {
- case kAudioDevicePropertyNominalSampleRate:
- {
- LogRel2(("CoreAudio: Playback sample rate changed\n"));
-
- /* We move the reinitialization to the next input event.
- * This make sure this thread isn't blocked and the
- * reinitialization is done when necessary only. */
- ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_REINIT);
- break;
- }
-
- default:
- break;
- }
- }
-
- return noErr;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioInit(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-
- LogFlowFuncEnter();
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- uint32_t *pcSamplesCaptured)
-{
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
-
- /* Check if the audio device should be reinitialized. If so do it. */
- if (ASMAtomicReadU32(&pStreamIn->status) == CA_STATUS_REINIT)
- drvHostCoreAudioReinitInput(pInterface, &pStreamIn->streamIn);
-
- if (ASMAtomicReadU32(&pStreamIn->status) != CA_STATUS_INIT)
- {
- if (pcSamplesCaptured)
- *pcSamplesCaptured = 0;
- return VINF_SUCCESS;
- }
-
- PRTCIRCBUF pCircBuf = NULL;
- pCircBuf = pStreamIn->cbCtx.pStream->pCircBuf;
- AssertPtr(pCircBuf);
-
- int rc = VINF_SUCCESS;
- uint32_t cbWrittenTotal = 0;
-
- do
- {
- size_t cbBuf = AudioMixBufSizeBytes(&pHstStrmIn->MixBuf);
- size_t cbToWrite = RT_MIN(cbBuf, RTCircBufUsed(pCircBuf));
-
- uint32_t cWritten, cbWritten;
- uint8_t *puBuf;
- size_t cbToRead;
-
- Log3Func(("cbBuf=%zu, cbToWrite=%zu/%zu\n", cbBuf, cbToWrite, RTCircBufSize(pCircBuf)));
-
- while (cbToWrite)
- {
- /* Try to acquire the necessary block from the ring buffer. */
- RTCircBufAcquireReadBlock(pCircBuf, cbToWrite, (void **)&puBuf, &cbToRead);
-
- if (cbToRead)
- {
-#ifdef DEBUG_DUMP_PCM_DATA
- RTFILE fh;
- rc = RTFileOpen(&fh, DEBUG_DUMP_PCM_DATA_PATH "ca-capture.pcm",
- RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
- if (RT_SUCCESS(rc))
- {
- RTFileWrite(fh, puBuf + cbWrittenTotal, cbToRead, NULL);
- RTFileClose(fh);
- }
- else
- AssertFailed();
-#endif
- rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf, puBuf, cbToRead, &cWritten);
- }
-
- /* Release the read buffer, so it could be used for new data. */
- RTCircBufReleaseReadBlock(pCircBuf, cbToRead);
-
- if ( RT_FAILURE(rc)
- || !cWritten)
- {
- break;
- }
-
- cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
-
- Assert(cbToWrite >= cbWritten);
- cbToWrite -= cbWritten;
- cbWrittenTotal += cbWritten;
- }
-
- Log3Func(("cbToWrite=%zu, cbToRead=%zu, cbWrittenTotal=%RU32, rc=%Rrc\n", cbToWrite, cbToRead, cbWrittenTotal, rc));
- }
- while (0);
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cCaptured = 0;
- uint32_t cWrittenTotal = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cbWrittenTotal);
- if (cWrittenTotal)
- rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal, &cCaptured);
-
- Log3Func(("cWrittenTotal=%RU32 (%RU32 bytes), cCaptured=%RU32, rc=%Rrc\n", cWrittenTotal, cbWrittenTotal, cCaptured, rc));
-
- if (cCaptured)
- LogFlowFunc(("%RU32 samples captured\n", cCaptured));
-
- if (pcSamplesCaptured)
- *pcSamplesCaptured = cCaptured;
- }
-
- if (RT_FAILURE(rc))
- LogFunc(("Failed with rc=%Rrc\n", rc));
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- uint32_t *pcSamplesPlayed)
-{
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
-
- int rc = VINF_SUCCESS;
-
- /* Check if the audio device should be reinitialized. If so do it. */
- if (ASMAtomicReadU32(&pStreamOut->status) == CA_STATUS_REINIT)
- {
- rc = drvHostCoreAudioReinitOutput(pInterface, &pStreamOut->streamOut);
- if (RT_FAILURE(rc))
- return rc;
- }
-
- uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
- if (!cLive) /* Not samples to play? Bail out. */
- {
- if (pcSamplesPlayed)
- *pcSamplesPlayed = 0;
- return VINF_SUCCESS;
- }
-
- PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
- AssertPtr(pCAStream);
-
- PRTCIRCBUF pCircBuf = NULL;
- pCircBuf = pCAStream->pCircBuf;
- AssertPtr(pCircBuf);
-
- size_t cbLive = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cLive);
-
- uint32_t cbReadTotal = 0;
-
- size_t cbToRead = RT_MIN(cbLive, RTCircBufFree(pCircBuf));
- Log3Func(("cbLive=%zu, cbToRead=%zu\n", cbLive, cbToRead));
-
- uint8_t *pvChunk;
- size_t cbChunk;
-
- while (cbToRead)
- {
- uint32_t cRead, cbRead;
-
- /* Try to acquire the necessary space from the ring buffer. */
- RTCircBufAcquireWriteBlock(pCircBuf, cbToRead, (void **)&pvChunk, &cbChunk);
- if (!cbChunk)
- {
- RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
- break;
- }
-
- Assert(cbChunk <= cbToRead);
-
- rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pvChunk, cbChunk, &cRead);
-
- cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
-
- /* Release the ring buffer, so the read thread could start reading this data. */
- RTCircBufReleaseWriteBlock(pCircBuf, cbChunk);
-
- if (RT_FAILURE(rc))
- break;
-
- Assert(cbToRead >= cbRead);
- cbToRead -= cbRead;
- cbReadTotal += cbRead;
- }
-
- if ( RT_SUCCESS(rc)
- && pCAStream->fRun
- && !pCAStream->fIsRunning)
- {
- rc = coreAudioStreamInvalidateQueue(pCAStream);
- if (RT_SUCCESS(rc))
- {
- AudioQueueStart(pCAStream->audioQueue, NULL);
- pCAStream->fRun = false;
- pCAStream->fIsRunning = true;
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
- if (cReadTotal)
- AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
-
- Log3Func(("cReadTotal=%RU32 (%RU32 bytes)\n", cReadTotal, cbReadTotal));
-
- if (pcSamplesPlayed)
- *pcSamplesPlayed = cReadTotal;
- }
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- RT_NOREF(pInterface);
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
-
- LogFlowFunc(("enmStreamCmd=%RU32\n", enmStreamCmd));
-
- uint32_t uStatus = ASMAtomicReadU32(&pStreamOut->status);
- if (!( uStatus == CA_STATUS_INIT
- || uStatus == CA_STATUS_REINIT))
- {
- return VINF_SUCCESS;
- }
-
- int rc = VINF_SUCCESS;
-
- PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
- AssertPtr(pCAStream);
-
- OSStatus err; RT_NOREF(err);
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- LogFunc(("Queue enable\n"));
- rc = coreAudioStreamInvalidateQueue(pCAStream);
- if (RT_SUCCESS(rc))
- {
- /* Start the audio queue immediately. */
- AudioQueueStart(pCAStream->audioQueue, NULL);
- }
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- {
- LogFunc(("Queue disable\n"));
- AudioQueueStop(pCAStream->audioQueue, 1 /* Immediately */);
- ASMAtomicXchgBool(&pCAStream->fRun, false);
- ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
- break;
- }
-
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- LogFunc(("Queue pause\n"));
- AudioQueuePause(pCAStream->audioQueue);
- ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
- break;
- }
-
- default:
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- RT_NOREF(pInterface);
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
-
- LogFlowFunc(("enmStreamCmd=%RU32\n", enmStreamCmd));
-
- uint32_t uStatus = ASMAtomicReadU32(&pStreamIn->status);
- if (!( uStatus == CA_STATUS_INIT
- || uStatus == CA_STATUS_REINIT))
- {
- return VINF_SUCCESS;
- }
-
- int rc = VINF_SUCCESS;
-
- PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
- AssertPtr(pCAStream);
-
- OSStatus err; RT_NOREF(err);
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- LogFunc(("Queue enable\n"));
- rc = coreAudioStreamInvalidateQueue(pCAStream);
- if (RT_SUCCESS(rc))
- {
- /* Start the audio queue immediately. */
- AudioQueueStart(pCAStream->audioQueue, NULL);
- }
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- {
- LogFunc(("Queue disable\n"));
- AudioQueueStop(pCAStream->audioQueue, 1 /* Immediately */);
- ASMAtomicXchgBool(&pCAStream->fRun, false);
- ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
- break;
- }
-
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- LogFunc(("Queue pause\n"));
- AudioQueuePause(pCAStream->audioQueue);
- ASMAtomicXchgBool(&pCAStream->fIsRunning, false);
- break;
- }
-
- default:
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN) pHstStrmIn;
-
- LogFlowFuncEnter();
-
- uint32_t status = ASMAtomicReadU32(&pStreamIn->status);
- if (!( status == CA_STATUS_INIT
- || status == CA_STATUS_REINIT))
- {
- return VINF_SUCCESS;
- }
-
- OSStatus err = noErr;
-
- int rc = drvHostCoreAudioControlIn(pInterface, &pStreamIn->streamIn, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- {
- /*
- * Unregister recording device callbacks.
- */
- AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-#ifdef DEBUG
- err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
- drvHostCoreAudioDevPropChgCb, &pStreamIn->cbCtx /* pvUser */);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the recording processor overload listener (%RI32)\n", err));
- }
-#endif /* DEBUG */
-
- propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
- err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr,
- drvHostCoreAudioDevPropChgCb, &pStreamIn->cbCtx /* pvUser */);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the recording sample rate changed listener (%RI32)\n", err));
- }
-
- if (pStreamIn->fDefDevChgListReg)
- {
- propAdr.mSelector = kAudioHardwarePropertyDefaultInputDevice;
- err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
- drvHostCoreAudioDefaultDeviceChangedCb, pStreamIn);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the default recording device changed listener (%RI32)\n", err));
- }
-
- pStreamIn->fDefDevChgListReg = false;
- }
-
- if (pStreamIn->fDevStateChgListReg)
- {
- Assert(pStreamIn->deviceID != kAudioDeviceUnknown);
-
- AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- err = AudioObjectRemovePropertyListener(pStreamIn->deviceID, &propAdr2,
- drvHostCoreAudioDeviceStateChangedCb, &pStreamIn->cbCtx);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the recording device state changed listener (%RI32)\n", err));
- }
-
- pStreamIn->fDevStateChgListReg = false;
- }
-
- if (RT_SUCCESS(rc))
- {
- PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
-
- rc = coreAudioStreamUninitQueue(pCAStream);
- if (RT_FAILURE(rc))
- {
- LogRel(("CoreAudio: Failed to uninit stream queue: %Rrc)\n", rc));
- return rc;
- }
-
- if (RTCritSectIsInitialized(&pCAStream->CritSect))
- RTCritSectDelete(&pCAStream->CritSect);
- }
-
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- if (pStreamIn->ConverterRef)
- {
- AudioConverterDispose(pStreamIn->ConverterRef);
- pStreamIn->ConverterRef = NULL;
- }
-#endif
-
- pStreamIn->deviceID = kAudioDeviceUnknown;
-
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- drvHostCoreAudioUninitConvCbCtx(&pStreamIn->convCbCtx);
-#endif
- if (pStreamIn->pCircBuf)
- {
- RTCircBufDestroy(pStreamIn->pCircBuf);
- pStreamIn->pCircBuf = NULL;
- }
-
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_UNINIT);
- }
- else
- {
- LogRel(("CoreAudio: Failed to stop recording on uninit (%RI32)\n", err));
- rc = VERR_GENERAL_FAILURE; /** @todo Fudge! */
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
-
- LogFlowFuncEnter();
-
- uint32_t status = ASMAtomicReadU32(&pStreamOut->status);
- if (!( status == CA_STATUS_INIT
- || status == CA_STATUS_REINIT))
- {
- return VINF_SUCCESS;
- }
-
- int rc = drvHostCoreAudioControlOut(pInterface, &pStreamOut->streamOut, PDMAUDIOSTREAMCMD_DISABLE);
- if (RT_SUCCESS(rc))
- {
- OSStatus err;
-
- /*
- * Unregister playback device callbacks.
- */
- AudioObjectPropertyAddress propAdr = { kAudioDeviceProcessorOverload, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-#ifdef DEBUG
- err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
- drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the playback processor overload listener (%RI32)\n", err));
- }
-#endif /* DEBUG */
-
- propAdr.mSelector = kAudioDevicePropertyNominalSampleRate;
- err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr,
- drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the playback sample rate changed listener (%RI32)\n", err));
- }
-
- if (pStreamOut->fDefDevChgListReg)
- {
- propAdr.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
- propAdr.mScope = kAudioObjectPropertyScopeGlobal;
- propAdr.mElement = kAudioObjectPropertyElementMaster;
- err = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &propAdr,
- drvHostCoreAudioDevPropChgCb, &pStreamOut->cbCtx /* pvUser */);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the default playback device changed listener (%RI32)\n", err));
- }
-
- pStreamOut->fDefDevChgListReg = false;
- }
-
- if (pStreamOut->fDevStateChgListReg)
- {
- Assert(pStreamOut->deviceID != kAudioDeviceUnknown);
-
- AudioObjectPropertyAddress propAdr2 = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- err = AudioObjectRemovePropertyListener(pStreamOut->deviceID, &propAdr2,
- drvHostCoreAudioDeviceStateChangedCb, &pStreamOut->cbCtx);
- if ( err != noErr
- && err != kAudioHardwareBadObjectError)
- {
- LogRel(("CoreAudio: Failed to remove the playback device state changed listener (%RI32)\n", err));
- }
-
- pStreamOut->fDevStateChgListReg = false;
- }
-
- if (RT_SUCCESS(rc))
- {
- PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
-
- rc = coreAudioStreamUninitQueue(pCAStream);
- if (RT_FAILURE(rc))
- {
- LogRel(("CoreAudio: Failed to uninit stream queue: %Rrc)\n", rc));
- return rc;
- }
-
- if (RTCritSectIsInitialized(&pCAStream->CritSect))
- RTCritSectDelete(&pCAStream->CritSect);
- }
-
- pStreamOut->deviceID = kAudioDeviceUnknown;
- if (pStreamOut->pCircBuf)
- {
- RTCircBufDestroy(pStreamOut->pCircBuf);
- pStreamOut->pCircBuf = NULL;
- }
-
- ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_UNINIT);
- }
- else
- LogRel(("CoreAudio: Failed to stop playback on uninit, rc=%Rrc\n", rc));
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioInitIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
-{
- RT_NOREF(enmRecSource);
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
-
- PCOREAUDIOSTREAMIN pStreamIn = (PCOREAUDIOSTREAMIN)pHstStrmIn;
-
- LogFlowFunc(("enmRecSource=%RU32\n", enmRecSource));
-
- pStreamIn->deviceID = kAudioDeviceUnknown;
-#ifdef VBOX_WITH_AUDIO_CA_CONVERTER
- pStreamIn->ConverterRef = NULL;
-#endif
- pStreamIn->pCircBuf = NULL;
- pStreamIn->status = CA_STATUS_UNINIT;
- pStreamIn->fDefDevChgListReg = false;
- pStreamIn->fDevStateChgListReg = false;
-
- /* Set attributes. */
- pStreamIn->Stream.enmDir = PDMAUDIODIR_IN;
- pStreamIn->Stream.pIn = pStreamIn;
-
- /* Set callback context. */
- pStreamIn->cbCtx.pThis = pThis;
- pStreamIn->cbCtx.pStream = &pStreamIn->Stream;
-
- int rc;
-
- PCOREAUDIOSTREAM pCAStream = pStreamIn->cbCtx.pStream;
-
- rc = RTCritSectInit(&pCAStream->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- pCAStream->hThread = NIL_RTTHREAD;
- pCAStream->fRun = false;
- pCAStream->fIsRunning = false;
-
- bool fDeviceByUser = false; /* Do we use a device which was set by the user? */
-#if 0
- /* Try to find the audio device set by the user */
- if (DeviceUID.pszInputDeviceUID)
- {
- pStreamIn->deviceID = drvHostCoreAudioDeviceUIDtoID(DeviceUID.pszInputDeviceUID);
- /* Not fatal */
- if (pStreamIn->deviceID == kAudioDeviceUnknown)
- LogRel(("CoreAudio: Unable to find recording device %s. Falling back to the default audio device. \n", DeviceUID.pszInputDeviceUID));
- else
- fDeviceByUser = true;
- }
-#endif
-
- rc = coreAudioStreamInitQueue(pStreamIn->cbCtx.pStream, true /* fIn */, pCfgReq, pCfgAcq);
- if (RT_SUCCESS(rc))
- {
- *pcSamples = AQ_BUF_SAMPLES;
- }
- if (RT_SUCCESS(rc))
- {
- ASMAtomicXchgU32(&pStreamIn->status, CA_STATUS_INIT);
-
- OSStatus err;
-
- /* When the devices isn't forced by the user, we want default device change notifications. */
- if (!fDeviceByUser)
- {
- if (!pStreamIn->fDefDevChgListReg)
- {
- AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
- drvHostCoreAudioDefaultDeviceChangedCb, &pStreamIn->cbCtx);
- if ( err == noErr
- || err == kAudioHardwareIllegalOperationError)
- {
- pStreamIn->fDefDevChgListReg = true;
- }
- else
- LogRel(("CoreAudio: Failed to add the default recording device changed listener (%RI32)\n", err));
- }
- }
-
- if ( !pStreamIn->fDevStateChgListReg
- && (pStreamIn->deviceID != kAudioDeviceUnknown))
- {
- /* Register callback for being notified if the device stops being alive. */
- AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- err = AudioObjectAddPropertyListener(pStreamIn->deviceID, &propAdr, drvHostCoreAudioDeviceStateChangedCb,
- &pStreamIn->cbCtx);
- if (err == noErr)
- {
- pStreamIn->fDevStateChgListReg = true;
- }
- else
- LogRel(("CoreAudio: Failed to add the recording device state changed listener (%RI32)\n", err));
- }
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioInitOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- uint32_t *pcSamples)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
-
- PCOREAUDIOSTREAMOUT pStreamOut = (PCOREAUDIOSTREAMOUT)pHstStrmOut;
-
- LogFlowFuncEnter();
-
- pStreamOut->deviceID = kAudioDeviceUnknown;
- pStreamOut->pCircBuf = NULL;
- pStreamOut->status = CA_STATUS_UNINIT;
- pStreamOut->fDefDevChgListReg = false;
- pStreamOut->fDevStateChgListReg = false;
-
- /* Set attributes. */
- pStreamOut->Stream.enmDir = PDMAUDIODIR_OUT;
- pStreamOut->Stream.pOut = pStreamOut;
-
- /* Set callback context. */
- pStreamOut->cbCtx.pThis = pThis;
- pStreamOut->cbCtx.pStream = &pStreamOut->Stream;
-
- PCOREAUDIOSTREAM pCAStream = pStreamOut->cbCtx.pStream;
-
- int rc = RTCritSectInit(&pCAStream->CritSect);
- if (RT_FAILURE(rc))
- return rc;
-
- pCAStream->hThread = NIL_RTTHREAD;
- pCAStream->fRun = false;
- pCAStream->fIsRunning = false;
-
- bool fDeviceByUser = false; /* Do we use a device which was set by the user? */
-
-#if 0
- /* Try to find the audio device set by the user. Use
- * export VBOX_COREAUDIO_OUTPUT_DEVICE_UID=AppleHDAEngineOutput:0
- * to set it. */
- if (DeviceUID.pszOutputDeviceUID)
- {
- pStreamOut->audioDeviceId = drvHostCoreAudioDeviceUIDtoID(DeviceUID.pszOutputDeviceUID);
- /* Not fatal */
- if (pStreamOut->audioDeviceId == kAudioDeviceUnknown)
- LogRel(("CoreAudio: Unable to find playback device %s. Falling back to the default audio device. \n", DeviceUID.pszOutputDeviceUID));
- else
- fDeviceByUser = true;
- }
-#endif
-
- rc = coreAudioStreamInitQueue(pStreamOut->cbCtx.pStream, false /* fIn */, pCfgReq, pCfgAcq);
- if (RT_SUCCESS(rc))
- {
- *pcSamples = AQ_BUF_SAMPLES;
- }
- if (RT_SUCCESS(rc))
- {
- ASMAtomicXchgU32(&pStreamOut->status, CA_STATUS_INIT);
-
- OSStatus err;
-
- /* When the devices isn't forced by the user, we want default device change notifications. */
- if (!fDeviceByUser)
- {
- AudioObjectPropertyAddress propAdr = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- err = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &propAdr,
- drvHostCoreAudioDefaultDeviceChangedCb, &pStreamOut->cbCtx);
- if (err == noErr)
- {
- pStreamOut->fDefDevChgListReg = true;
- }
- else
- LogRel(("CoreAudio: Failed to add the default playback device changed listener (%RI32)\n", err));
- }
-
- if ( !pStreamOut->fDevStateChgListReg
- && (pStreamOut->deviceID != kAudioDeviceUnknown))
- {
- /* Register callback for being notified if the device stops being alive. */
- AudioObjectPropertyAddress propAdr = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- err = AudioObjectAddPropertyListener(pStreamOut->deviceID, &propAdr, drvHostCoreAudioDeviceStateChangedCb,
- (void *)&pStreamOut->cbCtx);
- if (err == noErr)
- {
- pStreamOut->fDevStateChgListReg = true;
- }
- else
- LogRel(("CoreAudio: Failed to add the playback device state changed listener (%RI32)\n", err));
- }
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(bool) drvHostCoreAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- NOREF(pInterface);
- NOREF(enmDir);
- return true; /* Always all enabled. */
-}
-
-static DECLCALLBACK(int) drvHostCoreAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
-
- return coreAudioUpdateStatusInternalEx(pThis, pCfg, 0 /* fEnum */);
-}
-
-static DECLCALLBACK(void) drvHostCoreAudioShutdown(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-}
-
-static DECLCALLBACK(void *) drvHostCoreAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
-
- return NULL;
-}
-
- /* Construct a DirectSound Audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvHostCoreAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(pCfg, fFlags);
- PDRVHOSTCOREAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTCOREAUDIO);
- LogRel(("Audio: Initializing Core Audio driver\n"));
-
- /*
- * Init the static parts.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvHostCoreAudioQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostCoreAudio);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Char driver registration record.
- */
-const PDMDRVREG g_DrvHostCoreAudio =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "CoreAudio",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Core Audio host driver",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVHOSTCOREAUDIO),
- /* pfnConstruct */
- drvHostCoreAudioConstruct,
- /* pfnDestruct */
- NULL,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
-
diff --git a/src/VBox/Devices/Audio_50/DrvHostDSound.cpp b/src/VBox/Devices/Audio_50/DrvHostDSound.cpp
deleted file mode 100644
index 150cccb..0000000
--- a/src/VBox/Devices/Audio_50/DrvHostDSound.cpp
+++ /dev/null
@@ -1,2302 +0,0 @@
-/* $Id: DrvHostDSound.cpp $ */
-/** @file
- * Windows host backend driver using DirectSound.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- *
- */
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <VBox/log.h>
-
-#include <iprt/win/windows.h>
-#include <dsound.h>
-
-#include <iprt/alloc.h>
-#include <iprt/uuid.h>
-
-#include "AudioMixBuffer.h"
-#include "DrvAudio.h"
-#include "VBoxDD.h"
-
-/*
- * IDirectSound* interface uses HRESULT status codes and the driver callbacks use
- * the IPRT status codes. To minimize HRESULT->IPRT conversion most internal functions
- * in the driver return HRESULT and conversion is done in the driver callbacks.
- *
- * Naming convention:
- * 'dsound*' functions return IPRT status code;
- * 'directSound*' - return HRESULT.
- */
-
-/*
- * Optional release logging, which a user can turn on with the
- * 'VBoxManage debugvm' command.
- * Debug logging still uses the common Log* macros from IPRT.
- * Messages which always should go to the release log use LogRel.
- */
-/* General code behavior. */
-#define DSLOG(a) do { LogRel2(a); } while(0)
-/* Something which produce a lot of logging during playback/recording. */
-#define DSLOGF(a) do { LogRel3(a); } while(0)
-/* Important messages like errors. Limited in the default release log to avoid log flood. */
-#define DSLOGREL(a) \
- do { \
- static int8_t scLogged = 0; \
- if (scLogged < 8) { \
- ++scLogged; \
- LogRel(a); \
- } \
- else { \
- DSLOG(a); \
- } \
- } while (0)
-
-/* Dynamically load dsound.dll. */
-typedef HRESULT WINAPI FNDIRECTSOUNDENUMERATEW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext);
-typedef FNDIRECTSOUNDENUMERATEW *PFNDIRECTSOUNDENUMERATEW;
-typedef HRESULT WINAPI FNDIRECTSOUNDCAPTUREENUMERATEW(LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext);
-typedef FNDIRECTSOUNDCAPTUREENUMERATEW *PFNDIRECTSOUNDCAPTUREENUMERATEW;
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
-# define VBOX_DSOUND_MAX_EVENTS 3
-
-typedef enum DSOUNDEVENT
-{
- DSOUNDEVENT_NOTIFY = 0,
- DSOUNDEVENT_INPUT,
- DSOUNDEVENT_OUTPUT,
- } DSOUNDEVENT;
-#endif /* VBOX_WITH_AUDIO_CALLBACKS */
-
-typedef struct DSOUNDHOSTCFG
-{
- DWORD cbBufferIn;
- DWORD cbBufferOut;
- RTUUID uuidPlay;
- LPCGUID pGuidPlay;
- RTUUID uuidCapture;
- LPCGUID pGuidCapture;
-} DSOUNDHOSTCFG, *PDSOUNDHOSTCFG;
-
-typedef struct DSOUNDSTREAMOUT
-{
- PDMAUDIOHSTSTRMOUT strmOut; /* Always must come first! */
- LPDIRECTSOUND8 pDS;
- LPDIRECTSOUNDBUFFER8 pDSB;
- DWORD cbPlayWritePos;
- DWORD csPlaybackBufferSize;
- bool fEnabled;
- bool fRestartPlayback;
- PDMAUDIOSTREAMCFG streamCfg;
-} DSOUNDSTREAMOUT, *PDSOUNDSTREAMOUT;
-
-typedef struct DSOUNDSTREAMIN
-{
- PDMAUDIOHSTSTRMIN strmIn; /* Always must come first! */
- LPDIRECTSOUNDCAPTURE8 pDSC;
- LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB;
- DWORD csCaptureReadPos;
- DWORD csCaptureBufferSize;
- HRESULT hrLastCaptureIn;
- PDMAUDIORECSOURCE enmRecSource;
- bool fEnabled;
- PDMAUDIOSTREAMCFG streamCfg;
-} DSOUNDSTREAMIN, *PDSOUNDSTREAMIN;
-
-typedef struct DRVHOSTDSOUND
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Our audio host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
- /** List of found host input devices. */
- RTLISTANCHOR lstDevInput;
- /** List of found host output devices. */
- RTLISTANCHOR lstDevOutput;
- /** DirectSound configuration options. */
- DSOUNDHOSTCFG cfg;
- /** Whether this backend supports any audio input. */
- bool fEnabledIn;
- /** Whether this backend supports any audio output. */
- bool fEnabledOut;
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- /** Pointer to the audio connector interface of the driver/device above us. */
- PPDMIAUDIOCONNECTOR pUpIAudioConnector;
- /** Stopped indicator. */
- bool fStopped;
- /** Shutdown indicator. */
- bool fShutdown;
- /** Notification thread. */
- RTTHREAD Thread;
- /** Array of events to wait for in notification thread. */
- HANDLE aEvents[VBOX_DSOUND_MAX_EVENTS];
- /** Number of events to wait for in notification thread.
- * Must not exceed VBOX_DSOUND_MAX_EVENTS. */
- uint8_t cEvents;
- /** Pointer to the input stream. */
- PDSOUNDSTREAMIN pDSStrmIn;
- /** Pointer to the output stream. */
- PDSOUNDSTREAMOUT pDSStrmOut;
-#endif
-} DRVHOSTDSOUND, *PDRVHOSTDSOUND;
-
-/** No flags specified. */
-#define DSOUNDENUMCBFLAGS_NONE 0
-/** (Release) log found devices. */
-#define DSOUNDENUMCBFLAGS_LOG RT_BIT(0)
-
-/**
- * Callback context for enumeration callbacks
- */
-typedef struct DSOUNDENUMCBCTX
-{
- PDRVHOSTDSOUND pDrv;
- PPDMAUDIOBACKENDCFG pCfg;
- /** Enumeration flags. */
- uint32_t fFlags;
-} DSOUNDENUMCBCTX, *PDSOUNDENUMCBCTX;
-
-typedef struct DSOUNDDEV
-{
- RTLISTNODE Node;
- char *pszName;
- GUID Guid;
-} DSOUNDDEV, *PDSOUNDDEV;
-
-/** Maximum number of attempts to restore the sound buffer before giving up. */
-#define DRV_DSOUND_RESTORE_ATTEMPTS_MAX 3
-
-/** Makes DRVHOSTDSOUND out of PDMIHOSTAUDIO. */
-#define PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface) \
- ( (PDRVHOSTDSOUND)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTDSOUND, IHostAudio)) )
-
-static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB);
-
-static void dsoundDeviceRemove(PDSOUNDDEV pDev);
-static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg);
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
-static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown);
-#endif
-
-static DWORD dsoundRingDistance(DWORD offEnd, DWORD offBegin, DWORD cSize)
-{
- return offEnd >= offBegin ? offEnd - offBegin : cSize - offBegin + offEnd;
-}
-
-static int dsoundWaveFmtFromCfg(PPDMAUDIOSTREAMCFG pCfg, PWAVEFORMATEX pFmt)
-{
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
- AssertPtrReturn(pFmt, VERR_INVALID_POINTER);
-
- RT_BZERO(pFmt, sizeof(WAVEFORMATEX));
-
- pFmt->wFormatTag = WAVE_FORMAT_PCM;
- pFmt->nChannels = pCfg->cChannels;
- pFmt->nSamplesPerSec = pCfg->uHz;
- pFmt->nAvgBytesPerSec = pCfg->uHz << (pCfg->cChannels == 2 ? 1: 0);
- pFmt->nBlockAlign = 1 << (pCfg->cChannels == 2 ? 1: 0);
- pFmt->cbSize = 0; /* No extra data specified. */
-
- switch (pCfg->enmFormat)
- {
- case AUD_FMT_S8:
- case AUD_FMT_U8:
- pFmt->wBitsPerSample = 8;
- break;
-
- case AUD_FMT_S16:
- case AUD_FMT_U16:
- pFmt->wBitsPerSample = 16;
- pFmt->nAvgBytesPerSec <<= 1;
- pFmt->nBlockAlign <<= 1;
- break;
-
- case AUD_FMT_S32:
- case AUD_FMT_U32:
- pFmt->wBitsPerSample = 32;
- pFmt->nAvgBytesPerSec <<= 2;
- pFmt->nBlockAlign <<= 2;
- break;
-
- default:
- AssertMsgFailed(("Wave format %ld not supported\n", pCfg->enmFormat));
- return VERR_NOT_SUPPORTED;
- }
-
- return VINF_SUCCESS;
-}
-
-static int dsoundGetPosOut(PDRVHOSTDSOUND pThis,
- PDSOUNDSTREAMOUT pDSoundStrmOut, DWORD *pdwBuffer, DWORD *pdwFree, DWORD *pdwPlayPos)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pDSoundStrmOut, VERR_INVALID_POINTER);
-
- LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStrmOut->pDSB;
- if (!pDSB)
- return VERR_INVALID_POINTER;
-
- DWORD cbBuffer = AUDIOMIXBUF_S2B(&pDSoundStrmOut->strmOut.MixBuf, pDSoundStrmOut->csPlaybackBufferSize);
-
- /* Get the current play position which is used for calculating the free space in the buffer. */
- DWORD cbPlayPos = 0; /* MSC maybe used uninitialized */
- HRESULT hr = E_FAIL; /* MSC maybe used uninitialized */
- for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
- {
- hr = IDirectSoundBuffer8_GetCurrentPosition(pDSB, &cbPlayPos, NULL);
- if ( SUCCEEDED(hr)
- || hr != DSERR_BUFFERLOST) /** @todo: MSDN doesn't state this error for GetCurrentPosition(). */
- {
- break;
- }
- else
- {
- LogFlowFunc(("Getting playing position failed due to lost buffer, restoring ...\n"));
- directSoundPlayRestore(pThis, pDSB);
- }
- }
-
- int rc = VINF_SUCCESS;
-
- if (FAILED(hr))
- {
- if (hr != DSERR_BUFFERLOST) /* Avoid log flooding if the error is still there. */
- DSLOGREL(("DSound: Getting current playback position failed with %Rhrc\n", hr));
- LogFlowFunc(("Failed with %Rhrc\n", hr));
-
- rc = VERR_NOT_AVAILABLE;
- }
- else
- {
- if (pdwBuffer)
- *pdwBuffer = cbBuffer;
-
- if (pdwFree)
- *pdwFree = cbBuffer - dsoundRingDistance(pDSoundStrmOut->cbPlayWritePos, cbPlayPos, cbBuffer);
-
- if (pdwPlayPos)
- *pdwPlayPos = cbPlayPos;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static char *dsoundGUIDToUtf8StrA(LPCGUID lpGUID)
-{
- if (lpGUID)
- {
- LPOLESTR lpOLEStr;
- HRESULT hr = StringFromCLSID(*lpGUID, &lpOLEStr);
- if (SUCCEEDED(hr))
- {
- char *pszGUID;
- int rc = RTUtf16ToUtf8(lpOLEStr, &pszGUID);
- CoTaskMemFree(lpOLEStr);
-
- return RT_SUCCESS(rc) ? pszGUID : NULL;
- }
- }
-
- return RTStrDup("{Default device}");
-}
-
-/**
- * Clears the list of the host's playback + capturing devices.
- *
- * @param pThis Host audio driver instance.
- */
-static void dsoundDevicesClear(PDRVHOSTDSOUND pThis)
-{
- AssertPtrReturnVoid(pThis);
-
- PDSOUNDDEV pDev;
- while (!RTListIsEmpty(&pThis->lstDevInput))
- {
- pDev = RTListGetFirst(&pThis->lstDevInput, DSOUNDDEV, Node);
- dsoundDeviceRemove(pDev);
- }
-
- while (!RTListIsEmpty(&pThis->lstDevOutput))
- {
- pDev = RTListGetFirst(&pThis->lstDevOutput, DSOUNDDEV, Node);
- dsoundDeviceRemove(pDev);
- }
-}
-
-static HRESULT directSoundPlayRestore(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB)
-{
- RT_NOREF(pThis);
- HRESULT hr = IDirectSoundBuffer8_Restore(pDSB);
- if (FAILED(hr))
- DSLOGREL(("DSound: Restoring playback buffer failed with %Rhrc\n", hr));
- return hr;
-}
-
-static HRESULT directSoundPlayUnlock(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB,
- LPVOID pv1, LPVOID pv2,
- DWORD cb1, DWORD cb2)
-{
- RT_NOREF(pThis);
- HRESULT hr = IDirectSoundBuffer8_Unlock(pDSB, pv1, cb1, pv2, cb2);
- if (FAILED(hr))
- DSLOGREL(("DSound: Unlocking playback buffer failed with %Rhrc\n", hr));
- return hr;
-}
-
-static HRESULT directSoundCaptureUnlock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB,
- LPVOID pv1, LPVOID pv2,
- DWORD cb1, DWORD cb2)
-{
- HRESULT hr = IDirectSoundCaptureBuffer8_Unlock(pDSCB, pv1, cb1, pv2, cb2);
- if (FAILED(hr))
- DSLOGREL(("DSound: Unlocking capture buffer failed with %Rhrc\n", hr));
- return hr;
-}
-
-static HRESULT directSoundPlayLock(PDRVHOSTDSOUND pThis,
- LPDIRECTSOUNDBUFFER8 pDSB, PDMPCMPROPS *pProps,
- DWORD dwOffset, DWORD dwBytes,
- LPVOID *ppv1, LPVOID *ppv2,
- DWORD *pcb1, DWORD *pcb2,
- DWORD dwFlags)
-{
- LPVOID pv1 = NULL;
- LPVOID pv2 = NULL;
- DWORD cb1 = 0;
- DWORD cb2 = 0;
-
- HRESULT hr = E_FAIL; /* MSC maybe uninitalized */
- for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
- {
- hr = IDirectSoundBuffer8_Lock(pDSB, dwOffset, dwBytes, &pv1, &cb1, &pv2, &cb2, dwFlags);
- if ( SUCCEEDED(hr)
- || hr != DSERR_BUFFERLOST)
- break;
- else
- {
- LogFlowFunc(("Locking failed due to lost buffer, restoring ...\n"));
- directSoundPlayRestore(pThis, pDSB);
- }
- }
-
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Locking playback buffer failed with %Rhrc\n", hr));
- return hr;
- }
-
- if ( (pv1 && (cb1 & pProps->uAlign))
- || (pv2 && (cb2 & pProps->uAlign)))
- {
- DSLOGREL(("DSound: Locking playback buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
- cb1, cb2, pProps->uAlign));
- directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
- return E_FAIL;
- }
-
- *ppv1 = pv1;
- *ppv2 = pv2;
- *pcb1 = cb1;
- *pcb2 = cb2;
-
- return S_OK;
-}
-
-static HRESULT directSoundCaptureLock(LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB, PPDMPCMPROPS pProps,
- DWORD dwOffset, DWORD dwBytes,
- LPVOID *ppv1, LPVOID *ppv2,
- DWORD *pcb1, DWORD *pcb2,
- DWORD dwFlags)
-{
- LPVOID pv1 = NULL;
- LPVOID pv2 = NULL;
- DWORD cb1 = 0;
- DWORD cb2 = 0;
-
- HRESULT hr = IDirectSoundCaptureBuffer8_Lock(pDSCB, dwOffset, dwBytes,
- &pv1, &cb1, &pv2, &cb2, dwFlags);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Locking capture buffer failed with %Rhrc\n", hr));
- return hr;
- }
-
- if ( (pv1 && (cb1 & pProps->uAlign))
- || (pv2 && (cb2 & pProps->uAlign)))
- {
- DSLOGREL(("DSound: Locking capture buffer returned misaligned buffer: cb1=%RI32, cb2=%RI32 (alignment: %RU32)\n",
- cb1, cb2, pProps->uAlign));
- directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);
- return E_FAIL;
- }
-
- *ppv1 = pv1;
- *ppv2 = pv2;
- *pcb1 = cb1;
- *pcb2 = cb2;
-
- return S_OK;
-}
-
-
-/*
- * DirectSound playback
- */
-
-static void directSoundPlayInterfaceRelease(PDSOUNDSTREAMOUT pDSoundStrmOut)
-{
- if (pDSoundStrmOut->pDS)
- {
- IDirectSound8_Release(pDSoundStrmOut->pDS);
- pDSoundStrmOut->pDS = NULL;
- }
-}
-
-static HRESULT directSoundPlayInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
-{
- if (pDSoundStrmOut->pDS != NULL)
- {
- DSLOG(("DSound: DirectSound instance already exists\n"));
- return S_OK;
- }
-
- HRESULT hr = CoCreateInstance(CLSID_DirectSound8, NULL, CLSCTX_ALL,
- IID_IDirectSound8, (void **)&pDSoundStrmOut->pDS);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Creating playback instance failed with %Rhrc\n", hr));
- }
- else
- {
- hr = IDirectSound8_Initialize(pDSoundStrmOut->pDS, pThis->cfg.pGuidPlay);
- if (SUCCEEDED(hr))
- {
- HWND hWnd = GetDesktopWindow();
- hr = IDirectSound8_SetCooperativeLevel(pDSoundStrmOut->pDS, hWnd, DSSCL_PRIORITY);
- if (FAILED(hr))
- DSLOGREL(("DSound: Setting cooperative level for window %p failed with %Rhrc\n", hWnd, hr));
- }
-
- if (FAILED(hr))
- {
- if (hr == DSERR_NODRIVER) /* Usually means that no playback devices are attached. */
- DSLOGREL(("DSound: DirectSound playback is currently unavailable\n"));
- else
- DSLOGREL(("DSound: DirectSound playback initialization failed with %Rhrc\n", hr));
-
- directSoundPlayInterfaceRelease(pDSoundStrmOut);
- }
- }
-
- return hr;
-}
-
-static HRESULT directSoundPlayClose(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
-{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStrmOut, E_POINTER);
-
- DSLOG(("DSound: Closing playback stream %p, buffer %p\n", pDSoundStrmOut, pDSoundStrmOut->pDSB));
-
- HRESULT hr = S_OK;
-
- if (pDSoundStrmOut->pDSB)
- {
- hr = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
- if (SUCCEEDED(hr))
- {
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- if (pThis->aEvents[DSOUNDEVENT_OUTPUT] != NULL)
- {
- CloseHandle(pThis->aEvents[DSOUNDEVENT_OUTPUT]);
- pThis->aEvents[DSOUNDEVENT_OUTPUT] = NULL;
-
- if (pThis->cEvents)
- pThis->cEvents--;
-
- pThis->pDSStrmOut = NULL;
- }
-
- int rc2 = dsoundNotifyThread(pThis, false /* fShutdown */);
- AssertRC(rc2);
-#endif
- IDirectSoundBuffer8_Release(pDSoundStrmOut->pDSB);
- pDSoundStrmOut->pDSB = NULL;
- }
- else
- DSLOGREL(("DSound: Stop playback stream %p when closing %Rhrc\n", pDSoundStrmOut, hr));
- }
-
- if (SUCCEEDED(hr))
- directSoundPlayInterfaceRelease(pDSoundStrmOut);
-
- return hr;
-}
-
-static HRESULT directSoundPlayOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
-{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStrmOut, E_POINTER);
-
- DSLOG(("DSound: pDSoundStrmOut=%p, cbBufferOut=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
- pDSoundStrmOut,
- pThis->cfg.cbBufferOut,
- pDSoundStrmOut->strmOut.Props.uHz,
- pDSoundStrmOut->strmOut.Props.cChannels,
- pDSoundStrmOut->strmOut.Props.cBits,
- pDSoundStrmOut->strmOut.Props.fSigned));
-
- if (pDSoundStrmOut->pDSB != NULL)
- {
- /* Should not happen but be forgiving. */
- DSLOGREL(("DSound: Playback buffer already exists\n"));
- directSoundPlayClose(pThis, pDSoundStrmOut);
- }
-
- WAVEFORMATEX wfx;
- int rc = dsoundWaveFmtFromCfg(&pDSoundStrmOut->streamCfg, &wfx);
- if (RT_FAILURE(rc))
- return E_INVALIDARG;
-
- HRESULT hr = directSoundPlayInterfaceCreate(pThis, pDSoundStrmOut);
- if (FAILED(hr))
- return hr;
-
- do /* To use breaks. */
- {
- LPDIRECTSOUNDBUFFER pDSB = NULL;
-
- DSBUFFERDESC bd;
- RT_ZERO(bd);
- bd.dwSize = sizeof(bd);
- bd.lpwfxFormat = &wfx;
-
- /*
- * As we reuse our (secondary) buffer for playing out data as it comes in,
- * we're using this buffer as a so-called static buffer.
- *
- * However, as we do not want to use memory on the sound device directly
- * (as most modern audio hardware on the host doesn't have this anyway),
- * we're *not* going to use DSBCAPS_STATIC for that.
- *
- * Instead we're specifying DSBCAPS_LOCSOFTWARE, as this fits the bill
- * of copying own buffer data (from AudioMixBuf) to our secondary's Direct Sound buffer.
- */
- bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE;
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- bd.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;
-#endif
- bd.dwBufferBytes = pThis->cfg.cbBufferOut;
-
- hr = IDirectSound8_CreateSoundBuffer(pDSoundStrmOut->pDS, &bd, &pDSB, NULL);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Creating playback sound buffer failed with %Rhrc\n", hr));
- break;
- }
-
- /* "Upgrade" to IDirectSoundBuffer8 interface. */
- hr = IDirectSoundBuffer_QueryInterface(pDSB, IID_IDirectSoundBuffer8, (LPVOID *)&pDSoundStrmOut->pDSB);
- IDirectSoundBuffer_Release(pDSB);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Querying playback sound buffer interface failed with %Rhrc\n", hr));
- break;
- }
-
- /*
- * Query the actual parameters.
- */
- hr = IDirectSoundBuffer8_GetFormat(pDSoundStrmOut->pDSB, &wfx, sizeof(wfx), NULL);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Getting playback format failed with %Rhrc\n", hr));
- break;
- }
-
- DSBCAPS bc;
- RT_ZERO(bc);
- bc.dwSize = sizeof(bc);
- hr = IDirectSoundBuffer8_GetCaps(pDSoundStrmOut->pDSB, &bc);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Getting playback capabilities failed with %Rhrc\n", hr));
- break;
- }
-
- DSLOG(("DSound: Playback format:\n"
- " dwBufferBytes = %RI32\n"
- " dwFlags = 0x%x\n"
- " wFormatTag = %RI16\n"
- " nChannels = %RI16\n"
- " nSamplesPerSec = %RU32\n"
- " nAvgBytesPerSec = %RU32\n"
- " nBlockAlign = %RI16\n"
- " wBitsPerSample = %RI16\n"
- " cbSize = %RI16\n",
- bc.dwBufferBytes,
- bc.dwFlags,
- wfx.wFormatTag,
- wfx.nChannels,
- wfx.nSamplesPerSec,
- wfx.nAvgBytesPerSec,
- wfx.nBlockAlign,
- wfx.wBitsPerSample,
- wfx.cbSize));
-
- if (bc.dwBufferBytes & pDSoundStrmOut->strmOut.Props.uAlign)
- DSLOGREL(("DSound: Playback capabilities returned misaligned buffer: size %RU32, alignment %RU32\n",
- bc.dwBufferBytes, pDSoundStrmOut->strmOut.Props.uAlign + 1));
-
- if (bc.dwBufferBytes != pThis->cfg.cbBufferOut)
- DSLOGREL(("DSound: Playback buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",
- bc.dwBufferBytes, pThis->cfg.cbBufferOut));
-
- /*
- * Initial state.
- * dsoundPlayStart initializes part of it to make sure that Stop/Start continues with a correct
- * playback buffer position.
- */
- pDSoundStrmOut->csPlaybackBufferSize = bc.dwBufferBytes >> pDSoundStrmOut->strmOut.Props.cShift;
- DSLOG(("DSound: csPlaybackBufferSize=%RU32\n", pDSoundStrmOut->csPlaybackBufferSize));
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- /*
- * Install notification.
- */
- pThis->aEvents[DSOUNDEVENT_OUTPUT] = CreateEvent(NULL /* Security attribute */,
- FALSE /* bManualReset */, FALSE /* bInitialState */,
- NULL /* lpName */);
- if (pThis->aEvents[DSOUNDEVENT_OUTPUT] == NULL)
- {
- hr = HRESULT_FROM_WIN32(GetLastError());
- DSLOGREL(("DSound: CreateEvent for output failed with %Rhrc\n", hr));
- break;
- }
-
- LPDIRECTSOUNDNOTIFY8 pNotify;
- hr = IDirectSoundNotify_QueryInterface(pDSoundStrmOut->pDSB, IID_IDirectSoundNotify8, (LPVOID *)&pNotify);
- if (SUCCEEDED(hr))
- {
- DSBPOSITIONNOTIFY dsBufPosNotify;
- RT_ZERO(dsBufPosNotify);
- dsBufPosNotify.dwOffset = DSBPN_OFFSETSTOP;
- dsBufPosNotify.hEventNotify = pThis->aEvents[DSOUNDEVENT_OUTPUT];
-
- hr = IDirectSoundNotify_SetNotificationPositions(pNotify, 1 /* Count */, &dsBufPosNotify);
- if (FAILED(hr))
- DSLOGREL(("DSound: Setting playback position notification failed with %Rhrc\n", hr));
-
- IDirectSoundNotify_Release(pNotify);
- }
- else
- DSLOGREL(("DSound: Querying interface for position notification failed with %Rhrc\n", hr));
-
- if (FAILED(hr))
- break;
-
- pThis->pDSStrmOut = pDSoundStrmOut;
-
- Assert(pThis->cEvents < VBOX_DSOUND_MAX_EVENTS);
- pThis->cEvents++;
-
- /* Let the thread know. */
- dsoundNotifyThread(pThis, false /* fShutdown */);
-
- /* Trigger the just installed output notification. */
- hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, 0);
-
-#endif /* VBOX_WITH_AUDIO_CALLBACKS */
-
- } while (0);
-
- if (FAILED(hr))
- directSoundPlayClose(pThis, pDSoundStrmOut);
-
- return hr;
-}
-
-static void dsoundPlayClearSamples(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
-{
- AssertPtrReturnVoid(pDSoundStrmOut);
-
- PPDMAUDIOHSTSTRMOUT pStrmOut = &pDSoundStrmOut->strmOut;
-
- LPVOID pv1, pv2;
- DWORD cb1, cb2;
- HRESULT hr = directSoundPlayLock(pThis, pDSoundStrmOut->pDSB, &pDSoundStrmOut->strmOut.Props,
- 0 /* dwOffset */, AUDIOMIXBUF_S2B(&pStrmOut->MixBuf, pDSoundStrmOut->csPlaybackBufferSize),
- &pv1, &pv2, &cb1, &cb2, DSBLOCK_ENTIREBUFFER);
- if (SUCCEEDED(hr))
- {
- DWORD len1 = AUDIOMIXBUF_B2S(&pStrmOut->MixBuf, cb1);
- DWORD len2 = AUDIOMIXBUF_B2S(&pStrmOut->MixBuf, cb2);
-
- if (pv1 && len1)
- DrvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv1, cb1, len1);
-
- if (pv2 && len2)
- DrvAudioClearBuf(&pDSoundStrmOut->strmOut.Props, pv2, cb2, len2);
-
- directSoundPlayUnlock(pThis, pDSoundStrmOut->pDSB, pv1, pv2, cb1, cb2);
- }
-}
-
-static HRESULT directSoundPlayGetStatus(PDRVHOSTDSOUND pThis, LPDIRECTSOUNDBUFFER8 pDSB, DWORD *pdwStatus)
-{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSB, E_POINTER);
- /* pdwStatus is optional. */
-
- DWORD dwStatus = 0;
-
- HRESULT hr = E_FAIL; /* MSC maybe used uninitialized */
- for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
- {
- hr = IDirectSoundBuffer8_GetStatus(pDSB, &dwStatus);
- if ( hr == DSERR_BUFFERLOST
- || ( SUCCEEDED(hr)
- && (dwStatus & DSBSTATUS_BUFFERLOST)))
- {
- LogFlowFunc(("Getting status failed due to lost buffer, restoring ...\n"));
- directSoundPlayRestore(pThis, pDSB);
- }
- else
- break;
- }
-
- if (SUCCEEDED(hr))
- {
- if (pdwStatus)
- *pdwStatus = dwStatus;
- }
- else
- DSLOGREL(("DSound: Retrieving playback status failed with %Rhrc\n", hr));
-
- return hr;
-}
-
-static HRESULT directSoundPlayStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
-{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStrmOut, E_POINTER);
-
- HRESULT hr;
-
- if (pDSoundStrmOut->pDSB != NULL)
- {
- DSLOG(("DSound: Stopping playback\n"));
-
- HRESULT hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
- if (FAILED(hr2))
- {
- hr2 = directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
- if (FAILED(hr2))
- hr2 = IDirectSoundBuffer8_Stop(pDSoundStrmOut->pDSB);
- }
-
- if (FAILED(hr2))
- DSLOG(("DSound: Stopping playback failed with %Rhrc\n", hr2));
-
- hr = S_OK; /* Always report success here. */
- }
- else
- hr = E_UNEXPECTED;
-
- if (SUCCEEDED(hr))
- {
- dsoundPlayClearSamples(pThis, pDSoundStrmOut);
- pDSoundStrmOut->fEnabled = false;
- }
- else
- DSLOGREL(("DSound: Stopping playback failed with %Rhrc\n", hr));
-
- return hr;
-}
-
-static HRESULT directSoundPlayStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMOUT pDSoundStrmOut)
-{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStrmOut, E_POINTER);
-
- HRESULT hr;
- if (pDSoundStrmOut->pDSB != NULL)
- {
- DWORD dwStatus;
- hr = directSoundPlayGetStatus(pThis, pDSoundStrmOut->pDSB, &dwStatus);
- if (SUCCEEDED(hr))
- {
- if (dwStatus & DSBSTATUS_PLAYING)
- {
- DSLOG(("DSound: Already playing\n"));
- }
- else
- {
- dsoundPlayClearSamples(pThis, pDSoundStrmOut);
-
- pDSoundStrmOut->fRestartPlayback = true;
- pDSoundStrmOut->fEnabled = true;
-
- DSLOG(("DSound: Playback started\n"));
-
- /*
- * The actual IDirectSoundBuffer8_Play call will be made in drvHostDSoundPlayOut,
- * because it is necessary to put some samples into the buffer first.
- */
- }
- }
- }
- else
- hr = E_UNEXPECTED;
-
- if (FAILED(hr))
- DSLOGREL(("DSound: Starting playback failed with %Rhrc\n", hr));
-
- return hr;
-}
-
-/*
- * DirectSoundCapture
- */
-
-static LPCGUID dsoundCaptureSelectDevice(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
-{
- AssertPtrReturn(pThis, NULL);
- AssertPtrReturn(pDSoundStrmIn, NULL);
-
- LPCGUID pGUID = pThis->cfg.pGuidCapture;
-
- if (!pGUID)
- {
- PDSOUNDDEV pDev = NULL;
-
- switch (pDSoundStrmIn->enmRecSource)
- {
- case PDMAUDIORECSOURCE_MIC:
- {
- RTListForEach(&pThis->lstDevInput, pDev, DSOUNDDEV, Node)
- {
- if (RTStrIStr(pDev->pszName, "Mic")) /** @todo what is with non en_us windows versions? */
- break;
- }
- if (RTListNodeIsDummy(&pThis->lstDevInput, pDev, DSOUNDDEV, Node))
- pDev = NULL; /* Found nothing. */
-
- break;
- }
-
- case PDMAUDIORECSOURCE_LINE_IN:
- default:
- /* Try opening the default device (NULL). */
- break;
- }
-
- if (pDev)
- {
- DSLOG(("DSound: Guest \"%s\" is using host \"%s\"\n",
- drvAudioRecSourceToString(pDSoundStrmIn->enmRecSource), pDev->pszName));
-
- pGUID = &pDev->Guid;
- }
- }
-
- char *pszGUID = dsoundGUIDToUtf8StrA(pGUID);
- /* This always has to be in the release log. */
- LogRel(("DSound: Guest \"%s\" is using host device with GUID: %s\n",
- drvAudioRecSourceToString(pDSoundStrmIn->enmRecSource), pszGUID? pszGUID: "{?}"));
- RTStrFree(pszGUID);
-
- return pGUID;
-}
-
-static void directSoundCaptureInterfaceRelease(PDSOUNDSTREAMIN pDSoundStrmIn)
-{
- if (pDSoundStrmIn->pDSC)
- {
- LogFlowFuncEnter();
- IDirectSoundCapture_Release(pDSoundStrmIn->pDSC);
- pDSoundStrmIn->pDSC = NULL;
- }
-}
-
-static HRESULT directSoundCaptureInterfaceCreate(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
-{
- if (pDSoundStrmIn->pDSC != NULL)
- {
- DSLOG(("DSound: DirectSoundCapture instance already exists\n"));
- return S_OK;
- }
-
- HRESULT hr = CoCreateInstance(CLSID_DirectSoundCapture8, NULL, CLSCTX_ALL,
- IID_IDirectSoundCapture8, (void **)&pDSoundStrmIn->pDSC);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Creating capture instance failed with %Rhrc\n", hr));
- }
- else
- {
- LPCGUID pGUID = dsoundCaptureSelectDevice(pThis, pDSoundStrmIn);
- hr = IDirectSoundCapture_Initialize(pDSoundStrmIn->pDSC, pGUID);
- if (FAILED(hr))
- {
- if (hr == DSERR_NODRIVER) /* Usually means that no capture devices are attached. */
- DSLOGREL(("DSound: Capture device currently is unavailable\n"));
- else
- DSLOGREL(("DSound: Initializing capturing device failed with %Rhrc\n", hr));
-
- directSoundCaptureInterfaceRelease(pDSoundStrmIn);
- }
- }
-
- LogFlowFunc(("Returning %Rhrc\n", hr));
- return hr;
-}
-
-static HRESULT directSoundCaptureClose(PDSOUNDSTREAMIN pDSoundStrmIn)
-{
- AssertPtrReturn(pDSoundStrmIn, E_POINTER);
-
- DSLOG(("DSound: pDSoundStrmIn=%p, pDSCB=%p\n", pDSoundStrmIn, pDSoundStrmIn->pDSCB));
-
- HRESULT hr = S_OK;
-
- if (pDSoundStrmIn->pDSCB)
- {
- hr = IDirectSoundCaptureBuffer_Stop(pDSoundStrmIn->pDSCB);
- if (SUCCEEDED(hr))
- {
- IDirectSoundCaptureBuffer8_Release(pDSoundStrmIn->pDSCB);
- pDSoundStrmIn->pDSCB = NULL;
- }
- else
- DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
- }
-
- if (SUCCEEDED(hr))
- directSoundCaptureInterfaceRelease(pDSoundStrmIn);
-
- LogFlowFunc(("Returning %Rhrc\n", hr));
- return hr;
-}
-
-static HRESULT directSoundCaptureOpen(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
-{
- AssertPtrReturn(pThis, E_POINTER);
- AssertPtrReturn(pDSoundStrmIn, E_POINTER);
-
- DSLOG(("DSound: pDSoundStrmIn=%p, cbBufferIn=%ld, uHz=%RU32, cChannels=%RU8, cBits=%RU8, fSigned=%RTbool\n",
- pDSoundStrmIn,
- pThis->cfg.cbBufferIn,
- pDSoundStrmIn->strmIn.Props.uHz,
- pDSoundStrmIn->strmIn.Props.cChannels,
- pDSoundStrmIn->strmIn.Props.cBits,
- pDSoundStrmIn->strmIn.Props.fSigned));
-
- if (pDSoundStrmIn->pDSCB != NULL)
- {
- /* Should not happen but be forgiving. */
- DSLOGREL(("DSound: DirectSoundCaptureBuffer already exists\n"));
- directSoundCaptureClose(pDSoundStrmIn);
- }
-
- WAVEFORMATEX wfx;
- int rc = dsoundWaveFmtFromCfg(&pDSoundStrmIn->streamCfg, &wfx);
- if (RT_FAILURE(rc))
- return E_INVALIDARG;
-
- HRESULT hr = directSoundCaptureInterfaceCreate(pThis, pDSoundStrmIn);
- if (FAILED(hr))
- return hr;
-
- do /* To use breaks. */
- {
- LPDIRECTSOUNDCAPTUREBUFFER pDSCB = NULL;
- DSCBUFFERDESC bd;
- RT_ZERO(bd);
- bd.dwSize = sizeof(bd);
- bd.lpwfxFormat = &wfx;
- bd.dwBufferBytes = pThis->cfg.cbBufferIn;
- hr = IDirectSoundCapture_CreateCaptureBuffer(pDSoundStrmIn->pDSC,
- &bd, &pDSCB, NULL);
- if (FAILED(hr))
- {
- if (hr == E_ACCESSDENIED)
- {
- DSLOGREL(("DSound: Capturing input from host not possible, access denied\n"));
- }
- else
- DSLOGREL(("DSound: Creating capture buffer failed with %Rhrc\n", hr));
- break;
- }
-
- hr = IDirectSoundCaptureBuffer_QueryInterface(pDSCB, IID_IDirectSoundCaptureBuffer8, (void **)&pDSoundStrmIn->pDSCB);
- IDirectSoundCaptureBuffer_Release(pDSCB);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Querying interface for capture buffer failed with %Rhrc\n", hr));
- break;
- }
-
- /*
- * Query the actual parameters.
- */
- DWORD cbReadPos = 0;
- hr = IDirectSoundCaptureBuffer8_GetCurrentPosition(pDSoundStrmIn->pDSCB, NULL, &cbReadPos);
- if (FAILED(hr))
- {
- cbReadPos = 0;
- DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
- }
-
- RT_ZERO(wfx);
- hr = IDirectSoundCaptureBuffer8_GetFormat(pDSoundStrmIn->pDSCB, &wfx, sizeof(wfx), NULL);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Getting capture format failed with %Rhrc\n", hr));
- break;
- }
-
- DSCBCAPS bc;
- RT_ZERO(bc);
- bc.dwSize = sizeof(bc);
- hr = IDirectSoundCaptureBuffer8_GetCaps(pDSoundStrmIn->pDSCB, &bc);
- if (FAILED(hr))
- {
- DSLOGREL(("Getting capture capabilities failed with %Rhrc\n", hr));
- break;
- }
-
- DSLOG(("DSound: Capture format:\n"
- " dwBufferBytes = %RI32\n"
- " dwFlags = 0x%x\n"
- " wFormatTag = %RI16\n"
- " nChannels = %RI16\n"
- " nSamplesPerSec = %RU32\n"
- " nAvgBytesPerSec = %RU32\n"
- " nBlockAlign = %RI16\n"
- " wBitsPerSample = %RI16\n"
- " cbSize = %RI16\n",
- bc.dwBufferBytes,
- bc.dwFlags,
- wfx.wFormatTag,
- wfx.nChannels,
- wfx.nSamplesPerSec,
- wfx.nAvgBytesPerSec,
- wfx.nBlockAlign,
- wfx.wBitsPerSample,
- wfx.cbSize));
-
- if (bc.dwBufferBytes & pDSoundStrmIn->strmIn.Props.uAlign)
- DSLOGREL(("DSound: Capture GetCaps returned misaligned buffer: size %RU32, alignment %RU32\n",
- bc.dwBufferBytes, pDSoundStrmIn->strmIn.Props.uAlign + 1));
-
- if (bc.dwBufferBytes != pThis->cfg.cbBufferIn)
- DSLOGREL(("DSound: Capture buffer size mismatched: DirectSound %RU32, requested %RU32 bytes\n",
- bc.dwBufferBytes, pThis->cfg.cbBufferIn));
-
- /* Initial state: reading at the initial capture position, no error. */
- pDSoundStrmIn->csCaptureReadPos = cbReadPos >> pDSoundStrmIn->strmIn.Props.cShift;
- pDSoundStrmIn->csCaptureBufferSize = bc.dwBufferBytes >> pDSoundStrmIn->strmIn.Props.cShift;
- pDSoundStrmIn->hrLastCaptureIn = S_OK;
-
- DSLOG(("DSound: csCaptureReadPos=%RU32, csCaptureBufferSize=%RU32\n",
- pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize));
-
- } while (0);
-
- if (FAILED(hr))
- directSoundCaptureClose(pDSoundStrmIn);
-
- LogFlowFunc(("Returning %Rhrc\n", hr));
- return hr;
-}
-
-static HRESULT directSoundCaptureStop(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
-{
- AssertPtrReturn(pThis , E_POINTER);
- AssertPtrReturn(pDSoundStrmIn, E_POINTER);
-
- NOREF(pThis);
-
- HRESULT hr;
-
- if (pDSoundStrmIn->pDSCB)
- {
- DSLOG(("DSound: Stopping capture\n"));
-
- hr = IDirectSoundCaptureBuffer_Stop(pDSoundStrmIn->pDSCB);
- if (FAILED(hr))
- DSLOGREL(("DSound: Stopping capture buffer failed with %Rhrc\n", hr));
- }
- else
- hr = E_UNEXPECTED;
-
- if (SUCCEEDED(hr))
- pDSoundStrmIn->fEnabled = false;
-
- LogFlowFunc(("Returning %Rhrc\n", hr));
- return hr;
-}
-
-static HRESULT directSoundCaptureStart(PDRVHOSTDSOUND pThis, PDSOUNDSTREAMIN pDSoundStrmIn)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pDSoundStrmIn, VERR_INVALID_POINTER);
-
- HRESULT hr;
- if (pDSoundStrmIn->pDSCB != NULL)
- {
- DWORD dwStatus;
- hr = IDirectSoundCaptureBuffer8_GetStatus(pDSoundStrmIn->pDSCB, &dwStatus);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Retrieving capture status failed with %Rhrc\n", hr));
- }
- else
- {
- if (dwStatus & DSCBSTATUS_CAPTURING)
- {
- DSLOG(("DSound: Already capturing\n"));
- }
- else
- {
- DWORD fFlags = 0;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- fFlags |= DSCBSTART_LOOPING;
-#endif
- DSLOG(("DSound: Starting to capture\n"));
- hr = IDirectSoundCaptureBuffer8_Start(pDSoundStrmIn->pDSCB, fFlags);
- if (FAILED(hr))
- DSLOGREL(("DSound: Starting to capture failed with %Rhrc\n", hr));
- }
- }
- }
- else
- hr = E_UNEXPECTED;
-
- if (SUCCEEDED(hr))
- pDSoundStrmIn->fEnabled = true;
-
- LogFlowFunc(("Returning %Rhrc\n", hr));
- return hr;
-}
-
-static int dsoundDevAdd(PRTLISTANCHOR pList, LPGUID lpGUID,
- LPCWSTR lpwstrDescription, PDSOUNDDEV *ppDev)
-{
- AssertPtrReturn(pList, VERR_INVALID_POINTER);
- AssertPtrReturn(lpGUID, VERR_INVALID_POINTER);
- AssertPtrReturn(lpwstrDescription, VERR_INVALID_POINTER);
-
- PDSOUNDDEV pDev = (PDSOUNDDEV)RTMemAlloc(sizeof(DSOUNDDEV));
- if (!pDev)
- return VERR_NO_MEMORY;
-
- int rc = RTUtf16ToUtf8(lpwstrDescription, &pDev->pszName);
- if (RT_SUCCESS(rc))
- memcpy(&pDev->Guid, lpGUID, sizeof(GUID));
-
- if (RT_SUCCESS(rc))
- RTListAppend(pList, &pDev->Node);
-
- if (ppDev)
- *ppDev = pDev;
-
- return rc;
-}
-
-static void dsoundDeviceRemove(PDSOUNDDEV pDev)
-{
- if (pDev)
- {
- RTStrFree(pDev->pszName);
- pDev->pszName = NULL;
-
- RTListNodeRemove(&pDev->Node);
-
- RTMemFree(pDev);
- }
-}
-
-static void dsoundLogDevice(const char *pszType, LPGUID lpGUID, LPCWSTR lpwstrDescription, LPCWSTR lpwstrModule)
-{
- char *pszGUID = dsoundGUIDToUtf8StrA(lpGUID);
- /* This always has to be in the release log. */
- LogRel(("DSound: %s: GUID: %s [%ls] (Module: %ls)\n",
- pszType, pszGUID? pszGUID: "{?}", lpwstrDescription, lpwstrModule));
- RTStrFree(pszGUID);
-}
-
-static BOOL CALLBACK dsoundDevicesEnumCbPlayback(LPGUID lpGUID, LPCWSTR lpwstrDescription,
- LPCWSTR lpwstrModule, LPVOID lpContext)
-{
- PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
- AssertPtrReturn(pCtx, FALSE);
- AssertPtrReturn(pCtx->pDrv, FALSE);
- AssertPtrReturn(pCtx->pCfg, FALSE);
-
- if (!lpGUID)
- return TRUE;
-
- AssertPtrReturn(lpwstrDescription, FALSE);
- /* Do not care about lpwstrModule. */
-
- if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
- dsoundLogDevice("Output", lpGUID, lpwstrDescription, lpwstrModule);
-
- int rc = dsoundDevAdd(&pCtx->pDrv->lstDevOutput,
- lpGUID, lpwstrDescription, NULL /* ppDev */);
- if (RT_FAILURE(rc))
- return FALSE; /* Abort enumeration. */
-
- pCtx->pCfg->cMaxHstStrmsOut++;
-
- return TRUE;
-}
-
-static BOOL CALLBACK dsoundDevicesEnumCbCapture(LPGUID lpGUID, LPCWSTR lpwstrDescription,
- LPCWSTR lpwstrModule, LPVOID lpContext)
-{
- PDSOUNDENUMCBCTX pCtx = (PDSOUNDENUMCBCTX)lpContext;
- AssertPtrReturn(pCtx, FALSE);
- AssertPtrReturn(pCtx->pDrv, FALSE);
- AssertPtrReturn(pCtx->pCfg, FALSE);
-
- if (!lpGUID)
- return TRUE;
-
- if (pCtx->fFlags & DSOUNDENUMCBFLAGS_LOG)
- dsoundLogDevice("Input", lpGUID, lpwstrDescription, lpwstrModule);
-
- int rc = dsoundDevAdd(&pCtx->pDrv->lstDevInput,
- lpGUID, lpwstrDescription, NULL /* ppDev */);
- if (RT_FAILURE(rc))
- return FALSE; /* Abort enumeration. */
-
- pCtx->pCfg->cMaxHstStrmsIn++;
-
- return TRUE;
-}
-
-/**
- * Does a (Re-)enumeration of the host's playback + capturing devices.
- *
- * @return IPRT status code.
- * @param pThis Host audio driver instance.
- * @param pCfg Where to store the enumeration results.
- * @param fEnum Enumeration flags.
- */
-static int dsoundDevicesEnumerate(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- dsoundDevicesClear(pThis);
-
- pCfg->cMaxHstStrmsOut = 0;
- pCfg->cMaxHstStrmsIn = 0;
-
- RTLDRMOD hDSound = NULL;
- int rc = RTLdrLoadSystem("dsound.dll", true /*fNoUnload*/, &hDSound);
- if (RT_SUCCESS(rc))
- {
- PFNDIRECTSOUNDENUMERATEW pfnDirectSoundEnumerateW = NULL;
- PFNDIRECTSOUNDCAPTUREENUMERATEW pfnDirectSoundCaptureEnumerateW = NULL;
-
- rc = RTLdrGetSymbol(hDSound, "DirectSoundEnumerateW", (void**)&pfnDirectSoundEnumerateW);
- if (RT_SUCCESS(rc))
- rc = RTLdrGetSymbol(hDSound, "DirectSoundCaptureEnumerateW", (void**)&pfnDirectSoundCaptureEnumerateW);
-
- if (RT_SUCCESS(rc))
- {
- DSOUNDENUMCBCTX ctx = { pThis, pCfg, fEnum };
-
- HRESULT hr = pfnDirectSoundEnumerateW(&dsoundDevicesEnumCbPlayback, &ctx);
- if (FAILED(hr))
- LogRel2(("DSound: Error enumerating host playback devices: %Rhrc\n", hr));
-
- hr = pfnDirectSoundCaptureEnumerateW(&dsoundDevicesEnumCbCapture, &ctx);
- if (FAILED(hr))
- LogRel2(("DSound: Error enumerating host capturing devices: %Rhrc\n", hr));
- }
-
- RTLdrClose(hDSound);
- }
- else
- {
- /* No dsound.dll on this system. */
- LogRel2(("DSound: Could not load dsound.dll: %Rrc\n", rc));
- }
-
- return rc;
-}
-
-/**
- * Updates this host driver's internal status, according to the global, overall input/output
- * state and all connected (native) audio streams.
- *
- * @param pThis Host audio driver instance.
- * @param pCfg Where to store the backend configuration. Optional.
- * @param fEnum Enumeration flags.
- */
-void dsoundUpdateStatusInternalEx(PDRVHOSTDSOUND pThis, PPDMAUDIOBACKENDCFG pCfg, uint32_t fEnum)
-{
- AssertPtrReturnVoid(pThis);
- /* pCfg is optional. */
-
- PDMAUDIOBACKENDCFG Cfg;
- RT_ZERO(Cfg);
-
- Cfg.cbStreamOut = sizeof(DSOUNDSTREAMOUT);
- Cfg.cbStreamIn = sizeof(DSOUNDSTREAMIN);
-
- int rc = dsoundDevicesEnumerate(pThis, &Cfg, fEnum);
- AssertRC(rc);
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- if ( pThis->fEnabledOut != RT_BOOL(Cfg.cMaxHstStrmsOut)
- || pThis->fEnabledIn != RT_BOOL(Cfg.cMaxHstStrmsIn))
- {
- /** @todo Use a registered callback to the audio connector (e.g "OnConfigurationChanged") to
- * let the connector know that something has changed within the host backend. */
- }
-#else
- pThis->fEnabledOut = RT_BOOL(Cfg.cMaxHstStrmsOut);
- pThis->fEnabledIn = RT_BOOL(Cfg.cMaxHstStrmsIn);
-#endif
-
- if (pCfg)
- memcpy(pCfg, &Cfg, sizeof(PDMAUDIOBACKENDCFG));
-
- LogFlowFuncLeaveRC(rc);
-}
-
-void dsoundUpdateStatusInternal(PDRVHOSTDSOUND pThis)
-{
- dsoundUpdateStatusInternalEx(pThis, NULL /* pCfg */, 0 /* fEnum */);
-}
-
-/*
- * PDMIHOSTAUDIO
- */
-
-static DECLCALLBACK(int) drvHostDSoundInitOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- uint32_t *pcSamples)
-{
- RT_NOREF(pCfgReq, pCfgAcq);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- /* pcSamples is optional. */
-
- LogFlowFunc(("pHstStrmOut=%p, pCfg=%p\n", pHstStrmOut, pCfgReq));
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
-
- pDSoundStrmOut->streamCfg = *pCfgReq;
- pDSoundStrmOut->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- int rc = DrvAudioStreamCfgToProps(&pDSoundStrmOut->streamCfg, &pDSoundStrmOut->strmOut.Props);
- if (RT_SUCCESS(rc))
- {
- pDSoundStrmOut->pDS = NULL;
- pDSoundStrmOut->pDSB = NULL;
- pDSoundStrmOut->cbPlayWritePos = 0;
- pDSoundStrmOut->fRestartPlayback = true;
- pDSoundStrmOut->csPlaybackBufferSize = 0;
-
- if (pcSamples)
- *pcSamples = pThis->cfg.cbBufferOut >> pHstStrmOut->Props.cShift;
-
- /* Try to open playback in case the device is already there. */
- directSoundPlayOpen(pThis, pDSoundStrmOut);
- }
- else
- {
- RT_ZERO(pDSoundStrmOut->streamCfg);
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostDSoundControlOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- LogFlowFunc(("pHstStrmOut=%p, cmd=%d\n", pHstStrmOut, enmStreamCmd));
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
-
- int rc = VINF_SUCCESS;
-
- HRESULT hr;
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_ENABLE\n"));
- /* Try to start playback. If it fails, then reopen and try again. */
- hr = directSoundPlayStart(pThis, pDSoundStrmOut);
- if (FAILED(hr))
- {
- hr = directSoundPlayClose(pThis, pDSoundStrmOut);
- if (SUCCEEDED(hr))
- hr = directSoundPlayOpen(pThis, pDSoundStrmOut);
- if (SUCCEEDED(hr))
- hr = directSoundPlayStart(pThis, pDSoundStrmOut);
- }
-
- if (FAILED(hr))
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- DSLOG(("DSound: Playback PDMAUDIOSTREAMCMD_DISABLE\n"));
- hr = directSoundPlayStop(pThis, pDSoundStrmOut);
- if (FAILED(hr))
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- default:
- {
- AssertMsgFailed(("Invalid command: %ld\n", enmStreamCmd));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostDSoundPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- uint32_t *pcSamplesPlayed)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- /* pcSamplesPlayed is optional. */
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
-
- int rc = VINF_SUCCESS;
- uint32_t cReadTotal = 0;
-
-#ifdef DEBUG_andy
- LogFlowFuncEnter();
-#endif
-
- do /* to use 'break' */
- {
- DWORD cbBuffer, cbFree, cbPlayPos;
- rc = dsoundGetPosOut(pThis, pDSoundStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
- if (RT_FAILURE(rc))
- break;
-
- /*
- * Check for full buffer, do not allow the cbPlayWritePos to catch cbPlayPos during playback,
- * i.e. always leave a free space for 1 audio sample.
- */
- const DWORD cbSample = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, 1);
- if (cbFree <= cbSample)
- break;
- cbFree -= cbSample;
-
- uint32_t csLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
- uint32_t cbLive = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, csLive);
-
- /* Do not write more than available space in the DirectSound playback buffer. */
- cbLive = RT_MIN(cbFree, cbLive);
-
- cbLive &= ~pHstStrmOut->Props.uAlign;
- if (cbLive == 0 || cbLive > cbBuffer)
- {
- DSLOG(("DSound: cbLive=%RU32, cbBuffer=%ld, cbPlayWritePos=%ld, cbPlayPos=%ld\n",
- cbLive, cbBuffer, pDSoundStrmOut->cbPlayWritePos, cbPlayPos));
- break;
- }
-
- LPDIRECTSOUNDBUFFER8 pDSB = pDSoundStrmOut->pDSB;
- AssertPtr(pDSB);
-
- LPVOID pv1, pv2;
- DWORD cb1, cb2;
- HRESULT hr = directSoundPlayLock(pThis, pDSB, &pHstStrmOut->Props, pDSoundStrmOut->cbPlayWritePos, cbLive,
- &pv1, &pv2, &cb1, &cb2, 0 /* dwFlags */);
- if (FAILED(hr))
- {
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- DWORD len1 = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cb1);
- /*DWORD len2 = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cb2);*/
-
- uint32_t cRead = 0;
-
- if (pv1 && cb1)
- {
- rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pv1, cb1, &cRead);
- if (RT_SUCCESS(rc))
- cReadTotal += cRead;
- }
-
- if ( RT_SUCCESS(rc)
- && cReadTotal == len1
- && pv2 && cb2)
- {
- rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pv2, cb2, &cRead);
- if (RT_SUCCESS(rc))
- cReadTotal += cRead;
- }
-
- directSoundPlayUnlock(pThis, pDSB, pv1, pv2, cb1, cb2);
-
- pDSoundStrmOut->cbPlayWritePos =
- (pDSoundStrmOut->cbPlayWritePos + AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal)) % cbBuffer;
-
- DSLOGF(("DSound: %RU32 (%RU32 samples) out of %RU32%s, buffer write pos %ld, rc=%Rrc\n",
- AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal), cReadTotal, cbLive,
- cbLive != AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cReadTotal) ? " !!!": "",
- pDSoundStrmOut->cbPlayWritePos, rc));
-
- if (cReadTotal)
- {
- AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
- rc = VINF_SUCCESS; /* Played something. */
- }
-
- if (RT_FAILURE(rc))
- break;
-
- if (pDSoundStrmOut->fRestartPlayback)
- {
- /*
- * The playback has been just started.
- * Some samples of the new sound have been copied to the buffer
- * and it can start playing.
- */
- pDSoundStrmOut->fRestartPlayback = false;
-
- DWORD fFlags = 0;
-#ifndef VBOX_WITH_AUDIO_CALLBACKS
- fFlags |= DSCBSTART_LOOPING;
-#endif
- for (unsigned i = 0; i < DRV_DSOUND_RESTORE_ATTEMPTS_MAX; i++)
- {
- hr = IDirectSoundBuffer8_Play(pDSoundStrmOut->pDSB, 0, 0, fFlags);
- if ( SUCCEEDED(hr)
- || hr != DSERR_BUFFERLOST)
- break;
- else
- {
- LogFlowFunc(("Restarting playback failed due to lost buffer, restoring ...\n"));
- directSoundPlayRestore(pThis, pDSoundStrmOut->pDSB);
- }
- }
-
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: Starting playback failed with %Rhrc\n", hr));
- rc = VERR_NOT_SUPPORTED;
- break;
- }
- }
-
- } while (0);
-
- if (RT_FAILURE(rc))
- {
- dsoundUpdateStatusInternal(pThis);
- }
- else
- {
- if (pcSamplesPlayed)
- *pcSamplesPlayed = cReadTotal;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostDSoundFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- PDSOUNDSTREAMOUT pDSoundStrmOut = (PDSOUNDSTREAMOUT)pHstStrmOut;
-
- directSoundPlayClose(pThis, pDSoundStrmOut);
-
- pDSoundStrmOut->cbPlayWritePos = 0;
- pDSoundStrmOut->fRestartPlayback = true;
- pDSoundStrmOut->csPlaybackBufferSize = 0;
-
- RT_ZERO(pDSoundStrmOut->streamCfg);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostDSoundInitIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
-{
- RT_NOREF(pCfgAcq);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- /* pcSamples is optional. */
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
-
- LogFlowFunc(("pHstStrmIn=%p, pCfgReq=%p, enmRecSource=%ld\n",
- pHstStrmIn, pCfgReq, enmRecSource));
-
- pDSoundStrmIn->streamCfg = *pCfgReq;
- pDSoundStrmIn->streamCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- /** @todo caller should already init Props? */
- int rc = DrvAudioStreamCfgToProps(&pDSoundStrmIn->streamCfg, &pHstStrmIn->Props);
- if (RT_SUCCESS(rc))
- {
- /* Init the stream structure and save relevant information to it. */
- pDSoundStrmIn->csCaptureReadPos = 0;
- pDSoundStrmIn->csCaptureBufferSize = 0;
- pDSoundStrmIn->pDSC = NULL;
- pDSoundStrmIn->pDSCB = NULL;
- pDSoundStrmIn->enmRecSource = enmRecSource;
- pDSoundStrmIn->hrLastCaptureIn = S_OK;
-
- if (pcSamples)
- *pcSamples = pThis->cfg.cbBufferIn >> pHstStrmIn->Props.cShift;
-
- /* Try to open capture in case the device is already there. */
- directSoundCaptureOpen(pThis, pDSoundStrmIn);
- }
- else
- {
- RT_ZERO(pDSoundStrmIn->streamCfg);
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostDSoundControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- LogFlowFunc(("pHstStrmIn=%p, enmStreamCmd=%ld\n", pHstStrmIn, enmStreamCmd));
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
- PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
-
- int rc = VINF_SUCCESS;
-
- HRESULT hr;
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- /* Try to start capture. If it fails, then reopen and try again. */
- hr = directSoundCaptureStart(pThis, pDSoundStrmIn);
- if (FAILED(hr))
- {
- hr = directSoundCaptureClose(pDSoundStrmIn);
- if (SUCCEEDED(hr))
- {
- hr = directSoundCaptureOpen(pThis, pDSoundStrmIn);
- if (SUCCEEDED(hr))
- hr = directSoundCaptureStart(pThis, pDSoundStrmIn);
- }
- }
-
- if (FAILED(hr))
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- hr = directSoundCaptureStop(pThis, pDSoundStrmIn);
- if (FAILED(hr))
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- default:
- {
- AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
- }
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostDSoundCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- uint32_t *pcSamplesCaptured)
-{
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
- LPDIRECTSOUNDCAPTUREBUFFER8 pDSCB = pDSoundStrmIn->pDSCB;
-
- int rc = VINF_SUCCESS;
-
- uint32_t cCaptured = 0;
-
- do
- {
- if (pDSCB == NULL)
- {
- rc = VERR_NOT_AVAILABLE;
- break;
- }
-
- /* Get DirectSound capture position in bytes. */
- DWORD cbReadPos;
- HRESULT hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pDSCB, NULL, &cbReadPos);
- if (FAILED(hr))
- {
- if (hr != pDSoundStrmIn->hrLastCaptureIn)
- {
- DSLOGREL(("DSound: Getting capture position failed with %Rhrc\n", hr));
- pDSoundStrmIn->hrLastCaptureIn = hr;
- }
-
- rc = VERR_NOT_AVAILABLE;
- break;
- }
-
- pDSoundStrmIn->hrLastCaptureIn = hr;
-
- if (cbReadPos & pHstStrmIn->Props.uAlign)
- DSLOGF(("DSound: Misaligned capture read position %ld (alignment: %RU32)\n", cbReadPos, pHstStrmIn->Props.uAlign));
-
- /* Capture position in samples. */
- DWORD csReadPos = cbReadPos >> pHstStrmIn->Props.cShift;
-
- /* Number of samples available in the DirectSound capture buffer. */
- DWORD csCaptured = dsoundRingDistance(csReadPos, pDSoundStrmIn->csCaptureReadPos, pDSoundStrmIn->csCaptureBufferSize);
- if (csCaptured == 0)
- break;
-
- /* Using as an intermediate not circular buffer. */
- AudioMixBufReset(&pHstStrmIn->MixBuf);
-
- /* Get number of free samples in the mix buffer and check that is has free space */
- uint32_t csMixFree = AudioMixBufFree(&pHstStrmIn->MixBuf);
- if (csMixFree == 0)
- {
- DSLOGF(("DSound: Capture buffer full\n"));
- break;
- }
-
- DSLOGF(("DSound: Capture csMixFree=%RU32, csReadPos=%ld, csCaptureReadPos=%ld, csCaptured=%ld\n",
- csMixFree, csReadPos, pDSoundStrmIn->csCaptureReadPos, csCaptured));
-
- /* No need to fetch more samples than mix buffer can receive. */
- csCaptured = RT_MIN(csCaptured, csMixFree);
-
- /* Lock relevant range in the DirectSound capture buffer. */
- LPVOID pv1, pv2;
- DWORD cb1, cb2;
- hr = directSoundCaptureLock(pDSCB, &pHstStrmIn->Props,
- AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, pDSoundStrmIn->csCaptureReadPos), /* dwOffset */
- AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, csCaptured), /* dwBytes */
- &pv1, &pv2, &cb1, &cb2,
- 0 /* dwFlags */);
- if (FAILED(hr))
- {
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- DWORD len1 = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cb1);
- DWORD len2 = AUDIOMIXBUF_B2S(&pHstStrmIn->MixBuf, cb2);
-
- uint32_t csWrittenTotal = 0;
- uint32_t csWritten;
- if (pv1 && len1)
- {
- rc = AudioMixBufWriteAt(&pHstStrmIn->MixBuf, 0 /* offWrite */,
- pv1, cb1, &csWritten);
- if (RT_SUCCESS(rc))
- csWrittenTotal += csWritten;
- }
-
- if ( RT_SUCCESS(rc)
- && csWrittenTotal == len1
- && pv2 && len2)
- {
- rc = AudioMixBufWriteAt(&pHstStrmIn->MixBuf, csWrittenTotal,
- pv2, cb2, &csWritten);
- if (RT_SUCCESS(rc))
- csWrittenTotal += csWritten;
- }
-
- directSoundCaptureUnlock(pDSCB, pv1, pv2, cb1, cb2);
-
- if (csWrittenTotal) /* Captured something? */
- rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, csWrittenTotal, &cCaptured);
-
- if (RT_SUCCESS(rc))
- {
- pDSoundStrmIn->csCaptureReadPos = (pDSoundStrmIn->csCaptureReadPos + cCaptured) % pDSoundStrmIn->csCaptureBufferSize;
- DSLOGF(("DSound: Capture %ld (%ld+%ld), processed %RU32/%RU32\n",
- csCaptured, len1, len2, cCaptured, csWrittenTotal));
- }
-
- } while (0);
-
- if (RT_FAILURE(rc))
- {
- dsoundUpdateStatusInternal(pThis);
- }
- else
- {
- if (pcSamplesCaptured)
- *pcSamplesCaptured = cCaptured;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostDSoundFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- RT_NOREF(pInterface);
- PDSOUNDSTREAMIN pDSoundStrmIn = (PDSOUNDSTREAMIN)pHstStrmIn;
-
- directSoundCaptureClose(pDSoundStrmIn);
-
- pDSoundStrmIn->csCaptureReadPos = 0;
- pDSoundStrmIn->csCaptureBufferSize = 0;
- RT_ZERO(pDSoundStrmIn->streamCfg);
-
- return VINF_SUCCESS;
-}
-
-/** @todo Replace PDMAUDIODIR with a (registered? unique) channel ID to provide multi-channel input/output. */
-static DECLCALLBACK(bool) drvHostDSoundIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- AssertPtrReturn(pInterface, false);
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- if (enmDir == PDMAUDIODIR_IN)
- return pThis->fEnabledIn;
-
- return pThis->fEnabledOut;
-}
-
-static DECLCALLBACK(int) drvHostDSoundGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- dsoundUpdateStatusInternalEx(pThis, pCfg, 0 /* fEnum */);
-
- return VINF_SUCCESS;
-}
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
-static int dsoundNotifyThread(PDRVHOSTDSOUND pThis, bool fShutdown)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- if (fShutdown)
- {
- LogFlowFunc(("Shutting down thread ...\n"));
- pThis->fShutdown = fShutdown;
- }
-
- /* Set the notification event so that the thread is being notified. */
- BOOL fRc = SetEvent(pThis->aEvents[DSOUNDEVENT_NOTIFY]);
- Assert(fRc);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostDSoundThread(RTTHREAD hThreadSelf, void *pvUser)
-{
- PDRVHOSTDSOUND pThis = (PDRVHOSTDSOUND)pvUser;
- AssertPtr(pThis);
-
- LogFlowFuncEnter();
-
- /* Let caller know that we're done initializing, regardless of the result. */
- int rc = RTThreadUserSignal(hThreadSelf);
- AssertRC(rc);
-
- do
- {
- HANDLE aEvents[VBOX_DSOUND_MAX_EVENTS];
- DWORD cEvents = 0;
- for (uint8_t i = 0; i < VBOX_DSOUND_MAX_EVENTS; i++)
- {
- if (pThis->aEvents[i])
- aEvents[cEvents++] = pThis->aEvents[i];
- }
- Assert(cEvents);
-
- LogFlowFunc(("Waiting: cEvents=%ld\n", cEvents));
-
- DWORD dwObj = WaitForMultipleObjects(cEvents, aEvents, FALSE /* bWaitAll */, INFINITE);
- switch (dwObj)
- {
- case WAIT_FAILED:
- {
- rc = VERR_CANCELLED;
- break;
- }
-
- case WAIT_TIMEOUT:
- {
- rc = VERR_TIMEOUT;
- break;
- }
-
- default:
- {
- dwObj = WAIT_OBJECT_0 + cEvents - 1;
- if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_NOTIFY])
- {
- LogFlowFunc(("Notify\n"));
- }
- else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_INPUT])
- {
-
- }
- else if (aEvents[dwObj] == pThis->aEvents[DSOUNDEVENT_OUTPUT])
- {
- DWORD cbBuffer, cbFree, cbPlayPos;
- rc = dsoundGetPosOut(pThis->pDSStrmOut, &cbBuffer, &cbFree, &cbPlayPos);
- if ( RT_SUCCESS(rc)
- && cbFree)
- {
- PDMAUDIOCALLBACKDATAOUT Out;
- Out.cbInFree = cbFree;
- Out.cbOutWritten = 0;
-
- while (!Out.cbOutWritten)
- {
- rc = pThis->pUpIAudioConnector->pfnCallback(pThis->pUpIAudioConnector,
- PDMAUDIOCALLBACKTYPE_OUTPUT, &Out, sizeof(Out));
- if (RT_FAILURE(rc))
- break;
- RTThreadSleep(100);
- }
-
- LogFlowFunc(("Output: cbBuffer=%ld, cbFree=%ld, cbPlayPos=%ld, cbWritten=%RU32, rc=%Rrc\n",
- cbBuffer, cbFree, cbPlayPos, Out.cbOutWritten, rc));
- }
- }
- break;
- }
- }
-
- if (pThis->fShutdown)
- break;
-
- } while (RT_SUCCESS(rc));
-
- pThis->fStopped = true;
-
- LogFlowFunc(("Exited with fShutdown=%RTbool, rc=%Rrc\n", pThis->fShutdown, rc));
- return rc;
-}
-#endif /* VBOX_WITH_AUDIO_CALLBACKS */
-
-static DECLCALLBACK(void) drvHostDSoundShutdown(PPDMIHOSTAUDIO pInterface)
-{
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- LogFlowFuncEnter();
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- int rc = dsoundNotifyThread(pThis, true /* fShutdown */);
- AssertRC(rc);
-
- int rcThread;
- rc = RTThreadWait(pThis->Thread, 15 * 1000 /* 15s timeout */, &rcThread);
- LogFlowFunc(("rc=%Rrc, rcThread=%Rrc\n", rc, rcThread));
-
- Assert(pThis->fStopped);
-
- if (pThis->aEvents[DSOUNDEVENT_NOTIFY])
- {
- CloseHandle(pThis->aEvents[DSOUNDEVENT_NOTIFY]);
- pThis->aEvents[DSOUNDEVENT_NOTIFY] = NULL;
- }
-#else
- RT_NOREF(pThis);
-#endif
-
- LogFlowFuncLeave();
-}
-
-static DECLCALLBACK(int) drvHostDSoundInit(PPDMIHOSTAUDIO pInterface)
-{
- PDRVHOSTDSOUND pThis = PDMIHOSTAUDIO_2_DRVHOSTDSOUND(pInterface);
-
- LogFlowFuncEnter();
-
- int rc;
-
- /* Verify that IDirectSound is available. */
- LPDIRECTSOUND pDirectSound = NULL;
- HRESULT hr = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_ALL,
- IID_IDirectSound, (void **)&pDirectSound);
- if (SUCCEEDED(hr))
- {
- IDirectSound_Release(pDirectSound);
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- /* Create notification event. */
- pThis->aEvents[DSOUNDEVENT_NOTIFY] = CreateEvent(NULL /* Security attribute */,
- FALSE /* bManualReset */, FALSE /* bInitialState */,
- NULL /* lpName */);
- Assert(pThis->aEvents[DSOUNDEVENT_NOTIFY] != NULL);
-
- /* Start notification thread. */
- rc = RTThreadCreate(&pThis->Thread, drvHostDSoundThread,
- pThis /*pvUser*/, 0 /*cbStack*/,
- RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "dSoundNtfy");
- if (RT_SUCCESS(rc))
- {
- /* Wait for the thread to initialize. */
- rc = RTThreadUserWait(pThis->Thread, RT_MS_1MIN);
- if (RT_FAILURE(rc))
- DSLOGREL(("DSound: Waiting for thread to initialize failed with rc=%Rrc\n", rc));
- }
- else
- DSLOGREL(("DSound: Creating thread failed with rc=%Rrc\n", rc));
-#else
- rc = VINF_SUCCESS;
-#endif
-
- PDMAUDIOBACKENDCFG Cfg;
- dsoundUpdateStatusInternalEx(pThis, &Cfg, DSOUNDENUMCBFLAGS_LOG /* fEnum */);
-
- DSLOGREL(("DSound: Found %RU32 host playback devices\n", Cfg.cMaxHstStrmsOut));
- DSLOGREL(("DSound: Found %RU32 host capturing devices\n", Cfg.cMaxHstStrmsIn));
- }
- else
- {
- DSLOGREL(("DSound: DirectSound not available: %Rhrc\n", hr));
- rc = VERR_NOT_SUPPORTED;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(void *) drvHostDSoundQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
- return NULL;
-}
-
-static LPCGUID dsoundConfigQueryGUID(PCFGMNODE pCfg, const char *pszName, RTUUID *pUuid)
-{
- LPCGUID pGuid = NULL;
-
- char *pszGuid = NULL;
- int rc = CFGMR3QueryStringAlloc(pCfg, pszName, &pszGuid);
- if (RT_SUCCESS(rc))
- {
- rc = RTUuidFromStr(pUuid, pszGuid);
- if (RT_SUCCESS(rc))
- pGuid = (LPCGUID)&pUuid;
- else
- DSLOGREL(("DSound: Error parsing device GUID for device '%s': %Rrc\n", pszName, rc));
-
- RTStrFree(pszGuid);
- }
-
- return pGuid;
-}
-
-static void dSoundConfigInit(PDRVHOSTDSOUND pThis, PCFGMNODE pCfg)
-{
- unsigned int uBufsizeOut, uBufsizeIn;
-
- CFGMR3QueryUIntDef(pCfg, "BufsizeOut", &uBufsizeOut, _16K);
- CFGMR3QueryUIntDef(pCfg, "BufsizeIn", &uBufsizeIn, _16K);
- pThis->cfg.cbBufferOut = uBufsizeOut;
- pThis->cfg.cbBufferIn = uBufsizeIn;
-
- pThis->cfg.pGuidPlay = dsoundConfigQueryGUID(pCfg, "DeviceGuidOut", &pThis->cfg.uuidPlay);
- pThis->cfg.pGuidCapture = dsoundConfigQueryGUID(pCfg, "DeviceGuidIn", &pThis->cfg.uuidCapture);
-
- DSLOG(("DSound: BufsizeOut %u, BufsizeIn %u, DeviceGuidOut {%RTuuid}, DeviceGuidIn {%RTuuid}\n",
- pThis->cfg.cbBufferOut,
- pThis->cfg.cbBufferIn,
- &pThis->cfg.uuidPlay,
- &pThis->cfg.uuidCapture));
-}
-
-static DECLCALLBACK(void) drvHostDSoundDestruct(PPDMDRVINS pDrvIns)
-{
- PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
- LogFlowFuncEnter();
-
- if (pThis->pDrvIns)
- CoUninitialize();
-
- LogFlowFuncLeave();
-}
-
-/**
- * Construct a DirectSound Audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvHostDSoundConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(fFlags);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
- PDRVHOSTDSOUND pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDSOUND);
-
- LogRel(("Audio: Initializing DirectSound audio driver\n"));
-
- HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
- if (FAILED(hr))
- {
- DSLOGREL(("DSound: CoInitializeEx failed with %Rhrc\n", hr));
- return VERR_NOT_SUPPORTED;
- }
-
- /*
- * Init basic data members and interfaces.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvHostDSoundQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostDSound);
-
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- /*
- * Get the IAudioConnector interface of the above driver/device.
- */
- pThis->pUpIAudioConnector = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
- if (!pThis->pUpIAudioConnector)
- {
- AssertMsgFailed(("Configuration error: No audio connector interface above!\n"));
- return VERR_PDM_MISSING_INTERFACE_ABOVE;
- }
-#endif
-
- /*
- * Init the static parts.
- */
- RTListInit(&pThis->lstDevInput);
- RTListInit(&pThis->lstDevOutput);
-
- pThis->fEnabledIn = false;
- pThis->fEnabledOut = false;
-#ifdef VBOX_WITH_AUDIO_CALLBACKS
- pThis->fStopped = false;
- pThis->fShutdown = false;
-
- RT_ZERO(pThis->aEvents);
- pThis->cEvents = 0;
-#endif
-
- /*
- * Initialize configuration values.
- */
- dSoundConfigInit(pThis, pCfg);
-
- return VINF_SUCCESS;
-}
-
-/**
- * PDM driver registration.
- */
-const PDMDRVREG g_DrvHostDSound =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "DSoundAudio",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "DirectSound Audio host driver",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVHOSTDSOUND),
- /* pfnConstruct */
- drvHostDSoundConstruct,
- /* pfnDestruct */
- drvHostDSoundDestruct,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
diff --git a/src/VBox/Devices/Audio_50/DrvHostNullAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostNullAudio.cpp
deleted file mode 100644
index a91d7db..0000000
--- a/src/VBox/Devices/Audio_50/DrvHostNullAudio.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/* $Id: DrvHostNullAudio.cpp $ */
-/** @file
- * NULL audio driver -- also acts as a fallback if no
- * other backend is available.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- *
- * This code is based on: noaudio.c QEMU based code.
- *
- * QEMU Timer based audio emulation
- *
- * Copyright (c) 2004-2005 Vassili Karpov (malc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <VBox/log.h>
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-
-#include "VBoxDD.h"
-
-#include <iprt/alloc.h>
-#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
-#include <VBox/vmm/pdmaudioifs.h>
-
-typedef struct NULLAUDIOSTREAMOUT
-{
- /** Note: Always must come first! */
- PDMAUDIOHSTSTRMOUT streamOut;
- uint64_t u64TicksLast;
- uint64_t csPlayBuffer;
- uint8_t *pu8PlayBuffer;
-} NULLAUDIOSTREAMOUT, *PNULLAUDIOSTREAMOUT;
-
-typedef struct NULLAUDIOSTREAMIN
-{
- /** Note: Always must come first! */
- PDMAUDIOHSTSTRMIN streamIn;
-} NULLAUDIOSTREAMIN, *PNULLAUDIOSTREAMIN;
-
-/**
- * NULL audio driver instance data.
- * @implements PDMIAUDIOCONNECTOR
- */
-typedef struct DRVHOSTNULLAUDIO
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
-} DRVHOSTNULLAUDIO, *PDRVHOSTNULLAUDIO;
-
-/*******************************************PDM_AUDIO_DRIVER******************************/
-
-
-static DECLCALLBACK(int) drvHostNullAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
- NOREF(pInterface);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- pCfg->cbStreamOut = sizeof(NULLAUDIOSTREAMOUT);
- pCfg->cbStreamIn = sizeof(NULLAUDIOSTREAMIN);
-
- pCfg->cMaxHstStrmsOut = 1; /* Output */
- pCfg->cMaxHstStrmsIn = 2; /* Line input + microphone input. */
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostNullAudioInit(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostNullAudioInitIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
-{
- NOREF(pInterface);
- NOREF(enmRecSource);
- NOREF(pCfgAcq);
-
- /* Just adopt the wanted stream configuration. */
- int rc = DrvAudioStreamCfgToProps(pCfgReq, &pHstStrmIn->Props);
- if (RT_SUCCESS(rc))
- {
- if (pcSamples)
- *pcSamples = _1K;
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostNullAudioInitOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- uint32_t *pcSamples)
-{
- NOREF(pInterface);
- NOREF(pCfgAcq);
-
- /* Just adopt the wanted stream configuration. */
- int rc = DrvAudioStreamCfgToProps(pCfgReq, &pHstStrmOut->Props);
- if (RT_SUCCESS(rc))
- {
- PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
- pNullStrmOut->u64TicksLast = 0;
- pNullStrmOut->csPlayBuffer = _1K;
- pNullStrmOut->pu8PlayBuffer = (uint8_t *)RTMemAlloc(_1K << pHstStrmOut->Props.cShift);
- if (pNullStrmOut->pu8PlayBuffer)
- {
- if (pcSamples)
- *pcSamples = pNullStrmOut->csPlayBuffer;
- }
- else
- {
- rc = VERR_NO_MEMORY;
- }
- }
-
- return rc;
-}
-
-static DECLCALLBACK(bool) drvHostNullAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- NOREF(pInterface);
- NOREF(enmDir);
- return true; /* Always all enabled. */
-}
-
-static DECLCALLBACK(int) drvHostNullAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- uint32_t *pcSamplesPlayed)
-{
- PDRVHOSTNULLAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTNULLAUDIO, IHostAudio);
- PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
-
- /* Consume as many samples as would be played at the current frequency since last call. */
- uint32_t csLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
- uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
- uint64_t u64TicksElapsed = u64TicksNow - pNullStrmOut->u64TicksLast;
- uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
-
- /* Remember when samples were consumed. */
- pNullStrmOut->u64TicksLast = u64TicksNow;
-
- /*
- * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
- * If rounding is not taken into account then the playback rate will be consistently lower that expected.
- */
- uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pHstStrmOut->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
-
- /* Don't play more than available. */
- if (cSamplesPlayed > csLive)
- cSamplesPlayed = csLive;
-
- cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStrmOut->csPlayBuffer);
-
- uint32_t csRead = 0;
- AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pNullStrmOut->pu8PlayBuffer,
- AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cSamplesPlayed), &csRead);
- AudioMixBufFinish(&pHstStrmOut->MixBuf, csRead);
-
- if (pcSamplesPlayed)
- *pcSamplesPlayed = csRead;
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostNullAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- uint32_t *pcSamplesCaptured)
-{
- RT_NOREF(pInterface, pHstStrmIn);
- /* Never capture anything. */
- if (pcSamplesCaptured)
- *pcSamplesCaptured = 0;
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostNullAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- NOREF(pInterface);
- NOREF(pHstStrmIn);
- NOREF(enmStreamCmd);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostNullAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- NOREF(pInterface);
- NOREF(pHstStrmOut);
- NOREF(enmStreamCmd);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostNullAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- RT_NOREF(pInterface, pHstStrmIn);
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostNullAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- RT_NOREF(pInterface);
- PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
- if ( pNullStrmOut
- && pNullStrmOut->pu8PlayBuffer)
- {
- RTMemFree(pNullStrmOut->pu8PlayBuffer);
- }
- return VINF_SUCCESS;
-}
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
- return NULL;
-}
-
-static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-}
-
-/**
- * Constructs a Null audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(pCfg, fFlags);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
-
- PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
- LogRel(("Audio: Initializing NULL driver\n"));
-
- /*
- * Init the static parts.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Char driver registration record.
- */
-const PDMDRVREG g_DrvHostNullAudio =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "NullAudio",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "NULL audio host driver",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVHOSTNULLAUDIO),
- /* pfnConstruct */
- drvHostNullAudioConstruct,
- /* pfnDestruct */
- NULL,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
-
diff --git a/src/VBox/Devices/Audio_50/DrvHostOSSAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostOSSAudio.cpp
deleted file mode 100644
index 098df56..0000000
--- a/src/VBox/Devices/Audio_50/DrvHostOSSAudio.cpp
+++ /dev/null
@@ -1,1006 +0,0 @@
-/* $Id: DrvHostOSSAudio.cpp $ */
-/** @file
- * OSS (Open Sound System) host audio backend.
- */
-
-/*
- * Copyright (C) 2014-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- * --------------------------------------------------------------------
- */
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <VBox/log.h>
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-
-#include "VBoxDD.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/soundcard.h>
-#include <unistd.h>
-
-#include <iprt/alloc.h>
-#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
-#include <VBox/vmm/pdmaudioifs.h>
-
-/**
- * OSS host audio driver instance data.
- * @implements PDMIAUDIOCONNECTOR
- */
-typedef struct DRVHOSTOSSAUDIO
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
- /** Error count for not flooding the release log.
- * UINT32_MAX for unlimited logging. */
- uint32_t cLogErrors;
-} DRVHOSTOSSAUDIO, *PDRVHOSTOSSAUDIO;
-
-typedef struct OSSAUDIOSTREAMCFG
-{
- PDMAUDIOFMT enmFormat;
- PDMAUDIOENDIANNESS enmENDIANNESS;
- uint16_t uFreq;
- uint8_t cChannels;
- uint16_t cFragments;
- uint32_t cbFragmentSize;
-} OSSAUDIOSTREAMCFG, *POSSAUDIOSTREAMCFG;
-
-typedef struct OSSAUDIOSTREAMIN
-{
- /** Note: Always must come first! */
- PDMAUDIOHSTSTRMIN pStreamIn;
- int hFile;
- int cFragments;
- int cbFragmentSize;
- /** Own PCM buffer. */
- void *pvPCMBuf;
- /** Size (in bytes) of own PCM buffer. */
- size_t cbPCMBuf;
- int old_optr;
-} OSSAUDIOSTREAMIN, *POSSAUDIOSTREAMIN;
-
-typedef struct OSSAUDIOSTREAMOUT
-{
- /** Note: Always must come first! */
- PDMAUDIOHSTSTRMOUT pStreamOut;
- int hFile;
- int cFragments;
- int cbFragmentSize;
-#ifndef RT_OS_L4
- /** Whether we use a memory mapped file instead of our
- * own allocated PCM buffer below. */
- bool fMemMapped;
-#endif
- /** Own PCM buffer in case memory mapping is unavailable. */
- void *pvPCMBuf;
- /** Size (in bytes) of own PCM buffer. */
- size_t cbPCMBuf;
- int old_optr;
-} OSSAUDIOSTREAMOUT, *POSSAUDIOSTREAMOUT;
-
-typedef struct OSSAUDIOCFG
-{
-#ifndef RT_OS_L4
- bool try_mmap;
-#endif
- int nfrags;
- int fragsize;
- const char *devpath_out;
- const char *devpath_in;
- int debug;
-} OSSAUDIOCFG, *POSSAUDIOCFG;
-
-static OSSAUDIOCFG s_OSSConf =
-{
-#ifndef RT_OS_L4
- false,
-#endif
- 4,
- 4096,
- "/dev/dsp",
- "/dev/dsp",
- 0
-};
-
-
-/* http://www.df.lth.se/~john_e/gems/gem002d.html */
-static uint32_t popcount(uint32_t u)
-{
- u = ((u&0x55555555) + ((u>>1)&0x55555555));
- u = ((u&0x33333333) + ((u>>2)&0x33333333));
- u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
- u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
- u = ( u&0x0000ffff) + (u>>16);
- return u;
-}
-
-static uint32_t lsbindex(uint32_t u)
-{
- return popcount ((u&-u)-1);
-}
-
-static int drvHostOSSAudioFmtToOSS(PDMAUDIOFMT fmt)
-{
- switch (fmt)
- {
- case AUD_FMT_S8:
- return AFMT_S8;
-
- case AUD_FMT_U8:
- return AFMT_U8;
-
- case AUD_FMT_S16:
- return AFMT_S16_LE;
-
- case AUD_FMT_U16:
- return AFMT_U16_LE;
-
- default:
- break;
- }
-
- AssertMsgFailed(("Format %ld not supported\n", fmt));
- return AFMT_U8;
-}
-
-static int drvHostOSSAudioOSSToFmt(int fmt,
- PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pENDIANNESS)
-{
- switch (fmt)
- {
- case AFMT_S8:
- *pFmt = AUD_FMT_S8;
- if (pENDIANNESS)
- *pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case AFMT_U8:
- *pFmt = AUD_FMT_U8;
- if (pENDIANNESS)
- *pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case AFMT_S16_LE:
- *pFmt = AUD_FMT_S16;
- if (pENDIANNESS)
- *pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case AFMT_U16_LE:
- *pFmt = AUD_FMT_U16;
- if (pENDIANNESS)
- *pENDIANNESS = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case AFMT_S16_BE:
- *pFmt = AUD_FMT_S16;
- if (pENDIANNESS)
- *pENDIANNESS = PDMAUDIOENDIANNESS_BIG;
- break;
-
- case AFMT_U16_BE:
- *pFmt = AUD_FMT_U16;
- if (pENDIANNESS)
- *pENDIANNESS = PDMAUDIOENDIANNESS_BIG;
- break;
-
- default:
- AssertMsgFailed(("Format %ld not supported\n", fmt));
- return VERR_NOT_SUPPORTED;
- }
-
- return VINF_SUCCESS;
-}
-
-static int drvHostOSSAudioClose(int *phFile)
-{
- if (!phFile || !*phFile)
- return VINF_SUCCESS;
-
- int rc;
- if (close(*phFile))
- {
- LogRel(("OSS: Closing descriptor failed: %s\n",
- strerror(errno)));
- rc = VERR_GENERAL_FAILURE; /** @todo */
- }
- else
- {
- *phFile = -1;
- rc = VINF_SUCCESS;
- }
-
- return rc;
-}
-
-static int drvHostOSSAudioOpen(bool fIn,
- POSSAUDIOSTREAMCFG pReq, POSSAUDIOSTREAMCFG pObt,
- int *phFile)
-{
- AssertPtrReturn(pReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pObt, VERR_INVALID_POINTER);
- AssertPtrReturn(phFile, VERR_INVALID_POINTER);
-
- int rc;
- int hFile;
-
- do
- {
- const char *pszDev = fIn ? s_OSSConf.devpath_in : s_OSSConf.devpath_out;
- if (!pszDev)
- {
- LogRel(("OSS: Invalid or no %s device name set\n",
- fIn ? "input" : "output"));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- hFile = open(pszDev, (fIn ? O_RDONLY : O_WRONLY) | O_NONBLOCK);
- if (hFile == -1)
- {
- LogRel(("OSS: Failed to open %s: %s(%d)\n", pszDev, strerror(errno), errno));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- int iFormat = drvHostOSSAudioFmtToOSS(pReq->enmFormat);
- if (ioctl(hFile, SNDCTL_DSP_SAMPLESIZE, &iFormat))
- {
- LogRel(("OSS: Failed to set audio format to %ld errno=%s(%d)\n", iFormat, strerror(errno), errno));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- int cChannels = pReq->cChannels;
- if (ioctl(hFile, SNDCTL_DSP_CHANNELS, &cChannels))
- {
- LogRel(("OSS: Failed to set number of audio channels (%d): %s(%d)\n", pReq->cChannels, strerror(errno), errno));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- int freq = pReq->uFreq;
- if (ioctl(hFile, SNDCTL_DSP_SPEED, &freq))
- {
- LogRel(("OSS: Failed to set audio frequency (%dHZ): %s(%d)\n", pReq->uFreq, strerror(errno), errno));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- /* Obsolete on Solaris (using O_NONBLOCK is sufficient). */
-#if !(defined(VBOX) && defined(RT_OS_SOLARIS))
- if (ioctl(hFile, SNDCTL_DSP_NONBLOCK))
- {
- LogRel(("OSS: Failed to set non-blocking mode: %s(%d)\n", strerror(errno), errno));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-#endif
- int mmmmssss = (pReq->cFragments << 16) | lsbindex(pReq->cbFragmentSize);
- if (ioctl(hFile, SNDCTL_DSP_SETFRAGMENT, &mmmmssss))
- {
- LogRel(("OSS: Failed to set %RU16 fragments to %RU32 bytes each: %s(%d)\n",
- pReq->cFragments, pReq->cbFragmentSize, strerror(errno), errno));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- audio_buf_info abinfo;
- if (ioctl(hFile, fIn ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo))
- {
- LogRel(("OSS: Failed to retrieve buffer length: %s(%d)\n", strerror(errno), errno));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- rc = drvHostOSSAudioOSSToFmt(iFormat, &pObt->enmFormat, &pObt->enmENDIANNESS);
- if (RT_SUCCESS(rc))
- {
- pObt->cChannels = cChannels;
- pObt->uFreq = freq;
- pObt->cFragments = abinfo.fragstotal;
- pObt->cbFragmentSize = abinfo.fragsize;
-
- *phFile = hFile;
- }
- }
- while (0);
-
- if (RT_FAILURE(rc))
- drvHostOSSAudioClose(&hFile);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- NOREF(pInterface);
- NOREF(pHstStrmIn);
- NOREF(enmStreamCmd);
-
- /** @todo Nothing to do here right now!? */
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
-
-#ifdef RT_OS_L4
- return VINF_SUCCESS;
-#else
- if (!pThisStrmOut->fMemMapped)
- return VINF_SUCCESS;
-#endif
-
- int rc = VINF_SUCCESS;
- int mask;
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- DrvAudioClearBuf(&pHstStrmOut->Props,
- pThisStrmOut->pvPCMBuf, pThisStrmOut->cbPCMBuf, AudioMixBufSize(&pHstStrmOut->MixBuf));
-
- mask = PCM_ENABLE_OUTPUT;
- if (ioctl(pThisStrmOut->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
- {
- LogRel(("OSS: Failed to enable output stream: %s\n", strerror(errno)));
- rc = RTErrConvertFromErrno(errno);
- }
-
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- mask = 0;
- if (ioctl(pThisStrmOut->hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
- {
- LogRel(("OSS: Failed to disable output stream: %s\n", strerror(errno)));
- rc = RTErrConvertFromErrno(errno);
- }
-
- break;
- }
-
- default:
- AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioInit(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-
- LogFlowFuncEnter();
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- uint32_t *pcSamplesCaptured)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
-
- int rc = VINF_SUCCESS;
- size_t cbToRead = RT_MIN(pThisStrmIn->cbPCMBuf,
- AudioMixBufFreeBytes(&pHstStrmIn->MixBuf));
-
- LogFlowFunc(("cbToRead=%zu\n", cbToRead));
-
- uint32_t cWrittenTotal = 0;
- uint32_t cbTemp;
- ssize_t cbRead;
- size_t offWrite = 0;
-
- while (cbToRead)
- {
- cbTemp = RT_MIN(cbToRead, pThisStrmIn->cbPCMBuf);
- AssertBreakStmt(cbTemp, rc = VERR_NO_DATA);
- cbRead = read(pThisStrmIn->hFile, (uint8_t *)pThisStrmIn->pvPCMBuf + offWrite, cbTemp);
-
- LogFlowFunc(("cbRead=%zi, cbTemp=%RU32, cbToRead=%zu\n",
- cbRead, cbTemp, cbToRead));
-
- if (cbRead < 0)
- {
- switch (errno)
- {
- case 0:
- {
- LogFunc(("Failed to read %z frames\n", cbRead));
- rc = VERR_ACCESS_DENIED;
- break;
- }
-
- case EINTR:
- case EAGAIN:
- rc = VERR_NO_DATA;
- break;
-
- default:
- LogFlowFunc(("Failed to read %zu input frames, rc=%Rrc\n",
- cbTemp, rc));
- rc = VERR_GENERAL_FAILURE; /** @todo */
- break;
- }
-
- if (RT_FAILURE(rc))
- break;
- }
- else if (cbRead)
- {
- uint32_t cWritten;
- rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
- pThisStrmIn->pvPCMBuf, cbRead,
- &cWritten);
- if (RT_FAILURE(rc))
- break;
-
- uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
-
- Assert(cbToRead >= cbWritten);
- cbToRead -= cbWritten;
- offWrite += cbWritten;
- cWrittenTotal += cWritten;
- }
- else /* No more data, try next round. */
- break;
- }
-
- if (rc == VERR_NO_DATA)
- rc = VINF_SUCCESS;
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cProcessed = 0;
- if (cWrittenTotal)
- rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
- &cProcessed);
-
- if (pcSamplesCaptured)
- *pcSamplesCaptured = cWrittenTotal;
-
- LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
- cWrittenTotal, cProcessed, rc));
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
-
- LogFlowFuncEnter();
-
- if (pThisStrmIn->pvPCMBuf)
- {
- Assert(pThisStrmIn->cbPCMBuf);
-
- RTMemFree(pThisStrmIn->pvPCMBuf);
- pThisStrmIn->pvPCMBuf = NULL;
- }
-
- pThisStrmIn->cbPCMBuf = 0;
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
-
- LogFlowFuncEnter();
-
-#ifndef RT_OS_L4
- if (!pThisStrmOut->fMemMapped)
- {
- if (pThisStrmOut->pvPCMBuf)
- {
- Assert(pThisStrmOut->cbPCMBuf);
-
- RTMemFree(pThisStrmOut->pvPCMBuf);
- pThisStrmOut->pvPCMBuf = NULL;
- }
-
- pThisStrmOut->cbPCMBuf = 0;
- }
-#endif
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
- NOREF(pInterface);
-
- pCfg->cbStreamOut = sizeof(OSSAUDIOSTREAMOUT);
- pCfg->cbStreamIn = sizeof(OSSAUDIOSTREAMIN);
- pCfg->cMaxHstStrmsOut = INT_MAX;
- pCfg->cMaxHstStrmsIn = INT_MAX;
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioInitIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
-{
- RT_NOREF(pInterface, pCfgAcq, enmRecSource);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
-
- POSSAUDIOSTREAMIN pThisStrmIn = (POSSAUDIOSTREAMIN)pHstStrmIn;
-
- int rc;
- int hFile = -1;
-
- do
- {
- uint32_t cSamples;
-
- OSSAUDIOSTREAMCFG reqStream, obtStream;
- reqStream.enmFormat = pCfgReq->enmFormat;
- reqStream.uFreq = pCfgReq->uHz;
- reqStream.cChannels = pCfgReq->cChannels;
- reqStream.cFragments = s_OSSConf.nfrags;
- reqStream.cbFragmentSize = s_OSSConf.fragsize;
-
- rc = drvHostOSSAudioOpen(true /* fIn */,
- &reqStream, &obtStream, &hFile);
- if (RT_SUCCESS(rc))
- {
- if (obtStream.cFragments * obtStream.cbFragmentSize & pHstStrmIn->Props.uAlign)
- LogRel(("OSS: Warning: Misaligned DAC output buffer: Size = %zu, Alignment = %u\n",
- obtStream.cFragments * obtStream.cbFragmentSize,
- pHstStrmIn->Props.uAlign + 1));
-
- pThisStrmIn->hFile = hFile;
-
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.enmFormat = obtStream.enmFormat;
- streamCfg.uHz = obtStream.uFreq;
- streamCfg.cChannels = pCfgReq->cChannels;
- streamCfg.enmEndianness = obtStream.enmENDIANNESS;
-
- rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
- if (RT_SUCCESS(rc))
- {
- cSamples = (obtStream.cFragments * obtStream.cbFragmentSize)
- >> pHstStrmIn->Props.cShift;
- if (!cSamples)
- rc = VERR_INVALID_PARAMETER;
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- size_t cbSample = (1 << pHstStrmIn->Props.cShift);
- size_t cbBuf = cSamples * cbSample;
- pThisStrmIn->pvPCMBuf = RTMemAlloc(cbBuf);
- if (!pThisStrmIn->pvPCMBuf)
- {
- LogRel(("OSS: Failed allocating ADC buffer with %RU32 samples (%zu bytes per sample)\n", cSamples, cbSample));
- rc = VERR_NO_MEMORY;
- }
-
- pThisStrmIn->cbPCMBuf = cbBuf;
-
- if (pcSamples)
- *pcSamples = cSamples;
- }
-
- } while (0);
-
- if (RT_FAILURE(rc))
- drvHostOSSAudioClose(&hFile);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioInitOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- uint32_t *pcSamples)
-{
- RT_NOREF(pInterface, pCfgAcq);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
-
- POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
-
- int rc;
- int hFile = -1;
-
- do
- {
- uint32_t cSamples;
-
- OSSAUDIOSTREAMCFG reqStream, obtStream;
- reqStream.enmFormat = pCfgReq->enmFormat;
- reqStream.uFreq = pCfgReq->uHz;
- reqStream.cChannels = pCfgReq->cChannels;
- reqStream.cFragments = s_OSSConf.nfrags;
- reqStream.cbFragmentSize = s_OSSConf.fragsize;
-
- rc = drvHostOSSAudioOpen(false /* fIn */,
- &reqStream, &obtStream, &hFile);
- if (RT_SUCCESS(rc))
- {
- if (obtStream.cFragments * obtStream.cbFragmentSize & pHstStrmOut->Props.uAlign)
- LogRel(("OSS: Warning: Misaligned DAC output buffer: Size = %zu, Alignment = %u\n",
- obtStream.cFragments * obtStream.cbFragmentSize,
- pHstStrmOut->Props.uAlign + 1));
-
- pThisStrmOut->hFile = hFile;
-
- PDMAUDIOSTREAMCFG streamCfg;
- streamCfg.enmFormat = obtStream.enmFormat;
- streamCfg.uHz = obtStream.uFreq;
- streamCfg.cChannels = pCfgReq->cChannels;
- streamCfg.enmEndianness = obtStream.enmENDIANNESS;
-
- rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
- if (RT_SUCCESS(rc))
- cSamples = (obtStream.cFragments * obtStream.cbFragmentSize)
- >> pHstStrmOut->Props.cShift;
- }
-
- if (RT_SUCCESS(rc))
- {
-#ifndef RT_OS_L4
- pThisStrmOut->fMemMapped = false;
- if (s_OSSConf.try_mmap)
- {
- pThisStrmOut->pvPCMBuf = mmap(0, cSamples << pHstStrmOut->Props.cShift,
- PROT_READ | PROT_WRITE, MAP_SHARED, hFile, 0);
- if (pThisStrmOut->pvPCMBuf == MAP_FAILED)
- {
- LogRel(("OSS: Failed to memory map %zu bytes of DAC output file: %s\n",
- cSamples << pHstStrmOut->Props.cShift, strerror(errno)));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
- else
- {
- int mask = 0;
- if (ioctl(hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
- {
- LogRel(("OSS: Failed to retrieve initial trigger mask: %s\n",
- strerror(errno)));
- rc = RTErrConvertFromErrno(errno);
- /* Note: No break here, need to unmap file first! */
- }
- else
- {
- mask = PCM_ENABLE_OUTPUT;
- if (ioctl (hFile, SNDCTL_DSP_SETTRIGGER, &mask) < 0)
- {
- LogRel(("OSS: Failed to retrieve PCM_ENABLE_OUTPUT mask: %s\n",
- strerror(errno)));
- rc = RTErrConvertFromErrno(errno);
- /* Note: No break here, need to unmap file first! */
- }
- else
- pThisStrmOut->fMemMapped = true;
- }
-
- if (!pThisStrmOut->fMemMapped)
- {
- int rc2 = munmap(pThisStrmOut->pvPCMBuf,
- cSamples << pHstStrmOut->Props.cShift);
- if (rc2)
- LogRel(("OSS: Failed to unmap DAC output file: %s\n", strerror(errno)));
- break;
- }
- }
- }
-#endif /* !RT_OS_L4 */
-
- /* Memory mapping failed above? Try allocating an own buffer. */
-#ifndef RT_OS_L4
- if (!pThisStrmOut->fMemMapped)
- {
-#endif
- size_t cbSample = (1 << pHstStrmOut->Props.cShift);
- size_t cbPCMBuf = cSamples * cbSample;
-
- LogFlowFunc(("cSamples=%RU32\n", cSamples));
-
- pThisStrmOut->pvPCMBuf = RTMemAlloc(cbPCMBuf);
- if (!pThisStrmOut->pvPCMBuf)
- {
- LogRel(("OSS: Failed allocating DAC buffer with %RU32 samples (%zu bytes per sample)\n", cSamples, cbSample));
- rc = VERR_NO_MEMORY;
- break;
- }
-
- pThisStrmOut->cbPCMBuf = cbPCMBuf;
-#ifndef RT_OS_L4
- }
-#endif
- if (pcSamples)
- *pcSamples = cSamples;
- }
-
- } while (0);
-
- if (RT_FAILURE(rc))
- drvHostOSSAudioClose(&hFile);
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(bool) drvHostOSSAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- NOREF(pInterface);
- NOREF(enmDir);
- return true; /* Always all enabled. */
-}
-
-static DECLCALLBACK(int) drvHostOSSAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- uint32_t *pcSamplesPlayed)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- POSSAUDIOSTREAMOUT pThisStrmOut = (POSSAUDIOSTREAMOUT)pHstStrmOut;
-
- int rc = VINF_SUCCESS;
- uint32_t cbReadTotal = 0;
- count_info cntinfo;
-
- do
- {
- size_t cbBuf = AudioMixBufSizeBytes(&pHstStrmOut->MixBuf);
-
- uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
- uint32_t cToRead;
-
-#ifndef RT_OS_L4
- if (pThisStrmOut->fMemMapped)
- {
- /* Get current playback pointer. */
- int rc2 = ioctl(pThisStrmOut->hFile, SNDCTL_DSP_GETOPTR, &cntinfo);
- if (!rc2)
- {
- LogRel(("OSS: Failed to retrieve current playback pointer: %s\n",
- strerror(errno)));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- /* Nothing to play? */
- if (cntinfo.ptr == pThisStrmOut->old_optr)
- break;
-
- int cbData;
- if (cntinfo.ptr > pThisStrmOut->old_optr)
- cbData = cntinfo.ptr - pThisStrmOut->old_optr;
- else
- cbData = cbBuf + cntinfo.ptr - pThisStrmOut->old_optr;
- Assert(cbData);
-
- cToRead = RT_MIN((uint32_t)AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbData),
- cLive);
- }
- else
- {
-#endif
- audio_buf_info abinfo;
- int rc2 = ioctl(pThisStrmOut->hFile, SNDCTL_DSP_GETOSPACE, &abinfo);
- if (rc2 < 0)
- {
- LogRel(("OSS: Failed to retrieve current playback buffer: %s\n",
- strerror(errno)));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- if ((size_t)abinfo.bytes > cbBuf)
- {
- LogFlowFunc(("Warning: Invalid available size, size=%d, bufsize=%d\n",
- abinfo.bytes, cbBuf));
- abinfo.bytes = cbBuf;
- /* Keep going. */
- }
-
- if (abinfo.bytes < 0)
- {
- LogFlowFunc(("Warning: Invalid available size, size=%d, bufsize=%d\n",
- abinfo.bytes, cbBuf));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- cToRead = RT_MIN((uint32_t)AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, abinfo.bytes),
- cLive);
- if (!cToRead)
- break;
-#ifndef RT_OS_L4
- }
-#endif
- size_t cbToRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cToRead);
- LogFlowFunc(("cbToRead=%zu\n", cbToRead));
-
- uint32_t cRead, cbRead;
- while (cbToRead)
- {
- rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf,
- pThisStrmOut->pvPCMBuf, cbToRead, &cRead);
- if (RT_FAILURE(rc))
- break;
-
- cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
- ssize_t cbWritten = write(pThisStrmOut->hFile, pThisStrmOut->pvPCMBuf,
- cbRead);
- if (cbWritten == -1)
- {
- LogRel(("OSS: Failed writing output data: %s\n", strerror(errno)));
- rc = RTErrConvertFromErrno(errno);
- break;
- }
-
- Assert(cbToRead >= cbRead);
- cbToRead -= cbRead;
- cbReadTotal += cbRead;
- }
-
-#ifndef RT_OS_L4
- /* Update read pointer. */
- if (pThisStrmOut->fMemMapped)
- pThisStrmOut->old_optr = cntinfo.ptr;
-#endif
-
- } while(0);
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
- if (cReadTotal)
- AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
-
- if (pcSamplesPlayed)
- *pcSamplesPlayed = cReadTotal;
-
- LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n",
- cReadTotal, cbReadTotal, rc));
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(void) drvHostOSSAudioShutdown(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-}
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvHostOSSAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTOSSAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
-
- return NULL;
-}
-
-/**
- * Constructs an OSS audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvHostOSSAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(pCfg, fFlags);
- PDRVHOSTOSSAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
- LogRel(("Audio: Initializing OSS driver\n"));
-
- /*
- * Init the static parts.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvHostOSSAudioQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostOSSAudio);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Char driver registration record.
- */
-const PDMDRVREG g_DrvHostOSSAudio =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "OSSAudio",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "OSS audio host driver",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVHOSTOSSAUDIO),
- /* pfnConstruct */
- drvHostOSSAudioConstruct,
- /* pfnDestruct */
- NULL,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
diff --git a/src/VBox/Devices/Audio_50/DrvHostPulseAudio.cpp b/src/VBox/Devices/Audio_50/DrvHostPulseAudio.cpp
deleted file mode 100644
index 951ab17..0000000
--- a/src/VBox/Devices/Audio_50/DrvHostPulseAudio.cpp
+++ /dev/null
@@ -1,1257 +0,0 @@
-/* $Id: DrvHostPulseAudio.cpp $ */
-/** @file
- * VBox audio devices: Pulse Audio audio driver.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <VBox/log.h>
-
-#include <stdio.h>
-
-#include <iprt/alloc.h>
-#include <iprt/mem.h>
-#include <iprt/uuid.h>
-
-RT_C_DECLS_BEGIN
- #include "pulse_mangling.h"
- #include "pulse_stubs.h"
-RT_C_DECLS_END
-
-#include <pulse/pulseaudio.h>
-
-#include "DrvAudio.h"
-#include "AudioMixBuffer.h"
-
-#include "VBoxDD.h"
-
-#define VBOX_PULSEAUDIO_MAX_LOG_REL_ERRORS 32 /** @todo Make this configurable thru driver options. */
-
-#ifndef PA_STREAM_NOFLAGS
-# define PA_STREAM_NOFLAGS (pa_context_flags_t)0x0000U /* since 0.9.19 */
-#endif
-
-#ifndef PA_CONTEXT_NOFLAGS
-# define PA_CONTEXT_NOFLAGS (pa_context_flags_t)0x0000U /* since 0.9.19 */
-#endif
-
-/*
- * We use a g_pMainLoop in a separate thread g_pContext. We have to call functions for
- * manipulating objects either from callback functions or we have to protect
- * these functions by pa_threaded_mainloop_lock() / pa_threaded_mainloop_unlock().
- */
-static struct pa_threaded_mainloop *g_pMainLoop;
-static struct pa_context *g_pContext;
-static volatile bool g_fAbortMainLoop;
-
-/**
- * Host Pulse audio driver instance data.
- * @implements PDMIAUDIOCONNECTOR
- */
-typedef struct DRVHOSTPULSEAUDIO
-{
- /** Pointer to the driver instance structure. */
- PPDMDRVINS pDrvIns;
- /** Pointer to host audio interface. */
- PDMIHOSTAUDIO IHostAudio;
- /** Error count for not flooding the release log.
- * UINT32_MAX for unlimited logging. */
- uint32_t cLogErrors;
- /** Configuration option: stream name. */
- char *pszStreamName;
-} DRVHOSTPULSEAUDIO, *PDRVHOSTPULSEAUDIO;
-
-typedef struct PULSEAUDIOSTREAM
-{
- /** Must come first, as this struct might be
- * casted to one of these structs. */
- union
- {
- PDMAUDIOHSTSTRMIN In;
- PDMAUDIOHSTSTRMOUT Out;
- };
- /** Pointer to driver instance. */
- PDRVHOSTPULSEAUDIO pDrv;
- /** DAC/ADC buffer. */
- void *pvPCMBuf;
- /** Size (in bytes) of DAC/ADC buffer. */
- uint32_t cbPCMBuf;
- /** Pointer to opaque PulseAudio stream. */
- pa_stream *pStream;
- /** Pulse sample format and attribute specification. */
- pa_sample_spec SampleSpec;
- /** Pulse playback and buffer metrics. */
- pa_buffer_attr BufAttr;
- int fOpSuccess;
- /** Pointer to Pulse sample peeking buffer. */
- const uint8_t *pu8PeekBuf;
- /** Current size (in bytes) of peeking data in
- * buffer. */
- size_t cbPeekBuf;
- /** Our offset (in bytes) in peeking buffer. */
- size_t offPeekBuf;
- pa_operation *pDrainOp;
-} PULSEAUDIOSTREAM, *PPULSEAUDIOSTREAM;
-
-/* The desired buffer length in milliseconds. Will be the target total stream
- * latency on newer version of pulse. Apparent latency can be less (or more.)
- */
-typedef struct PULSEAUDIOCFG
-{
- RTMSINTERVAL buffer_msecs_out;
- RTMSINTERVAL buffer_msecs_in;
-} PULSEAUDIOCFG, *PPULSEAUDIOCFG;
-
-static PULSEAUDIOCFG s_pulseCfg =
-{
- 100, /* buffer_msecs_out */
- 100 /* buffer_msecs_in */
-};
-
-/** Makes DRVHOSTPULSEAUDIO out of PDMIHOSTAUDIO. */
-#define PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface) \
- ( (PDRVHOSTPULSEAUDIO)((uintptr_t)pInterface - RT_OFFSETOF(DRVHOSTPULSEAUDIO, IHostAudio)) )
-
-static int drvHostPulseAudioError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg);
-static void drvHostPulseAudioCbSuccess(pa_stream *pStream, int fSuccess, void *pvContext);
-
-/**
- * Signal the main loop to abort. Just signalling isn't sufficient as the
- * mainloop might not have been entered yet.
- */
-static void drvHostPulseAudioAbortMainLoop(void)
-{
- g_fAbortMainLoop = true;
- pa_threaded_mainloop_signal(g_pMainLoop, 0);
-}
-
-static pa_sample_format_t drvHostPulseAudioFmtToPulse(PDMAUDIOFMT fmt)
-{
- switch (fmt)
- {
- case AUD_FMT_U8:
- return PA_SAMPLE_U8;
-
- case AUD_FMT_S16:
- return PA_SAMPLE_S16LE;
-
-#ifdef PA_SAMPLE_S32LE
- case AUD_FMT_S32:
- return PA_SAMPLE_S32LE;
-#endif
- default:
- break;
- }
-
- AssertMsgFailed(("Format %ld not supported\n", fmt));
- return PA_SAMPLE_U8;
-}
-
-static int drvHostPulseAudioPulseToFmt(pa_sample_format_t pulsefmt,
- PDMAUDIOFMT *pFmt, PDMAUDIOENDIANNESS *pEndianness)
-{
- switch (pulsefmt)
- {
- case PA_SAMPLE_U8:
- *pFmt = AUD_FMT_U8;
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case PA_SAMPLE_S16LE:
- *pFmt = AUD_FMT_S16;
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-
- case PA_SAMPLE_S16BE:
- *pFmt = AUD_FMT_S16;
- *pEndianness = PDMAUDIOENDIANNESS_BIG;
- break;
-
-#ifdef PA_SAMPLE_S32LE
- case PA_SAMPLE_S32LE:
- *pFmt = AUD_FMT_S32;
- *pEndianness = PDMAUDIOENDIANNESS_LITTLE;
- break;
-#endif
-
-#ifdef PA_SAMPLE_S32BE
- case PA_SAMPLE_S32BE:
- *pFmt = AUD_FMT_S32;
- *pEndianness = PDMAUDIOENDIANNESS_BIG;
- break;
-#endif
-
- default:
- AssertMsgFailed(("Format %ld not supported\n", pulsefmt));
- return VERR_NOT_SUPPORTED;
- }
-
- return VINF_SUCCESS;
-}
-
-/**
- * Synchronously wait until an operation completed.
- */
-static int drvHostPulseAudioWaitFor(pa_operation *pOP, RTMSINTERVAL cMsTimeout)
-{
- AssertPtrReturn(pOP, VERR_INVALID_POINTER);
-
- int rc = VINF_SUCCESS;
- if (pOP)
- {
- uint64_t u64StartMs = RTTimeMilliTS();
- while (pa_operation_get_state(pOP) == PA_OPERATION_RUNNING)
- {
- if (!g_fAbortMainLoop)
- pa_threaded_mainloop_wait(g_pMainLoop);
- g_fAbortMainLoop = false;
-
- uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
- if (u64ElapsedMs >= cMsTimeout)
- {
- rc = VERR_TIMEOUT;
- break;
- }
- }
-
- pa_operation_unref(pOP);
- }
-
- return rc;
-}
-
-/**
- * Context status changed.
- */
-static void drvHostPulseAudioCbCtxState(pa_context *pContext, void *pvUser)
-{
- AssertPtrReturnVoid(pContext);
- NOREF(pvUser);
-
- switch (pa_context_get_state(pContext))
- {
- case PA_CONTEXT_READY:
- case PA_CONTEXT_TERMINATED:
- drvHostPulseAudioAbortMainLoop();
- break;
-
- case PA_CONTEXT_FAILED:
- LogRel(("PulseAudio: Audio input/output stopped!\n"));
- drvHostPulseAudioAbortMainLoop();
- break;
-
- default:
- break;
- }
-}
-
-/**
- * Callback called when our pa_stream_drain operation was completed.
- */
-static void drvHostPulseAudioCbStreamDrain(pa_stream *pStream, int fSuccess, void *pvContext)
-{
- AssertPtrReturnVoid(pStream);
-
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvContext;
- AssertPtrReturnVoid(pStrm);
-
- pStrm->fOpSuccess = fSuccess;
- if (fSuccess)
- {
- pa_operation_unref(pa_stream_cork(pStream, 1,
- drvHostPulseAudioCbSuccess, pvContext));
- }
- else
- drvHostPulseAudioError(pStrm->pDrv, "Failed to drain stream");
-
- pa_operation_unref(pStrm->pDrainOp);
- pStrm->pDrainOp = NULL;
-}
-
-/**
- * Stream status changed.
- */
-static void drvHostPulseAudioCbStreamState(pa_stream *pStream, void *pvContext)
-{
- AssertPtrReturnVoid(pStream);
- NOREF(pvContext);
-
- switch (pa_stream_get_state(pStream))
- {
- case PA_STREAM_READY:
- case PA_STREAM_FAILED:
- case PA_STREAM_TERMINATED:
- drvHostPulseAudioAbortMainLoop();
- break;
-
- default:
- break;
- }
-}
-
-static void drvHostPulseAudioCbSuccess(pa_stream *pStream, int fSuccess, void *pvContext)
-{
- AssertPtrReturnVoid(pStream);
-
- PPULSEAUDIOSTREAM pStrm = (PPULSEAUDIOSTREAM)pvContext;
- AssertPtrReturnVoid(pStrm);
-
- pStrm->fOpSuccess = fSuccess;
-
- if (fSuccess)
- drvHostPulseAudioAbortMainLoop();
- else
- drvHostPulseAudioError(pStrm->pDrv, "Failed to finish stream operation");
-}
-
-static int drvHostPulseAudioOpen(bool fIn, const char *pszName,
- pa_sample_spec *pSampleSpec, pa_buffer_attr *pBufAttr,
- pa_stream **ppStream)
-{
- AssertPtrReturn(pszName, VERR_INVALID_POINTER);
- AssertPtrReturn(pSampleSpec, VERR_INVALID_POINTER);
- AssertPtrReturn(pBufAttr, VERR_INVALID_POINTER);
- AssertPtrReturn(ppStream, VERR_INVALID_POINTER);
-
- if (!pa_sample_spec_valid(pSampleSpec))
- {
- LogRel(("PulseAudio: Unsupported sample specification for stream \"%s\"\n",
- pszName));
- return VERR_NOT_SUPPORTED;
- }
-
- int rc = VINF_SUCCESS;
-
- pa_stream *pStream = NULL;
- uint32_t flags = PA_STREAM_NOFLAGS;
-
- LogFunc(("Opening \"%s\", rate=%dHz, channels=%d, format=%s\n",
- pszName, pSampleSpec->rate, pSampleSpec->channels,
- pa_sample_format_to_string(pSampleSpec->format)));
-
- pa_threaded_mainloop_lock(g_pMainLoop);
-
- do
- {
- if (!(pStream = pa_stream_new(g_pContext, pszName, pSampleSpec,
- NULL /* pa_channel_map */)))
- {
- LogRel(("PulseAudio: Could not create stream \"%s\"\n", pszName));
- rc = VERR_NO_MEMORY;
- break;
- }
-
- pa_stream_set_state_callback(pStream, drvHostPulseAudioCbStreamState, NULL);
-
-#if PA_API_VERSION >= 12
- /* XXX */
- flags |= PA_STREAM_ADJUST_LATENCY;
-#endif
-
-#if 0
- /* Not applicable as we don't use pa_stream_get_latency() and pa_stream_get_time(). */
- flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
-#endif
- /* No input/output right away after the stream was started. */
- flags |= PA_STREAM_START_CORKED;
-
- if (fIn)
- {
- LogFunc(("Input stream attributes: maxlength=%d fragsize=%d\n",
- pBufAttr->maxlength, pBufAttr->fragsize));
-
- if (pa_stream_connect_record(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags) < 0)
- {
- LogRel(("PulseAudio: Could not connect input stream \"%s\": %s\n",
- pszName, pa_strerror(pa_context_errno(g_pContext))));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- }
- else
- {
- LogFunc(("Output buffer attributes: maxlength=%d tlength=%d prebuf=%d minreq=%d\n",
- pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
-
- if (pa_stream_connect_playback(pStream, /*dev=*/NULL, pBufAttr, (pa_stream_flags_t)flags,
- /*cvolume=*/NULL, /*sync_stream=*/NULL) < 0)
- {
- LogRel(("PulseAudio: Could not connect playback stream \"%s\": %s\n",
- pszName, pa_strerror(pa_context_errno(g_pContext))));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- }
-
- /* Wait until the stream is ready. */
- for (;;)
- {
- if (!g_fAbortMainLoop)
- pa_threaded_mainloop_wait(g_pMainLoop);
- g_fAbortMainLoop = false;
-
- pa_stream_state_t sstate = pa_stream_get_state(pStream);
- if (sstate == PA_STREAM_READY)
- break;
- else if ( sstate == PA_STREAM_FAILED
- || sstate == PA_STREAM_TERMINATED)
- {
- LogRel(("PulseAudio: Failed to initialize stream \"%s\" (state %ld)\n",
- pszName, sstate));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- }
-
- if (RT_FAILURE(rc))
- break;
-
- const pa_buffer_attr *pBufAttrObtained = pa_stream_get_buffer_attr(pStream);
- AssertPtr(pBufAttrObtained);
- memcpy(pBufAttr, pBufAttrObtained, sizeof(pa_buffer_attr));
-
- if (fIn)
- LogFunc(("Obtained record buffer attributes: maxlength=%RU32, fragsize=%RU32\n",
- pBufAttr->maxlength, pBufAttr->fragsize));
- else
- LogFunc(("Obtained playback buffer attributes: maxlength=%d, tlength=%d, prebuf=%d, minreq=%d\n",
- pBufAttr->maxlength, pBufAttr->tlength, pBufAttr->prebuf, pBufAttr->minreq));
-
- }
- while (0);
-
- if ( RT_FAILURE(rc)
- && pStream)
- pa_stream_disconnect(pStream);
-
- pa_threaded_mainloop_unlock(g_pMainLoop);
-
- if (RT_FAILURE(rc))
- {
- if (pStream)
- pa_stream_unref(pStream);
- }
- else
- *ppStream = pStream;
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-
- LogFlowFuncEnter();
-
- int rc = audioLoadPulseLib();
- if (RT_FAILURE(rc))
- {
- LogRel(("PulseAudio: Failed to load the PulseAudio shared library! Error %Rrc\n", rc));
- return rc;
- }
-
- bool fLocked = false;
-
- do
- {
- if (!(g_pMainLoop = pa_threaded_mainloop_new()))
- {
- LogRel(("PulseAudio: Failed to allocate main loop: %s\n",
- pa_strerror(pa_context_errno(g_pContext))));
- rc = VERR_NO_MEMORY;
- break;
- }
-
- if (!(g_pContext = pa_context_new(pa_threaded_mainloop_get_api(g_pMainLoop), "VirtualBox")))
- {
- LogRel(("PulseAudio: Failed to allocate context: %s\n",
- pa_strerror(pa_context_errno(g_pContext))));
- rc = VERR_NO_MEMORY;
- break;
- }
-
- if (pa_threaded_mainloop_start(g_pMainLoop) < 0)
- {
- LogRel(("PulseAudio: Failed to start threaded mainloop: %s\n",
- pa_strerror(pa_context_errno(g_pContext))));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- g_fAbortMainLoop = false;
- pa_context_set_state_callback(g_pContext, drvHostPulseAudioCbCtxState, NULL);
- pa_threaded_mainloop_lock(g_pMainLoop);
- fLocked = true;
-
- if (pa_context_connect(g_pContext, NULL /* pszServer */,
- PA_CONTEXT_NOFLAGS, NULL) < 0)
- {
- LogRel(("PulseAudio: Failed to connect to server: %s\n",
- pa_strerror(pa_context_errno(g_pContext))));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
-
- /* Wait until the g_pContext is ready */
- for (;;)
- {
- if (!g_fAbortMainLoop)
- pa_threaded_mainloop_wait(g_pMainLoop);
- g_fAbortMainLoop = false;
-
- pa_context_state_t cstate = pa_context_get_state(g_pContext);
- if (cstate == PA_CONTEXT_READY)
- break;
- else if ( cstate == PA_CONTEXT_TERMINATED
- || cstate == PA_CONTEXT_FAILED)
- {
- LogRel(("PulseAudio: Failed to initialize context (state %d)\n", cstate));
- rc = VERR_AUDIO_BACKEND_INIT_FAILED;
- break;
- }
- }
- }
- while (0);
-
- if (fLocked)
- pa_threaded_mainloop_unlock(g_pMainLoop);
-
- if (RT_FAILURE(rc))
- {
- if (g_pMainLoop)
- pa_threaded_mainloop_stop(g_pMainLoop);
-
- if (g_pContext)
- {
- pa_context_disconnect(g_pContext);
- pa_context_unref(g_pContext);
- g_pContext = NULL;
- }
-
- if (g_pMainLoop)
- {
- pa_threaded_mainloop_free(g_pMainLoop);
- g_pMainLoop = NULL;
- }
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioInitOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- uint32_t *pcSamples)
-{
- RT_NOREF(pCfgAcq);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- /* pcSamples is optional. */
-
- PDRVHOSTPULSEAUDIO pDrv = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
-
- LogFlowFuncEnter();
-
- pThisStrmOut->pDrainOp = NULL;
-
- pThisStrmOut->SampleSpec.format = drvHostPulseAudioFmtToPulse(pCfgReq->enmFormat);
- pThisStrmOut->SampleSpec.rate = pCfgReq->uHz;
- pThisStrmOut->SampleSpec.channels = pCfgReq->cChannels;
-
- /* Note that setting maxlength to -1 does not work on PulseAudio servers
- * older than 0.9.10. So use the suggested value of 3/2 of tlength */
- pThisStrmOut->BufAttr.tlength = (pa_bytes_per_second(&pThisStrmOut->SampleSpec)
- * s_pulseCfg.buffer_msecs_out) / 1000;
- pThisStrmOut->BufAttr.maxlength = (pThisStrmOut->BufAttr.tlength * 3) / 2;
- pThisStrmOut->BufAttr.prebuf = -1; /* Same as tlength */
- pThisStrmOut->BufAttr.minreq = -1; /* Pulse should set something sensible for minreq on it's own */
-
- /* Note that the struct BufAttr is updated to the obtained values after this call! */
- char achName[64];
- RTStrPrintf(achName, sizeof(achName), "%.32s (out)", pDrv->pszStreamName);
- int rc = drvHostPulseAudioOpen(false /* fIn */, achName, &pThisStrmOut->SampleSpec, &pThisStrmOut->BufAttr,
- &pThisStrmOut->pStream);
- if (RT_FAILURE(rc))
- return rc;
-
- PDMAUDIOSTREAMCFG streamCfg;
- rc = drvHostPulseAudioPulseToFmt(pThisStrmOut->SampleSpec.format,
- &streamCfg.enmFormat, &streamCfg.enmEndianness);
- if (RT_FAILURE(rc))
- {
- LogRel(("PulseAudio: Cannot find audio output format %ld\n", pThisStrmOut->SampleSpec.format));
- return rc;
- }
-
- streamCfg.uHz = pThisStrmOut->SampleSpec.rate;
- streamCfg.cChannels = pThisStrmOut->SampleSpec.channels;
-
- rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmOut->Props);
- if (RT_SUCCESS(rc))
- {
- uint32_t cbBuf = RT_MIN(pThisStrmOut->BufAttr.tlength * 2,
- pThisStrmOut->BufAttr.maxlength); /** @todo Make this configurable! */
- if (cbBuf)
- {
- pThisStrmOut->pvPCMBuf = RTMemAllocZ(cbBuf);
- if (pThisStrmOut->pvPCMBuf)
- {
- pThisStrmOut->cbPCMBuf = cbBuf;
-
- uint32_t cSamples = cbBuf >> pHstStrmOut->Props.cShift;
- if (pcSamples)
- *pcSamples = cSamples;
-
- /* Save pointer to driver instance. */
- pThisStrmOut->pDrv = pDrv;
-
- LogFunc(("cbBuf=%RU32, cSamples=%RU32\n", cbBuf, cSamples));
- }
- else
- rc = VERR_NO_MEMORY;
- }
- else
- rc = VERR_INVALID_PARAMETER;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(bool) drvHostPulseAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- NOREF(pInterface);
- NOREF(enmDir);
- return true; /* Always all enabled. */
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioInitIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- PDMAUDIORECSOURCE enmRecSource,
- uint32_t *pcSamples)
-{
- RT_NOREF(pCfgAcq, enmRecSource);
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- /* pcSamples is optional. */
-
- PDRVHOSTPULSEAUDIO pDrv = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface);
- PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
-
- LogFunc(("enmRecSrc=%ld\n", enmRecSource));
-
- pThisStrmIn->SampleSpec.format = drvHostPulseAudioFmtToPulse(pCfgReq->enmFormat);
- pThisStrmIn->SampleSpec.rate = pCfgReq->uHz;
- pThisStrmIn->SampleSpec.channels = pCfgReq->cChannels;
-
- /* XXX check these values */
- pThisStrmIn->BufAttr.fragsize = (pa_bytes_per_second(&pThisStrmIn->SampleSpec)
- * s_pulseCfg.buffer_msecs_in) / 1000;
- pThisStrmIn->BufAttr.maxlength = (pThisStrmIn->BufAttr.fragsize * 3) / 2;
- /* Note: Other members of pa_buffer_attr are ignored for record streams. */
-
- char achName[64];
- RTStrPrintf(achName, sizeof(achName), "%.32s (in)", pDrv->pszStreamName);
- int rc = drvHostPulseAudioOpen(true /* fIn */, achName, &pThisStrmIn->SampleSpec, &pThisStrmIn->BufAttr,
- &pThisStrmIn->pStream);
- if (RT_FAILURE(rc))
- return rc;
-
- PDMAUDIOSTREAMCFG streamCfg;
- rc = drvHostPulseAudioPulseToFmt(pThisStrmIn->SampleSpec.format, &streamCfg.enmFormat,
- &streamCfg.enmEndianness);
- if (RT_FAILURE(rc))
- {
- LogRel(("PulseAudio: Cannot find audio capture format %ld\n", pThisStrmIn->SampleSpec.format));
- return rc;
- }
-
- streamCfg.uHz = pThisStrmIn->SampleSpec.rate;
- streamCfg.cChannels = pThisStrmIn->SampleSpec.channels;
-
- rc = DrvAudioStreamCfgToProps(&streamCfg, &pHstStrmIn->Props);
- if (RT_SUCCESS(rc))
- {
- uint32_t cSamples = RT_MIN(pThisStrmIn->BufAttr.fragsize * 10, pThisStrmIn->BufAttr.maxlength)
- >> pHstStrmIn->Props.cShift;
- LogFunc(("cShift=%RU8, cSamples=%RU32\n", pHstStrmIn->Props.cShift, cSamples));
-
- if (pcSamples)
- *pcSamples = cSamples;
-
- /* Save pointer to driver instance. */
- pThisStrmIn->pDrv = pDrv;
-
- pThisStrmIn->pu8PeekBuf = NULL;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- uint32_t *pcSamplesCaptured)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- /* pcSamplesPlayed is optional. */
-
- PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
-
- /* We should only call pa_stream_readable_size() once and trust the first value. */
- pa_threaded_mainloop_lock(g_pMainLoop);
- size_t cbAvail = pa_stream_readable_size(pThisStrmIn->pStream);
- pa_threaded_mainloop_unlock(g_pMainLoop);
-
- if (cbAvail == (size_t)-1)
- return drvHostPulseAudioError(pThisStrmIn->pDrv, "Failed to determine input data size");
-
- /* If the buffer was not dropped last call, add what remains. */
- if (pThisStrmIn->pu8PeekBuf)
- {
- Assert(pThisStrmIn->cbPeekBuf >= pThisStrmIn->offPeekBuf);
- cbAvail += (pThisStrmIn->cbPeekBuf - pThisStrmIn->offPeekBuf);
- }
-
- if (!cbAvail) /* No data? Bail out. */
- {
- if (pcSamplesCaptured)
- *pcSamplesCaptured = 0;
- return VINF_SUCCESS;
- }
-
- int rc = VINF_SUCCESS;
- size_t cbToRead = RT_MIN(cbAvail, AudioMixBufFreeBytes(&pHstStrmIn->MixBuf));
-
- LogFlowFunc(("cbToRead=%zu, cbAvail=%zu, offPeekBuf=%zu, cbPeekBuf=%zu\n",
- cbToRead, cbAvail, pThisStrmIn->offPeekBuf, pThisStrmIn->cbPeekBuf));
-
- uint32_t cWrittenTotal = 0;
-
- while (cbToRead)
- {
- /* If there is no data, do another peek. */
- if (!pThisStrmIn->pu8PeekBuf)
- {
- pa_threaded_mainloop_lock(g_pMainLoop);
- pa_stream_peek(pThisStrmIn->pStream,
- (const void**)&pThisStrmIn->pu8PeekBuf, &pThisStrmIn->cbPeekBuf);
- pa_threaded_mainloop_unlock(g_pMainLoop);
-
- pThisStrmIn->offPeekBuf = 0;
-
- /* No data anymore?
- * Note: If there's a data hole (cbPeekBuf then contains the length of the hole)
- * we need to drop the stream lateron. */
- if ( !pThisStrmIn->pu8PeekBuf
- && !pThisStrmIn->cbPeekBuf)
- {
- break;
- }
- }
-
- Assert(pThisStrmIn->cbPeekBuf >= pThisStrmIn->offPeekBuf);
- size_t cbToWrite = RT_MIN(pThisStrmIn->cbPeekBuf - pThisStrmIn->offPeekBuf, cbToRead);
-
- LogFlowFunc(("cbToRead=%zu, cbToWrite=%zu, offPeekBuf=%zu, cbPeekBuf=%zu, pu8PeekBuf=%p\n",
- cbToRead, cbToWrite,
- pThisStrmIn->offPeekBuf, pThisStrmIn->cbPeekBuf, pThisStrmIn->pu8PeekBuf));
-
- if (cbToWrite)
- {
- uint32_t cWritten;
- rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf,
- pThisStrmIn->pu8PeekBuf + pThisStrmIn->offPeekBuf,
- cbToWrite, &cWritten);
- if (RT_FAILURE(rc))
- break;
-
- uint32_t cbWritten = AUDIOMIXBUF_S2B(&pHstStrmIn->MixBuf, cWritten);
-
- Assert(cbToRead >= cbWritten);
- cbToRead -= cbWritten;
- cWrittenTotal += cWritten;
- pThisStrmIn->offPeekBuf += cbWritten;
- }
-
- if (/* Nothing to write anymore? Drop the buffer. */
- !cbToWrite
- /* Was there a hole in the peeking buffer? Drop it. */
- || !pThisStrmIn->pu8PeekBuf
- /* If the buffer is done, drop it. */
- || pThisStrmIn->offPeekBuf == pThisStrmIn->cbPeekBuf)
- {
- pa_threaded_mainloop_lock(g_pMainLoop);
- pa_stream_drop(pThisStrmIn->pStream);
- pa_threaded_mainloop_unlock(g_pMainLoop);
-
- pThisStrmIn->pu8PeekBuf = NULL;
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cProcessed = 0;
- if (cWrittenTotal)
- rc = AudioMixBufMixToParent(&pHstStrmIn->MixBuf, cWrittenTotal,
- &cProcessed);
-
- if (pcSamplesCaptured)
- *pcSamplesCaptured = cWrittenTotal;
-
- LogFlowFunc(("cWrittenTotal=%RU32 (%RU32 processed), rc=%Rrc\n",
- cWrittenTotal, cProcessed, rc));
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- uint32_t *pcSamplesPlayed)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- /* pcSamplesPlayed is optional. */
-
- PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
-
- int rc = VINF_SUCCESS;
- uint32_t cbReadTotal = 0;
-
- uint32_t cLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
- if (!cLive)
- {
- LogFlowFunc(("%p: No live samples, skipping\n", pHstStrmOut));
-
- if (pcSamplesPlayed)
- *pcSamplesPlayed = 0;
- return VINF_SUCCESS;
- }
-
- pa_threaded_mainloop_lock(g_pMainLoop);
-
- do
- {
- size_t cbWriteable = pa_stream_writable_size(pThisStrmOut->pStream);
- if (cbWriteable == (size_t)-1)
- {
- rc = drvHostPulseAudioError(pThisStrmOut->pDrv, "Failed to determine output data size");
- break;
- }
-
- size_t cbLive = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cLive);
- size_t cbToRead = RT_MIN(cbWriteable, cbLive);
-
- LogFlowFunc(("cbToRead=%zu, cbWriteable=%zu, cbLive=%zu\n",
- cbToRead, cbWriteable, cbLive));
-
- uint32_t cRead, cbRead;
- while (cbToRead)
- {
- rc = AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pThisStrmOut->pvPCMBuf,
- RT_MIN(cbToRead, pThisStrmOut->cbPCMBuf), &cRead);
- if ( !cRead
- || RT_FAILURE(rc))
- {
- break;
- }
-
- cbRead = AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead);
- if (pa_stream_write(pThisStrmOut->pStream, pThisStrmOut->pvPCMBuf, cbRead, NULL /* Cleanup callback */,
- 0, PA_SEEK_RELATIVE) < 0)
- {
- rc = drvHostPulseAudioError(pThisStrmOut->pDrv, "Failed to write to output stream");
- break;
- }
-
- Assert(cbToRead >= cbRead);
- cbToRead -= cbRead;
- cbReadTotal += cbRead;
-
- LogFlowFunc(("\tcRead=%RU32 (%zu bytes) cbReadTotal=%RU32, cbToRead=%RU32\n",
- cRead, AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cRead), cbReadTotal, cbToRead));
- }
-
- } while (0);
-
- pa_threaded_mainloop_unlock(g_pMainLoop);
-
- if (RT_SUCCESS(rc))
- {
- uint32_t cReadTotal = AUDIOMIXBUF_B2S(&pHstStrmOut->MixBuf, cbReadTotal);
- if (cReadTotal)
- AudioMixBufFinish(&pHstStrmOut->MixBuf, cReadTotal);
-
- if (pcSamplesPlayed)
- *pcSamplesPlayed = cReadTotal;
-
- LogFlowFunc(("cReadTotal=%RU32 (%RU32 bytes), rc=%Rrc\n", cReadTotal, cbReadTotal, rc));
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-/** @todo Implement va handling. */
-static int drvHostPulseAudioError(PDRVHOSTPULSEAUDIO pThis, const char *szMsg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(szMsg, VERR_INVALID_POINTER);
-
- if (pThis->cLogErrors++ < VBOX_PULSEAUDIO_MAX_LOG_REL_ERRORS)
- {
- int rc2 = pa_context_errno(g_pContext);
- LogRel(("PulseAudio: %s: %s\n", szMsg, pa_strerror(rc2)));
- }
-
- /** @todo Implement some PulseAudio -> IPRT mapping here. */
- return VERR_GENERAL_FAILURE;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
-
- PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
- if (pThisStrmIn->pStream)
- {
- pa_threaded_mainloop_lock(g_pMainLoop);
- pa_stream_disconnect(pThisStrmIn->pStream);
- pa_stream_unref(pThisStrmIn->pStream);
- pa_threaded_mainloop_unlock(g_pMainLoop);
-
- pThisStrmIn->pStream = NULL;
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
-
- PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
- if (pThisStrmOut->pStream)
- {
- pa_threaded_mainloop_lock(g_pMainLoop);
- pa_stream_disconnect(pThisStrmOut->pStream);
- pa_stream_unref(pThisStrmOut->pStream);
- pa_threaded_mainloop_unlock(g_pMainLoop);
-
- pThisStrmOut->pStream = NULL;
- }
-
- if (pThisStrmOut->pvPCMBuf)
- {
- RTMemFree(pThisStrmOut->pvPCMBuf);
- pThisStrmOut->pvPCMBuf = NULL;
-
- pThisStrmOut->cbPCMBuf = 0;
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioControlOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOHSTSTRMOUT pHstStrmOut, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
-
- PPULSEAUDIOSTREAM pThisStrmOut = (PPULSEAUDIOSTREAM)pHstStrmOut;
- int rc = VINF_SUCCESS;
-
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- pa_threaded_mainloop_lock(g_pMainLoop);
-
- if ( pThisStrmOut->pDrainOp
- && pa_operation_get_state(pThisStrmOut->pDrainOp) != PA_OPERATION_DONE)
- {
- pa_operation_cancel(pThisStrmOut->pDrainOp);
- pa_operation_unref(pThisStrmOut->pDrainOp);
-
- pThisStrmOut->pDrainOp = NULL;
- }
- else
- {
- /* This should return immediately. */
- rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmOut->pStream, 0,
- drvHostPulseAudioCbSuccess, pThisStrmOut),
- 15 * 1000 /* 15s timeout */);
- }
-
- pa_threaded_mainloop_unlock(g_pMainLoop);
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- /* Pause audio output (the Pause bit of the AC97 x_CR register is set).
- * Note that we must return immediately from here! */
- pa_threaded_mainloop_lock(g_pMainLoop);
- if (!pThisStrmOut->pDrainOp)
- {
- /* This should return immediately. */
- rc = drvHostPulseAudioWaitFor(pa_stream_trigger(pThisStrmOut->pStream,
- drvHostPulseAudioCbSuccess, pThisStrmOut),
- 15 * 1000 /* 15s timeout */);
- if (RT_LIKELY(RT_SUCCESS(rc)))
- pThisStrmOut->pDrainOp = pa_stream_drain(pThisStrmOut->pStream,
- drvHostPulseAudioCbStreamDrain, pThisStrmOut);
- }
- pa_threaded_mainloop_unlock(g_pMainLoop);
- break;
- }
-
- default:
- AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- NOREF(pInterface);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- PPULSEAUDIOSTREAM pThisStrmIn = (PPULSEAUDIOSTREAM)pHstStrmIn;
- int rc = VINF_SUCCESS;
-
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-
- switch (enmStreamCmd)
- {
- case PDMAUDIOSTREAMCMD_ENABLE:
- case PDMAUDIOSTREAMCMD_RESUME:
- {
- pa_threaded_mainloop_lock(g_pMainLoop);
- /* This should return immediately. */
- rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmIn->pStream, 0 /* Play / resume */,
- drvHostPulseAudioCbSuccess, pThisStrmIn),
- 15 * 1000 /* 15s timeout */);
- pa_threaded_mainloop_unlock(g_pMainLoop);
- break;
- }
-
- case PDMAUDIOSTREAMCMD_DISABLE:
- case PDMAUDIOSTREAMCMD_PAUSE:
- {
- pa_threaded_mainloop_lock(g_pMainLoop);
- if (pThisStrmIn->pu8PeekBuf) /* Do we need to drop the peek buffer?*/
- {
- pa_stream_drop(pThisStrmIn->pStream);
- pThisStrmIn->pu8PeekBuf = NULL;
- }
- /* This should return immediately. */
- rc = drvHostPulseAudioWaitFor(pa_stream_cork(pThisStrmIn->pStream, 1 /* Stop / pause */,
- drvHostPulseAudioCbSuccess, pThisStrmIn),
- 15 * 1000 /* 15s timeout */);
- pa_threaded_mainloop_unlock(g_pMainLoop);
- break;
- }
-
- default:
- AssertMsgFailed(("Invalid command %ld\n", enmStreamCmd));
- rc = VERR_INVALID_PARAMETER;
- break;
- }
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvHostPulseAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
- NOREF(pInterface);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- pCfg->cbStreamOut = sizeof(PULSEAUDIOSTREAM);
- pCfg->cbStreamIn = sizeof(PULSEAUDIOSTREAM);
- pCfg->cMaxHstStrmsOut = UINT32_MAX;
- pCfg->cMaxHstStrmsIn = UINT32_MAX;
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(void) drvHostPulseAudioShutdown(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-
- LogFlowFuncEnter();
-
- if (g_pMainLoop)
- pa_threaded_mainloop_stop(g_pMainLoop);
-
- if (g_pContext)
- {
- pa_context_disconnect(g_pContext);
- pa_context_unref(g_pContext);
- g_pContext = NULL;
- }
-
- if (g_pMainLoop)
- {
- pa_threaded_mainloop_free(g_pMainLoop);
- g_pMainLoop = NULL;
- }
-
- LogFlowFuncLeave();
-}
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvHostPulseAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- AssertPtrReturn(pInterface, NULL);
- AssertPtrReturn(pszIID, NULL);
-
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
-
- return NULL;
-}
-
-/**
- * Constructs a PulseAudio Audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(int) drvHostPulseAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(fFlags);
- AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
-
- PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO);
- LogRel(("Audio: Initializing PulseAudio driver\n"));
-
- CFGMR3QueryStringAlloc(pCfg, "StreamName", &pThis->pszStreamName);
-
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvHostPulseAudioQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostPulseAudio);
-
- return VINF_SUCCESS;
-}
-
-/**
- * Destructs a PulseAudio Audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-static DECLCALLBACK(void) drvHostPulseAudioDestruct(PPDMDRVINS pDrvIns)
-{
- PDRVHOSTPULSEAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPULSEAUDIO);
- LogFlowFuncEnter();
- if (pThis->pszStreamName)
- {
- MMR3HeapFree(pThis->pszStreamName);
- pThis->pszStreamName = NULL;
- }
-}
-
-/**
- * Char driver registration record.
- */
-const PDMDRVREG g_DrvHostPulseAudio =
-{
- /* u32Version */
- PDM_DRVREG_VERSION,
- /* szName */
- "PulseAudio",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Pulse Audio host driver",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVHOSTPULSEAUDIO),
- /* pfnConstruct */
- drvHostPulseAudioConstruct,
- /* pfnDestruct */
- drvHostPulseAudioDestruct,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
-
-#if 0 // unused
-static struct audio_option pulse_options[] =
-{
- {"DAC_MS", AUD_OPT_INT, &s_pulseCfg.buffer_msecs_out,
- "DAC period size in milliseconds", NULL, 0},
- {"ADC_MS", AUD_OPT_INT, &s_pulseCfg.buffer_msecs_in,
- "ADC period size in milliseconds", NULL, 0},
-
- NULL
-};
-#endif
diff --git a/src/VBox/Devices/Audio_50/HDACodec.cpp b/src/VBox/Devices/Audio_50/HDACodec.cpp
deleted file mode 100644
index ba6d027..0000000
--- a/src/VBox/Devices/Audio_50/HDACodec.cpp
+++ /dev/null
@@ -1,2782 +0,0 @@
-/* $Id: HDACodec.cpp $ */
-/** @file
- * DevIchHdaCodec - VBox ICH Intel HD Audio Codec.
- *
- * Implemented against "Intel I/O Controller Hub 6 (ICH6) High Definition
- * Audio / AC '97 - Programmer's Reference Manual (PRM)", document number
- * 302349-003.
- */
-
-/*
- * Copyright (C) 2006-2016 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DEV_HDA_CODEC
-#include <VBox/vmm/pdmdev.h>
-#include <VBox/vmm/pdmaudioifs.h>
-#include <iprt/assert.h>
-#include <iprt/uuid.h>
-#include <iprt/string.h>
-#include <iprt/mem.h>
-#include <iprt/asm.h>
-#include <iprt/cpp/utils.h>
-
-#include "VBoxDD.h"
-#include "DevIchHdaCodec.h"
-
-
-/*********************************************************************************************************************************
-* Defined Constants And Macros *
-*********************************************************************************************************************************/
-/* PRM 5.3.1 */
-/** Codec address mask. */
-#define CODEC_CAD_MASK 0xF0000000
-/** Codec address shift. */
-#define CODEC_CAD_SHIFT 28
-#define CODEC_DIRECT_MASK RT_BIT(27)
-/** Node ID mask. */
-#define CODEC_NID_MASK 0x07F00000
-/** Node ID shift. */
-#define CODEC_NID_SHIFT 20
-#define CODEC_VERBDATA_MASK 0x000FFFFF
-#define CODEC_VERB_4BIT_CMD 0x000FFFF0
-#define CODEC_VERB_4BIT_DATA 0x0000000F
-#define CODEC_VERB_8BIT_CMD 0x000FFF00
-#define CODEC_VERB_8BIT_DATA 0x000000FF
-#define CODEC_VERB_16BIT_CMD 0x000F0000
-#define CODEC_VERB_16BIT_DATA 0x0000FFFF
-
-#define CODEC_CAD(cmd) (((cmd) & CODEC_CAD_MASK) >> CODEC_CAD_SHIFT)
-#define CODEC_DIRECT(cmd) ((cmd) & CODEC_DIRECT_MASK)
-#define CODEC_NID(cmd) ((((cmd) & CODEC_NID_MASK)) >> CODEC_NID_SHIFT)
-#define CODEC_VERBDATA(cmd) ((cmd) & CODEC_VERBDATA_MASK)
-#define CODEC_VERB_CMD(cmd, mask, x) (((cmd) & (mask)) >> (x))
-#define CODEC_VERB_CMD4(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_4BIT_CMD, 4))
-#define CODEC_VERB_CMD8(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_8BIT_CMD, 8))
-#define CODEC_VERB_CMD16(cmd) (CODEC_VERB_CMD((cmd), CODEC_VERB_16BIT_CMD, 16))
-#define CODEC_VERB_PAYLOAD4(cmd) ((cmd) & CODEC_VERB_4BIT_DATA)
-#define CODEC_VERB_PAYLOAD8(cmd) ((cmd) & CODEC_VERB_8BIT_DATA)
-#define CODEC_VERB_PAYLOAD16(cmd) ((cmd) & CODEC_VERB_16BIT_DATA)
-
-#define CODEC_VERB_GET_AMP_DIRECTION RT_BIT(15)
-#define CODEC_VERB_GET_AMP_SIDE RT_BIT(13)
-#define CODEC_VERB_GET_AMP_INDEX 0x7
-
-/* HDA spec 7.3.3.7 NoteA */
-#define CODEC_GET_AMP_DIRECTION(cmd) (((cmd) & CODEC_VERB_GET_AMP_DIRECTION) >> 15)
-#define CODEC_GET_AMP_SIDE(cmd) (((cmd) & CODEC_VERB_GET_AMP_SIDE) >> 13)
-#define CODEC_GET_AMP_INDEX(cmd) (CODEC_GET_AMP_DIRECTION(cmd) ? 0 : ((cmd) & CODEC_VERB_GET_AMP_INDEX))
-
-/* HDA spec 7.3.3.7 NoteC */
-#define CODEC_VERB_SET_AMP_OUT_DIRECTION RT_BIT(15)
-#define CODEC_VERB_SET_AMP_IN_DIRECTION RT_BIT(14)
-#define CODEC_VERB_SET_AMP_LEFT_SIDE RT_BIT(13)
-#define CODEC_VERB_SET_AMP_RIGHT_SIDE RT_BIT(12)
-#define CODEC_VERB_SET_AMP_INDEX (0x7 << 8)
-#define CODEC_VERB_SET_AMP_MUTE RT_BIT(7)
-/** Note: 7-bit value [6:0]. */
-#define CODEC_VERB_SET_AMP_GAIN 0x7F
-
-#define CODEC_SET_AMP_IS_OUT_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_OUT_DIRECTION) != 0)
-#define CODEC_SET_AMP_IS_IN_DIRECTION(cmd) (((cmd) & CODEC_VERB_SET_AMP_IN_DIRECTION) != 0)
-#define CODEC_SET_AMP_IS_LEFT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_LEFT_SIDE) != 0)
-#define CODEC_SET_AMP_IS_RIGHT_SIDE(cmd) (((cmd) & CODEC_VERB_SET_AMP_RIGHT_SIDE) != 0)
-#define CODEC_SET_AMP_INDEX(cmd) (((cmd) & CODEC_VERB_SET_AMP_INDEX) >> 7)
-#define CODEC_SET_AMP_MUTE(cmd) ((cmd) & CODEC_VERB_SET_AMP_MUTE)
-#define CODEC_SET_AMP_GAIN(cmd) ((cmd) & CODEC_VERB_SET_AMP_GAIN)
-
-/* HDA spec 7.3.3.1 defines layout of configuration registers/verbs (0xF00) */
-/* VendorID (7.3.4.1) */
-#define CODEC_MAKE_F00_00(vendorID, deviceID) (((vendorID) << 16) | (deviceID))
-#define CODEC_F00_00_VENDORID(f00_00) (((f00_00) >> 16) & 0xFFFF)
-#define CODEC_F00_00_DEVICEID(f00_00) ((f00_00) & 0xFFFF)
-/* RevisionID (7.3.4.2)*/
-#define CODEC_MAKE_F00_02(MajRev, MinRev, RevisionID, SteppingID) (((MajRev) << 20)|((MinRev) << 16)|((RevisionID) << 8)|(SteppingID))
-/* Subordinate node count (7.3.4.3)*/
-#define CODEC_MAKE_F00_04(startNodeNumber, totalNodeNumber) ((((startNodeNumber) & 0xFF) << 16)|((totalNodeNumber) & 0xFF))
-#define CODEC_F00_04_TO_START_NODE_NUMBER(f00_04) (((f00_04) >> 16) & 0xFF)
-#define CODEC_F00_04_TO_NODE_COUNT(f00_04) ((f00_04) & 0xFF)
-/*
- * Function Group Type (7.3.4.4)
- * 0 & [0x3-0x7f] are reserved types
- * [0x80 - 0xff] are vendor defined function groups
- */
-#define CODEC_MAKE_F00_05(UnSol, NodeType) (((UnSol) << 8)|(NodeType))
-#define CODEC_F00_05_UNSOL RT_BIT(8)
-#define CODEC_F00_05_AFG (0x1)
-#define CODEC_F00_05_MFG (0x2)
-#define CODEC_F00_05_IS_UNSOL(f00_05) RT_BOOL((f00_05) & RT_BIT(8))
-#define CODEC_F00_05_GROUP(f00_05) ((f00_05) & 0xff)
-/* Audio Function Group capabilities (7.3.4.5) */
-#define CODEC_MAKE_F00_08(BeepGen, InputDelay, OutputDelay) ((((BeepGen) & 0x1) << 16)| (((InputDelay) & 0xF) << 8) | ((OutputDelay) & 0xF))
-#define CODEC_F00_08_BEEP_GEN(f00_08) ((f00_08) & RT_BIT(16)
-
-/* Widget Capabilities (7.3.4.6) */
-#define CODEC_MAKE_F00_09(type, delay, chanel_count) \
- ( (((type) & 0xF) << 20) \
- | (((delay) & 0xF) << 16) \
- | (((chanel_count) & 0xF) << 13))
-/* note: types 0x8-0xe are reserved */
-#define CODEC_F00_09_TYPE_AUDIO_OUTPUT (0x0)
-#define CODEC_F00_09_TYPE_AUDIO_INPUT (0x1)
-#define CODEC_F00_09_TYPE_AUDIO_MIXER (0x2)
-#define CODEC_F00_09_TYPE_AUDIO_SELECTOR (0x3)
-#define CODEC_F00_09_TYPE_PIN_COMPLEX (0x4)
-#define CODEC_F00_09_TYPE_POWER_WIDGET (0x5)
-#define CODEC_F00_09_TYPE_VOLUME_KNOB (0x6)
-#define CODEC_F00_09_TYPE_BEEP_GEN (0x7)
-#define CODEC_F00_09_TYPE_VENDOR_DEFINED (0xF)
-
-#define CODEC_F00_09_CAP_CP RT_BIT(12)
-#define CODEC_F00_09_CAP_L_R_SWAP RT_BIT(11)
-#define CODEC_F00_09_CAP_POWER_CTRL RT_BIT(10)
-#define CODEC_F00_09_CAP_DIGITAL RT_BIT(9)
-#define CODEC_F00_09_CAP_CONNECTION_LIST RT_BIT(8)
-#define CODEC_F00_09_CAP_UNSOL RT_BIT(7)
-#define CODEC_F00_09_CAP_PROC_WIDGET RT_BIT(6)
-#define CODEC_F00_09_CAP_STRIPE RT_BIT(5)
-#define CODEC_F00_09_CAP_FMT_OVERRIDE RT_BIT(4)
-#define CODEC_F00_09_CAP_AMP_FMT_OVERRIDE RT_BIT(3)
-#define CODEC_F00_09_CAP_OUT_AMP_PRESENT RT_BIT(2)
-#define CODEC_F00_09_CAP_IN_AMP_PRESENT RT_BIT(1)
-#define CODEC_F00_09_CAP_LSB RT_BIT(0)
-
-#define CODEC_F00_09_TYPE(f00_09) (((f00_09) >> 20) & 0xF)
-
-#define CODEC_F00_09_IS_CAP_CP(f00_09) RT_BOOL((f00_09) & RT_BIT(12))
-#define CODEC_F00_09_IS_CAP_L_R_SWAP(f00_09) RT_BOOL((f00_09) & RT_BIT(11))
-#define CODEC_F00_09_IS_CAP_POWER_CTRL(f00_09) RT_BOOL((f00_09) & RT_BIT(10))
-#define CODEC_F00_09_IS_CAP_DIGITAL(f00_09) RT_BOOL((f00_09) & RT_BIT(9))
-#define CODEC_F00_09_IS_CAP_CONNECTION_LIST(f00_09) RT_BOOL((f00_09) & RT_BIT(8))
-#define CODEC_F00_09_IS_CAP_UNSOL(f00_09) RT_BOOL((f00_09) & RT_BIT(7))
-#define CODEC_F00_09_IS_CAP_PROC_WIDGET(f00_09) RT_BOOL((f00_09) & RT_BIT(6))
-#define CODEC_F00_09_IS_CAP_STRIPE(f00_09) RT_BOOL((f00_09) & RT_BIT(5))
-#define CODEC_F00_09_IS_CAP_FMT_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(4))
-#define CODEC_F00_09_IS_CAP_AMP_OVERRIDE(f00_09) RT_BOOL((f00_09) & RT_BIT(3))
-#define CODEC_F00_09_IS_CAP_OUT_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(2))
-#define CODEC_F00_09_IS_CAP_IN_AMP_PRESENT(f00_09) RT_BOOL((f00_09) & RT_BIT(1))
-#define CODEC_F00_09_IS_CAP_LSB(f00_09) RT_BOOL((f00_09) & RT_BIT(0))
-
-/* Supported PCM size, rates (7.3.4.7) */
-#define CODEC_F00_0A_32_BIT RT_BIT(19)
-#define CODEC_F00_0A_24_BIT RT_BIT(18)
-#define CODEC_F00_0A_16_BIT RT_BIT(17)
-#define CODEC_F00_0A_8_BIT RT_BIT(16)
-
-#define CODEC_F00_0A_48KHZ_MULT_8X RT_BIT(11)
-#define CODEC_F00_0A_48KHZ_MULT_4X RT_BIT(10)
-#define CODEC_F00_0A_44_1KHZ_MULT_4X RT_BIT(9)
-#define CODEC_F00_0A_48KHZ_MULT_2X RT_BIT(8)
-#define CODEC_F00_0A_44_1KHZ_MULT_2X RT_BIT(7)
-#define CODEC_F00_0A_48KHZ RT_BIT(6)
-#define CODEC_F00_0A_44_1KHZ RT_BIT(5)
-/* 2/3 * 48kHz */
-#define CODEC_F00_0A_48KHZ_2_3X RT_BIT(4)
-/* 1/2 * 44.1kHz */
-#define CODEC_F00_0A_44_1KHZ_1_2X RT_BIT(3)
-/* 1/3 * 48kHz */
-#define CODEC_F00_0A_48KHZ_1_3X RT_BIT(2)
-/* 1/4 * 44.1kHz */
-#define CODEC_F00_0A_44_1KHZ_1_4X RT_BIT(1)
-/* 1/6 * 48kHz */
-#define CODEC_F00_0A_48KHZ_1_6X RT_BIT(0)
-
-/* Supported streams formats (7.3.4.8) */
-#define CODEC_F00_0B_AC3 RT_BIT(2)
-#define CODEC_F00_0B_FLOAT32 RT_BIT(1)
-#define CODEC_F00_0B_PCM RT_BIT(0)
-
-/* Pin Capabilities (7.3.4.9)*/
-#define CODEC_MAKE_F00_0C(vref_ctrl) (((vref_ctrl) & 0xFF) << 8)
-#define CODEC_F00_0C_CAP_HBR RT_BIT(27)
-#define CODEC_F00_0C_CAP_DP RT_BIT(24)
-#define CODEC_F00_0C_CAP_EAPD RT_BIT(16)
-#define CODEC_F00_0C_CAP_HDMI RT_BIT(7)
-#define CODEC_F00_0C_CAP_BALANCED_IO RT_BIT(6)
-#define CODEC_F00_0C_CAP_INPUT RT_BIT(5)
-#define CODEC_F00_0C_CAP_OUTPUT RT_BIT(4)
-#define CODEC_F00_0C_CAP_HP RT_BIT(3)
-#define CODEC_F00_0C_CAP_PRESENSE_DETECT RT_BIT(2)
-#define CODEC_F00_0C_CAP_TRIGGER_REQUIRED RT_BIT(1)
-#define CODEC_F00_0C_CAP_IMPENDANCE_SENSE RT_BIT(0)
-
-#define CODEC_F00_0C_IS_CAP_HBR(f00_0c) ((f00_0c) & RT_BIT(27))
-#define CODEC_F00_0C_IS_CAP_DP(f00_0c) ((f00_0c) & RT_BIT(24))
-#define CODEC_F00_0C_IS_CAP_EAPD(f00_0c) ((f00_0c) & RT_BIT(16))
-#define CODEC_F00_0C_IS_CAP_HDMI(f00_0c) ((f00_0c) & RT_BIT(7))
-#define CODEC_F00_0C_IS_CAP_BALANCED_IO(f00_0c) ((f00_0c) & RT_BIT(6))
-#define CODEC_F00_0C_IS_CAP_INPUT(f00_0c) ((f00_0c) & RT_BIT(5))
-#define CODEC_F00_0C_IS_CAP_OUTPUT(f00_0c) ((f00_0c) & RT_BIT(4))
-#define CODEC_F00_0C_IS_CAP_HP(f00_0c) ((f00_0c) & RT_BIT(3))
-#define CODEC_F00_0C_IS_CAP_PRESENSE_DETECT(f00_0c) ((f00_0c) & RT_BIT(2))
-#define CODEC_F00_0C_IS_CAP_TRIGGER_REQUIRED(f00_0c) ((f00_0c) & RT_BIT(1))
-#define CODEC_F00_0C_IS_CAP_IMPENDANCE_SENSE(f00_0c) ((f00_0c) & RT_BIT(0))
-
-/* Input Amplifier capabilities (7.3.4.10) */
-#define CODEC_MAKE_F00_0D(mute_cap, step_size, num_steps, offset) \
- ( (((mute_cap) & UINT32_C(0x01)) << 31) \
- | (((step_size) & UINT32_C(0xFF)) << 16) \
- | (((num_steps) & UINT32_C(0xFF)) << 8) \
- | ( (offset) & UINT32_C(0xFF)) )
-
-#define CODEC_F00_0D_CAP_MUTE RT_BIT(7)
-
-#define CODEC_F00_0D_IS_CAP_MUTE(f00_0d) ( ( f00_0d) & RT_BIT(31))
-#define CODEC_F00_0D_STEP_SIZE(f00_0d) ((( f00_0d) & (0x7F << 16)) >> 16)
-#define CODEC_F00_0D_NUM_STEPS(f00_0d) ((((f00_0d) & (0x7F << 8)) >> 8) + 1)
-#define CODEC_F00_0D_OFFSET(f00_0d) ( (f00_0d) & 0x7F)
-
-/* Output Amplifier capabilities (7.3.4.10) */
-#define CODEC_MAKE_F00_12 CODEC_MAKE_F00_0D
-
-#define CODEC_F00_12_IS_CAP_MUTE(f00_12) CODEC_F00_0D_IS_CAP_MUTE(f00_12)
-#define CODEC_F00_12_STEP_SIZE(f00_12) CODEC_F00_0D_STEP_SIZE(f00_12)
-#define CODEC_F00_12_NUM_STEPS(f00_12) CODEC_F00_0D_NUM_STEPS(f00_12)
-#define CODEC_F00_12_OFFSET(f00_12) CODEC_F00_0D_OFFSET(f00_12)
-
-/* Connection list lenght (7.3.4.11) */
-#define CODEC_MAKE_F00_0E(long_form, length) \
- ( (((long_form) & 0x1) << 7) \
- | ((length) & 0x7F))
-/* Indicates short-form NIDs. */
-#define CODEC_F00_0E_LIST_NID_SHORT 0
-/* Indicates long-form NIDs. */
-#define CODEC_F00_0E_LIST_NID_LONG 1
-#define CODEC_F00_0E_IS_LONG(f00_0e) RT_BOOL((f00_0e) & RT_BIT(7))
-#define CODEC_F00_0E_COUNT(f00_0e) ((f00_0e) & 0x7F)
-/* Supported Power States (7.3.4.12) */
-#define CODEC_F00_0F_EPSS RT_BIT(31)
-#define CODEC_F00_0F_CLKSTOP RT_BIT(30)
-#define CODEC_F00_0F_S3D3 RT_BIT(29)
-#define CODEC_F00_0F_D3COLD RT_BIT(4)
-#define CODEC_F00_0F_D3 RT_BIT(3)
-#define CODEC_F00_0F_D2 RT_BIT(2)
-#define CODEC_F00_0F_D1 RT_BIT(1)
-#define CODEC_F00_0F_D0 RT_BIT(0)
-
-/* Processing capabilities 7.3.4.13 */
-#define CODEC_MAKE_F00_10(num, benign) ((((num) & 0xFF) << 8) | ((benign) & 0x1))
-#define CODEC_F00_10_NUM(f00_10) (((f00_10) & (0xFF << 8)) >> 8)
-#define CODEC_F00_10_BENING(f00_10) ((f00_10) & 0x1)
-
-/* CP/IO Count (7.3.4.14) */
-#define CODEC_MAKE_F00_11(wake, unsol, numgpi, numgpo, numgpio) \
- ( (((wake) & UINT32_C(0x01)) << 31) \
- | (((unsol) & UINT32_C(0x01)) << 30) \
- | (((numgpi) & UINT32_C(0xFF)) << 16) \
- | (((numgpo) & UINT32_C(0xFF)) << 8) \
- | ((numgpio) & UINT32_C(0xFF)) )
-
-/* Processing States (7.3.3.4) */
-#define CODEC_F03_OFF (0)
-#define CODEC_F03_ON RT_BIT(0)
-#define CODEC_F03_BENING RT_BIT(1)
-/* Power States (7.3.3.10) */
-#define CODEC_MAKE_F05(reset, stopok, error, act, set) \
- ( (((reset) & 0x1) << 10) \
- | (((stopok) & 0x1) << 9) \
- | (((error) & 0x1) << 8) \
- | (((act) & 0x7) << 4) \
- | ((set) & 0x7))
-#define CODEC_F05_D3COLD (4)
-#define CODEC_F05_D3 (3)
-#define CODEC_F05_D2 (2)
-#define CODEC_F05_D1 (1)
-#define CODEC_F05_D0 (0)
-
-#define CODEC_F05_IS_RESET(value) (((value) & RT_BIT(10)) != 0)
-#define CODEC_F05_IS_STOPOK(value) (((value) & RT_BIT(9)) != 0)
-#define CODEC_F05_IS_ERROR(value) (((value) & RT_BIT(8)) != 0)
-#define CODEC_F05_ACT(value) (((value) & 0x7) >> 4)
-#define CODEC_F05_SET(value) (((value) & 0x7))
-
-#define CODEC_F05_GE(p0, p1) ((p0) <= (p1))
-#define CODEC_F05_LE(p0, p1) ((p0) >= (p1))
-
-/* Pin Widged Control (7.3.3.13) */
-#define CODEC_F07_VREF_HIZ (0)
-#define CODEC_F07_VREF_50 (0x1)
-#define CODEC_F07_VREF_GROUND (0x2)
-#define CODEC_F07_VREF_80 (0x4)
-#define CODEC_F07_VREF_100 (0x5)
-#define CODEC_F07_IN_ENABLE RT_BIT(5)
-#define CODEC_F07_OUT_ENABLE RT_BIT(6)
-#define CODEC_F07_OUT_H_ENABLE RT_BIT(7)
-
-/* Unsolicited enabled (7.3.3.14) */
-#define CODEC_MAKE_F08(enable, tag) ((((enable) & 1) << 7) | ((tag) & 0x3F))
-
-/* Converter formats (7.3.3.8) and (3.7.1) */
-#define CODEC_MAKE_A(fNonPCM, f44_1BaseRate, mult, div, bits, chan) \
- ( (((fNonPCM) & 0x1) << 15) \
- | (((f44_1BaseRate) & 0x1) << 14) \
- | (((mult) & 0x7) << 11) \
- | (((div) & 0x7) << 8) \
- | (((bits) & 0x7) << 4) \
- | ((chan) & 0xF))
-
-#define CODEC_A_TYPE RT_BIT(15)
-#define CODEC_A_TYPE_PCM (0)
-#define CODEC_A_TYPE_NON_PCM (1)
-
-#define CODEC_A_BASE RT_BIT(14)
-#define CODEC_A_BASE_48KHZ (0)
-#define CODEC_A_BASE_44KHZ (1)
-
-#define CODEC_A_MULT_1X (0)
-#define CODEC_A_MULT_2X (1)
-#define CODEC_A_MULT_3X (2)
-#define CODEC_A_MULT_4X (3)
-
-#define CODEC_A_DIV_1X (0)
-#define CODEC_A_DIV_2X (1)
-#define CODEC_A_DIV_3X (2)
-#define CODEC_A_DIV_4X (3)
-#define CODEC_A_DIV_5X (4)
-#define CODEC_A_DIV_6X (5)
-#define CODEC_A_DIV_7X (6)
-#define CODEC_A_DIV_8X (7)
-
-#define CODEC_A_8_BIT (0)
-#define CODEC_A_16_BIT (1)
-#define CODEC_A_20_BIT (2)
-#define CODEC_A_24_BIT (3)
-#define CODEC_A_32_BIT (4)
-
-#define CODEC_A_CHAN_MONO (0)
-#define CODEC_A_CHAN_STEREO (1)
-
-/* Pin Sense (7.3.3.15) */
-#define CODEC_MAKE_F09_ANALOG(fPresent, impedance) \
- ( (((fPresent) & UINT32_C(0x00000001)) << 31) \
- | ((impedance) & UINT32_C(0x7FFFFFFF)) )
-#define CODEC_F09_ANALOG_NA 0x7FFFFFFF
-#define CODEC_MAKE_F09_DIGITAL(fPresent, fELDValid) \
- ( (((fPresent) & UINT32_C(0x1)) << 31) \
- | (((fELDValid) & UINT32_C(0x1)) << 30))
-
-#define CODEC_MAKE_F0C(lrswap, eapd, btl) ((((lrswap) & 1) << 2) | (((eapd) & 1) << 1) | ((btl) & 1))
-#define CODEC_FOC_IS_LRSWAP(f0c) RT_BOOL((f0c) & RT_BIT(2))
-#define CODEC_FOC_IS_EAPD(f0c) RT_BOOL((f0c) & RT_BIT(1))
-#define CODEC_FOC_IS_BTL(f0c) RT_BOOL((f0c) & RT_BIT(0))
-/* HDA spec 7.3.3.31 defines layout of configuration registers/verbs (0xF1C) */
-/* Configuration's port connection */
-#define CODEC_F1C_PORT_MASK (0x3)
-#define CODEC_F1C_PORT_SHIFT (30)
-
-#define CODEC_F1C_PORT_COMPLEX (0x0)
-#define CODEC_F1C_PORT_NO_PHYS (0x1)
-#define CODEC_F1C_PORT_FIXED (0x2)
-#define CODEC_F1C_BOTH (0x3)
-
-/* Configuration default: connection */
-#define CODEC_F1C_PORT_MASK (0x3)
-#define CODEC_F1C_PORT_SHIFT (30)
-
-/* Connected to a jack (1/8", ATAPI, ...). */
-#define CODEC_F1C_PORT_COMPLEX (0x0)
-/* No physical connection. */
-#define CODEC_F1C_PORT_NO_PHYS (0x1)
-/* Fixed function device (integrated speaker, integrated mic, ...). */
-#define CODEC_F1C_PORT_FIXED (0x2)
-/* Both, a jack and an internal device are attached. */
-#define CODEC_F1C_BOTH (0x3)
-
-/* Configuration default: Location */
-#define CODEC_F1C_LOCATION_MASK (0x3F)
-#define CODEC_F1C_LOCATION_SHIFT (24)
-
-/* [4:5] bits of location region means chassis attachment */
-#define CODEC_F1C_LOCATION_PRIMARY_CHASSIS (0)
-#define CODEC_F1C_LOCATION_INTERNAL RT_BIT(4)
-#define CODEC_F1C_LOCATION_SECONDRARY_CHASSIS RT_BIT(5)
-#define CODEC_F1C_LOCATION_OTHER RT_BIT(5)
-
-/* [0:3] bits of location region means geometry location attachment */
-#define CODEC_F1C_LOCATION_NA (0)
-#define CODEC_F1C_LOCATION_REAR (0x1)
-#define CODEC_F1C_LOCATION_FRONT (0x2)
-#define CODEC_F1C_LOCATION_LEFT (0x3)
-#define CODEC_F1C_LOCATION_RIGTH (0x4)
-#define CODEC_F1C_LOCATION_TOP (0x5)
-#define CODEC_F1C_LOCATION_BOTTOM (0x6)
-#define CODEC_F1C_LOCATION_SPECIAL_0 (0x7)
-#define CODEC_F1C_LOCATION_SPECIAL_1 (0x8)
-#define CODEC_F1C_LOCATION_SPECIAL_2 (0x9)
-
-/* Configuration default: Device type */
-#define CODEC_F1C_DEVICE_MASK (0xF)
-#define CODEC_F1C_DEVICE_SHIFT (20)
-#define CODEC_F1C_DEVICE_LINE_OUT (0)
-#define CODEC_F1C_DEVICE_SPEAKER (0x1)
-#define CODEC_F1C_DEVICE_HP (0x2)
-#define CODEC_F1C_DEVICE_CD (0x3)
-#define CODEC_F1C_DEVICE_SPDIF_OUT (0x4)
-#define CODEC_F1C_DEVICE_DIGITAL_OTHER_OUT (0x5)
-#define CODEC_F1C_DEVICE_MODEM_LINE_SIDE (0x6)
-#define CODEC_F1C_DEVICE_MODEM_HANDSET_SIDE (0x7)
-#define CODEC_F1C_DEVICE_LINE_IN (0x8)
-#define CODEC_F1C_DEVICE_AUX (0x9)
-#define CODEC_F1C_DEVICE_MIC (0xA)
-#define CODEC_F1C_DEVICE_PHONE (0xB)
-#define CODEC_F1C_DEVICE_SPDIF_IN (0xC)
-#define CODEC_F1C_DEVICE_RESERVED (0xE)
-#define CODEC_F1C_DEVICE_OTHER (0xF)
-
-/* Configuration default: Connection type */
-#define CODEC_F1C_CONNECTION_TYPE_MASK (0xF)
-#define CODEC_F1C_CONNECTION_TYPE_SHIFT (16)
-
-#define CODEC_F1C_CONNECTION_TYPE_UNKNOWN (0)
-#define CODEC_F1C_CONNECTION_TYPE_1_8INCHES (0x1)
-#define CODEC_F1C_CONNECTION_TYPE_1_4INCHES (0x2)
-#define CODEC_F1C_CONNECTION_TYPE_ATAPI (0x3)
-#define CODEC_F1C_CONNECTION_TYPE_RCA (0x4)
-#define CODEC_F1C_CONNECTION_TYPE_OPTICAL (0x5)
-#define CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL (0x6)
-#define CODEC_F1C_CONNECTION_TYPE_ANALOG (0x7)
-#define CODEC_F1C_CONNECTION_TYPE_DIN (0x8)
-#define CODEC_F1C_CONNECTION_TYPE_XLR (0x9)
-#define CODEC_F1C_CONNECTION_TYPE_RJ_11 (0xA)
-#define CODEC_F1C_CONNECTION_TYPE_COMBO (0xB)
-#define CODEC_F1C_CONNECTION_TYPE_OTHER (0xF)
-
-/* Configuration's color */
-#define CODEC_F1C_COLOR_MASK (0xF)
-#define CODEC_F1C_COLOR_SHIFT (12)
-#define CODEC_F1C_COLOR_UNKNOWN (0)
-#define CODEC_F1C_COLOR_BLACK (0x1)
-#define CODEC_F1C_COLOR_GREY (0x2)
-#define CODEC_F1C_COLOR_BLUE (0x3)
-#define CODEC_F1C_COLOR_GREEN (0x4)
-#define CODEC_F1C_COLOR_RED (0x5)
-#define CODEC_F1C_COLOR_ORANGE (0x6)
-#define CODEC_F1C_COLOR_YELLOW (0x7)
-#define CODEC_F1C_COLOR_PURPLE (0x8)
-#define CODEC_F1C_COLOR_PINK (0x9)
-#define CODEC_F1C_COLOR_RESERVED_0 (0xA)
-#define CODEC_F1C_COLOR_RESERVED_1 (0xB)
-#define CODEC_F1C_COLOR_RESERVED_2 (0xC)
-#define CODEC_F1C_COLOR_RESERVED_3 (0xD)
-#define CODEC_F1C_COLOR_WHITE (0xE)
-#define CODEC_F1C_COLOR_OTHER (0xF)
-
-/* Configuration's misc */
-#define CODEC_F1C_MISC_MASK (0xF)
-#define CODEC_F1C_MISC_SHIFT (8)
-#define CODEC_F1C_MISC_JACK_DETECT (0)
-#define CODEC_F1C_MISC_RESERVED_0 (1)
-#define CODEC_F1C_MISC_RESERVED_1 (2)
-#define CODEC_F1C_MISC_RESERVED_2 (3)
-
-/* Configuration default: Association */
-#define CODEC_F1C_ASSOCIATION_MASK (0xF)
-#define CODEC_F1C_ASSOCIATION_SHIFT (4)
-
-/* Reserved; don't use. */
-#define CODEC_F1C_ASSOCIATION_INVALID 0x0
-#define CODEC_F1C_ASSOCIATION_GROUP_0 0x1
-#define CODEC_F1C_ASSOCIATION_GROUP_1 0x2
-#define CODEC_F1C_ASSOCIATION_GROUP_2 0x3
-#define CODEC_F1C_ASSOCIATION_GROUP_3 0x4
-#define CODEC_F1C_ASSOCIATION_GROUP_4 0x5
-#define CODEC_F1C_ASSOCIATION_GROUP_5 0x6
-#define CODEC_F1C_ASSOCIATION_GROUP_6 0x7
-#define CODEC_F1C_ASSOCIATION_GROUP_7 0x8
-#define CODEC_F1C_ASSOCIATION_GROUP_15 0xF
-
-/* Configuration default: Association Sequence */
-#define CODEC_F1C_SEQ_MASK (0xF)
-#define CODEC_F1C_SEQ_SHIFT (0)
-
-/* Implementation identification (7.3.3.30) */
-#define CODEC_MAKE_F20(bmid, bsku, aid) \
- ( (((bmid) & 0xFFFF) << 16) \
- | (((bsku) & 0xFF) << 8) \
- | (((aid) & 0xFF)) \
- )
-
-/* macro definition helping in filling the configuration registers. */
-#define CODEC_MAKE_F1C(port_connectivity, location, device, connection_type, color, misc, association, sequence) \
- ( ((port_connectivity) << CODEC_F1C_PORT_SHIFT) \
- | ((location) << CODEC_F1C_LOCATION_SHIFT) \
- | ((device) << CODEC_F1C_DEVICE_SHIFT) \
- | ((connection_type) << CODEC_F1C_CONNECTION_TYPE_SHIFT) \
- | ((color) << CODEC_F1C_COLOR_SHIFT) \
- | ((misc) << CODEC_F1C_MISC_SHIFT) \
- | ((association) << CODEC_F1C_ASSOCIATION_SHIFT) \
- | ((sequence)))
-
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
-/** The F00 parameter length (in dwords). */
-#define CODECNODE_F00_PARAM_LENGTH 20
-/** The F02 parameter length (in dwords). */
-#define CODECNODE_F02_PARAM_LENGTH 16
-
-/**
- * Common (or core) codec node structure.
- */
-typedef struct CODECCOMMONNODE
-{
- /** Node id - 7 bit format */
- uint8_t id;
- /** The node name. */
- char const *pszName;
- /* PRM 5.3.6 */
- uint32_t au32F00_param[CODECNODE_F00_PARAM_LENGTH];
- uint32_t au32F02_param[CODECNODE_F02_PARAM_LENGTH];
-} CODECCOMMONNODE;
-typedef CODECCOMMONNODE *PCODECCOMMONNODE;
-AssertCompile(CODECNODE_F00_PARAM_LENGTH == 20); /* saved state */
-AssertCompile(CODECNODE_F02_PARAM_LENGTH == 16); /* saved state */
-
-/**
- * Compile time assertion on the expected node size.
- */
-#define AssertNodeSize(a_Node, a_cParams) \
- AssertCompile((a_cParams) <= (60 + 6)); /* the max size - saved state */ \
- AssertCompile( sizeof(a_Node) - sizeof(CODECCOMMONNODE) \
- == (((a_cParams) * sizeof(uint32_t) + sizeof(void *) - 1) & ~(sizeof(void *) - 1)) )
-
-typedef struct ROOTCODECNODE
-{
- CODECCOMMONNODE node;
-} ROOTCODECNODE, *PROOTCODECNODE;
-AssertNodeSize(ROOTCODECNODE, 0);
-
-#define AMPLIFIER_SIZE 60
-typedef uint32_t AMPLIFIER[AMPLIFIER_SIZE];
-#define AMPLIFIER_IN 0
-#define AMPLIFIER_OUT 1
-#define AMPLIFIER_LEFT 1
-#define AMPLIFIER_RIGHT 0
-#define AMPLIFIER_REGISTER(amp, inout, side, index) ((amp)[30*(inout) + 15*(side) + (index)])
-typedef struct DACNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F0d_param;
- uint32_t u32F04_param;
- uint32_t u32F05_param;
- uint32_t u32F06_param;
- uint32_t u32F0c_param;
-
- uint32_t u32A_param;
- AMPLIFIER B_params;
-
-} DACNODE, *PDACNODE;
-AssertNodeSize(DACNODE, 6 + 60);
-
-typedef struct ADCNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F03_param;
- uint32_t u32F05_param;
- uint32_t u32F06_param;
- uint32_t u32F09_param;
-
- uint32_t u32A_param;
- uint32_t u32F01_param;
- AMPLIFIER B_params;
-} ADCNODE, *PADCNODE;
-AssertNodeSize(DACNODE, 6 + 60);
-
-typedef struct SPDIFOUTNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F05_param;
- uint32_t u32F06_param;
- uint32_t u32F09_param;
- uint32_t u32F0d_param;
-
- uint32_t u32A_param;
- AMPLIFIER B_params;
-} SPDIFOUTNODE, *PSPDIFOUTNODE;
-AssertNodeSize(SPDIFOUTNODE, 5 + 60);
-
-typedef struct SPDIFINNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F05_param;
- uint32_t u32F06_param;
- uint32_t u32F09_param;
- uint32_t u32F0d_param;
-
- uint32_t u32A_param;
- AMPLIFIER B_params;
-} SPDIFINNODE, *PSPDIFINNODE;
-AssertNodeSize(SPDIFINNODE, 5 + 60);
-
-typedef struct AFGCODECNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F05_param;
- uint32_t u32F08_param;
- uint32_t u32F20_param;
- uint32_t u32F17_param;
-} AFGCODECNODE, *PAFGCODECNODE;
-AssertNodeSize(AFGCODECNODE, 4);
-
-typedef struct PORTNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F07_param;
- uint32_t u32F08_param;
- uint32_t u32F09_param;
- uint32_t u32F01_param;
- uint32_t u32F1c_param;
- AMPLIFIER B_params;
-} PORTNODE, *PPORTNODE;
-AssertNodeSize(PORTNODE, 5 + 60);
-
-typedef struct DIGOUTNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F01_param;
- uint32_t u32F08_param;
- uint32_t u32F07_param;
- uint32_t u32F09_param;
- uint32_t u32F1c_param;
-} DIGOUTNODE, *PDIGOUTNODE;
-AssertNodeSize(DIGOUTNODE, 5);
-
-typedef struct DIGINNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F05_param;
- uint32_t u32F07_param;
- uint32_t u32F08_param;
- uint32_t u32F09_param;
- uint32_t u32F0c_param;
- uint32_t u32F1c_param;
- uint32_t u32F1e_param;
-} DIGINNODE, *PDIGINNODE;
-AssertNodeSize(DIGINNODE, 7);
-
-typedef struct ADCMUXNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F01_param;
-
- uint32_t u32A_param;
- AMPLIFIER B_params;
-} ADCMUXNODE, *PADCMUXNODE;
-AssertNodeSize(ADCMUXNODE, 2 + 60);
-
-typedef struct PCBEEPNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F07_param;
- uint32_t u32F0a_param;
-
- uint32_t u32A_param;
- AMPLIFIER B_params;
- uint32_t u32F1c_param;
-} PCBEEPNODE, *PPCBEEPNODE;
-AssertNodeSize(PCBEEPNODE, 3 + 60 + 1);
-
-typedef struct CDNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F07_param;
- uint32_t u32F1c_param;
-} CDNODE, *PCDNODE;
-AssertNodeSize(CDNODE, 2);
-
-typedef struct VOLUMEKNOBNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F08_param;
- uint32_t u32F0f_param;
-} VOLUMEKNOBNODE, *PVOLUMEKNOBNODE;
-AssertNodeSize(VOLUMEKNOBNODE, 2);
-
-typedef struct ADCVOLNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F0c_param;
- uint32_t u32F01_param;
- uint32_t u32A_params;
- AMPLIFIER B_params;
-} ADCVOLNODE, *PADCVOLNODE;
-AssertNodeSize(ADCVOLNODE, 3 + 60);
-
-typedef struct RESNODE
-{
- CODECCOMMONNODE node;
- uint32_t u32F05_param;
- uint32_t u32F06_param;
- uint32_t u32F07_param;
- uint32_t u32F1c_param;
-} RESNODE, *PRESNODE;
-AssertNodeSize(RESNODE, 4);
-
-/**
- * Used for the saved state.
- */
-typedef struct CODECSAVEDSTATENODE
-{
- CODECCOMMONNODE Core;
- uint32_t au32Params[60 + 6];
-} CODECSAVEDSTATENODE;
-AssertNodeSize(CODECSAVEDSTATENODE, 60 + 6);
-
-typedef union CODECNODE
-{
- CODECCOMMONNODE node;
- ROOTCODECNODE root;
- AFGCODECNODE afg;
- DACNODE dac;
- ADCNODE adc;
- SPDIFOUTNODE spdifout;
- SPDIFINNODE spdifin;
- PORTNODE port;
- DIGOUTNODE digout;
- DIGINNODE digin;
- ADCMUXNODE adcmux;
- PCBEEPNODE pcbeep;
- CDNODE cdnode;
- VOLUMEKNOBNODE volumeKnob;
- ADCVOLNODE adcvol;
- RESNODE reserved;
- CODECSAVEDSTATENODE SavedState;
-} CODECNODE, *PCODECNODE;
-AssertNodeSize(CODECNODE, 60 + 6);
-
-
-/*********************************************************************************************************************************
-* Global Variables *
-*********************************************************************************************************************************/
-/* STAC9220 - Nodes IDs / names. */
-#define STAC9220_NID_ROOT 0x0 /* Root node */
-#define STAC9220_NID_AFG 0x1 /* Audio Configuration Group */
-#define STAC9220_NID_DAC0 0x2 /* Out */
-#define STAC9220_NID_DAC1 0x3 /* Out */
-#define STAC9220_NID_DAC2 0x4 /* Out */
-#define STAC9220_NID_DAC3 0x5 /* Out */
-#define STAC9220_NID_ADC0 0x6 /* In */
-#define STAC9220_NID_ADC1 0x7 /* In */
-#define STAC9220_NID_SPDIF_OUT 0x8 /* Out */
-#define STAC9220_NID_SPDIF_IN 0x9 /* In */
-#define STAC9220_NID_PIN_HEADPHONE0 0xA /* In, Out */
-#define STAC9220_NID_PIN_B 0xB /* In, Out */
-#define STAC9220_NID_PIN_C 0xC /* In, Out */
-#define STAC9220_NID_PIN_HEADPHONE1 0xD /* In, Out */
-#define STAC9220_NID_PIN_E 0xE /* In */
-#define STAC9220_NID_PIN_F 0xF /* In, Out */
-#define STAC9220_NID_PIN_SPDIF_OUT 0x10 /* Out */
-#define STAC9220_NID_PIN_SPDIF_IN 0x11 /* In */
-#define STAC9220_NID_ADC0_MUX 0x12 /* In */
-#define STAC9220_NID_ADC1_MUX 0x13 /* In */
-#define STAC9220_NID_PCBEEP 0x14 /* Out */
-#define STAC9220_NID_PIN_CD 0x15 /* In */
-#define STAC9220_NID_VOL_KNOB 0x16
-#define STAC9220_NID_AMP_ADC0 0x17 /* In */
-#define STAC9220_NID_AMP_ADC1 0x18 /* In */
-/* STAC9221. */
-#define STAC9221_NID_ADAT_OUT 0x19 /* Out */
-#define STAC9221_NID_I2S_OUT 0x1A /* Out */
-#define STAC9221_NID_PIN_I2S_OUT 0x1B /* Out */
-
-#if 1
-/* STAC9220 - Referenced thru STAC9220WIDGET in the constructor below. */
-static uint8_t const g_abStac9220Ports[] = { 0x0A, 0xB, 0xC, 0xD, 0xE, 0xF, 0};
-static uint8_t const g_abStac9220Dacs[] = { 0x02, 0x3, 0x4, 0x5, 0};
-static uint8_t const g_abStac9220Adcs[] = { 0x06, 0x7, 0};
-static uint8_t const g_abStac9220SpdifOuts[] = { 0x08, 0 };
-static uint8_t const g_abStac9220SpdifIns[] = { 0x09, 0 };
-static uint8_t const g_abStac9220DigOutPins[] = { 0x10, 0 };
-static uint8_t const g_abStac9220DigInPins[] = { 0x11, 0 };
-static uint8_t const g_abStac9220AdcVols[] = { 0x17, 0x18, 0};
-static uint8_t const g_abStac9220AdcMuxs[] = { 0x12, 0x13, 0};
-static uint8_t const g_abStac9220Pcbeeps[] = { 0x14, 0 };
-static uint8_t const g_abStac9220Cds[] = { 0x15, 0 };
-static uint8_t const g_abStac9220VolKnobs[] = { 0x16, 0 };
-static uint8_t const g_abStac9220Reserveds[] = { 0x09, 0x19, 0x1a, 0x1b, 0 };
-#else /** @todo Enable this after 5.0 -- needs more testing first. */
-static uint8_t const g_abStac9220Ports[] = { STAC9220_NID_PIN_HEADPHONE0, STAC9220_NID_PIN_B, STAC9220_NID_PIN_C, STAC9220_NID_PIN_HEADPHONE1, STAC9220_NID_PIN_E, STAC9220_NID_PIN_F, 0};
-static uint8_t const g_abStac9220Dacs[] = { STAC9220_NID_DAC0, STAC9220_NID_DAC1, STAC9220_NID_DAC2, STAC9220_NID_DAC3, 0};
-static uint8_t const g_abStac9220Adcs[] = { STAC9220_NID_ADC0, STAC9220_NID_ADC1, 0};
-static uint8_t const g_abStac9220SpdifOuts[] = { STAC9220_NID_SPDIF_OUT, 0 };
-static uint8_t const g_abStac9220SpdifIns[] = { STAC9220_NID_SPDIF_IN, 0 };
-static uint8_t const g_abStac9220DigOutPins[] = { STAC9220_NID_PIN_SPDIF_OUT, 0 };
-static uint8_t const g_abStac9220DigInPins[] = { STAC9220_NID_PIN_SPDIF_IN, 0 };
-static uint8_t const g_abStac9220AdcVols[] = { STAC9220_NID_AMP_ADC0, STAC9220_NID_AMP_ADC1, 0};
-static uint8_t const g_abStac9220AdcMuxs[] = { STAC9220_NID_ADC0_MUX, STAC9220_NID_ADC1_MUX, 0};
-static uint8_t const g_abStac9220Pcbeeps[] = { STAC9220_NID_PCBEEP, 0 };
-static uint8_t const g_abStac9220Cds[] = { STAC9220_NID_PIN_CD, 0 };
-static uint8_t const g_abStac9220VolKnobs[] = { STAC9220_NID_VOL_KNOB, 0 };
-/* STAC 9221. */
-/** @todo Is STAC9220_NID_SPDIF_IN really correct for reserved nodes? */
-static uint8_t const g_abStac9220Reserveds[] = { STAC9220_NID_SPDIF_IN, STAC9221_NID_ADAT_OUT, STAC9221_NID_I2S_OUT, STAC9221_NID_PIN_I2S_OUT, 0 };
-#endif
-
-/** SSM description of a CODECNODE. */
-static SSMFIELD const g_aCodecNodeFields[] =
-{
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id),
- SSMFIELD_ENTRY_PAD_HC_AUTO(3, 3),
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
- SSMFIELD_ENTRY_TERM()
-};
-
-/** Backward compatibility with v1 of the CODECNODE. */
-static SSMFIELD const g_aCodecNodeFieldsV1[] =
-{
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.id),
- SSMFIELD_ENTRY_PAD_HC_AUTO(3, 7),
- SSMFIELD_ENTRY_OLD_HCPTR(Core.name),
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F00_param),
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, Core.au32F02_param),
- SSMFIELD_ENTRY( CODECSAVEDSTATENODE, au32Params),
- SSMFIELD_ENTRY_TERM()
-};
-
-
-
-
-static DECLCALLBACK(void) stac9220DbgNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- RT_NOREF(pszArgs);
- for (int i = 1; i < 12; i++)
- {
- PCODECNODE pNode = &pThis->paNodes[i];
- AMPLIFIER *pAmp = &pNode->dac.B_params;
-
- uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) & 0x7f;
- uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) & 0x7f;
-
- pHlp->pfnPrintf(pHlp, "0x%x: lVol=%RU8, rVol=%RU8\n", i, lVol, rVol);
- }
-}
-
-
-static DECLCALLBACK(int) stac9220ResetNode(PHDACODEC pThis, uint8_t nodenum, PCODECNODE pNode)
-{
- pNode->node.id = nodenum;
- pNode->node.au32F00_param[0xF] = 0; /* Power statest Supported: are the same as AFG reports */
- switch (nodenum)
- {
- /* Root Node*/
- case 0:
- pNode->node.au32F00_param[0x02] = CODEC_MAKE_F00_02(0x1, 0x0, 0x34, 0x1); /* rev id */
- break;
- case 1:
- pNode->node.au32F00_param[0x08] = CODEC_MAKE_F00_08(1, 0xd, 0xd);
- pNode->node.au32F00_param[0x0C] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_BALANCED_IO
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_PRESENSE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
- | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//(17 << 8)|RT_BIT(6)|RT_BIT(5)|RT_BIT(2)|RT_BIT(1)|RT_BIT(0);
- pNode->node.au32F00_param[0x0B] = CODEC_F00_0B_PCM;
- pNode->node.au32F00_param[0x0D] = CODEC_MAKE_F00_0D(1, 0x5, 0xE, 0);//RT_BIT(31)|(0x5 << 16)|(0xE)<<8;
- pNode->node.au32F00_param[0x12] = RT_BIT(31)|(0x2 << 16)|(0x7f << 8)|0x7f;
- pNode->node.au32F00_param[0x11] = CODEC_MAKE_F00_11(1, 1, 0, 0, 4);//0xc0000004;
- pNode->node.au32F00_param[0x0F] = CODEC_F00_0F_D3|CODEC_F00_0F_D2|CODEC_F00_0F_D1|CODEC_F00_0F_D0;
- pNode->afg.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D2, CODEC_F05_D2);//0x2 << 4| 0x2; /* PS-Act: D3, PS->Set D3 */
- pNode->afg.u32F08_param = 0;
- pNode->afg.u32F17_param = 0;
- break;
- case 2:
- case 3:
- case 4:
- case 5:
- memset(pNode->dac.B_params, 0, AMPLIFIER_SIZE);
- pNode->dac.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//RT_BIT(14)|(0x1 << 4)|0x1; /* 44100Hz/16bit/2ch */
-
- AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_LEFT, 0) = 0x7F | RT_BIT(7);
- AMPLIFIER_REGISTER(pNode->dac.B_params, AMPLIFIER_OUT, AMPLIFIER_RIGHT, 0) = 0x7F | RT_BIT(7);
-
- pNode->dac.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0xD, 0)
- | CODEC_F00_09_CAP_L_R_SWAP
- | CODEC_F00_09_CAP_POWER_CTRL
- | CODEC_F00_09_CAP_OUT_AMP_PRESENT
- | CODEC_F00_09_CAP_LSB;//(0xD << 16) | RT_BIT(11) | RT_BIT(10) | RT_BIT(2) | RT_BIT(0);
- pNode->dac.u32F0c_param = 0;
- pNode->dac.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3, Set: D3 */
- break;
- case 6:
- pNode->node.au32F02_param[0] = 0x17;
- goto adc_init;
- case 7:
- pNode->node.au32F02_param[0] = 0x18;
- adc_init:
- pNode->adc.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//RT_BIT(14)|(0x1 << 3)|0x1; /* 44100Hz/16bit/2ch */
- pNode->adc.node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0);
- pNode->adc.u32F03_param = RT_BIT(0);
- pNode->adc.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 Set: D3 */
- pNode->adc.u32F06_param = 0;
- pNode->adc.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0xD, 0)
- | CODEC_F00_09_CAP_POWER_CTRL
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_PROC_WIDGET
- | CODEC_F00_09_CAP_LSB;//RT_BIT(20)| (0xd << 16) | RT_BIT(10) | RT_BIT(8) | RT_BIT(6)| RT_BIT(0);
- break;
- case 8:
- pNode->spdifout.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//(1<<14)|(0x1<<4) | 0x1;
- pNode->spdifout.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x4, 0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_FMT_OVERRIDE
- | CODEC_F00_09_CAP_LSB;//(4 << 16) | RT_BIT(9)|RT_BIT(4)|0x1;
- pNode->node.au32F00_param[0xa] = pThis->paNodes[1].node.au32F00_param[0xA];
- pNode->spdifout.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
- pNode->spdifout.u32F06_param = 0;
- pNode->spdifout.u32F0d_param = 0;
- break;
- case 9:
- pNode->spdifin.u32A_param = CODEC_MAKE_A(0, 1, CODEC_A_MULT_1X, CODEC_A_DIV_1X, CODEC_A_16_BIT, 1);//(0x1<<4) | 0x1;
- pNode->spdifin.node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_INPUT, 0x4, 0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_FMT_OVERRIDE
- | CODEC_F00_09_CAP_LSB;//(0x1 << 20)|(4 << 16) | RT_BIT(9)| RT_BIT(8)|RT_BIT(4)|0x1;
- pNode->node.au32F00_param[0xA] = pThis->paNodes[1].node.au32F00_param[0xA];
- pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//RT_BIT(0);
- pNode->node.au32F02_param[0] = 0x11;
- pNode->spdifin.node.au32F00_param[0xB] = CODEC_F00_0B_PCM;
- pNode->spdifin.u32F06_param = 0;
- pNode->spdifin.u32F0d_param = 0;
- break;
- case 0xA:
- pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_HP
- | CODEC_F00_0C_CAP_PRESENSE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
- | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x173f;
- pNode->node.au32F02_param[0] = 0x2;
- pNode->port.u32F07_param = CODEC_F07_IN_ENABLE
- | CODEC_F07_OUT_ENABLE;
- pNode->port.u32F08_param = 0;
- if (!pThis->fInReset)
- pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_FRONT,
- CODEC_F1C_DEVICE_HP,
- CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
- CODEC_F1C_COLOR_GREEN,
- CODEC_F1C_MISC_JACK_DETECT,
- 0x2, 0);//RT_MAKE_U32_FROM_U8(0x20, 0x40, 0x21, 0x02);
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
- goto port_init;
- case 0xB:
- pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENSE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
- | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
- pNode->node.au32F02_param[0] = 0x4;
- pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
- if (!pThis->fInReset)
- pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_INTERNAL|CODEC_F1C_LOCATION_REAR,
- CODEC_F1C_DEVICE_SPEAKER,
- CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
- CODEC_F1C_COLOR_BLACK,
- CODEC_F1C_MISC_JACK_DETECT,
- 0x1, 0x1);//RT_MAKE_U32_FROM_U8(0x11, 0x60, 0x11, 0x01);
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
- goto port_init;
- case 0xC:
- pNode->node.au32F02_param[0] = 0x3;
- pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENSE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
- | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
- pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
- if (!pThis->fInReset)
- pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_REAR,
- CODEC_F1C_DEVICE_SPEAKER,
- CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
- CODEC_F1C_COLOR_GREEN,
- 0x0, 0x1, 0x0);//RT_MAKE_U32_FROM_U8(0x10, 0x40, 0x11, 0x01);
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
- goto port_init;
- case 0xD:
- pNode->node.au32F00_param[0xC] = CODEC_MAKE_F00_0C(0x17)
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENSE_DETECT
- | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
- | CODEC_F00_0C_CAP_IMPENDANCE_SENSE;//0x1737;
- pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
- pNode->node.au32F02_param[0] = 0x2;
- if (!pThis->fInReset)
- pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_FRONT,
- CODEC_F1C_DEVICE_MIC,
- CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
- CODEC_F1C_COLOR_PINK,
- 0x0, 0x5, 0x0);//RT_MAKE_U32_FROM_U8(0x50, 0x90, 0xA1, 0x02); /* Microphone */
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(1, CODEC_F09_ANALOG_NA);//RT_BIT(31)|0x7fffffff;
- port_init:
- pNode->port.u32F08_param = 0;
- pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0)
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_UNSOL
- | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(0);
- pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1;
- break;
- case 0xE:
- pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0)
- | CODEC_F00_09_CAP_UNSOL
- | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(7)|RT_BIT(0);
- pNode->port.u32F08_param = 0;
- pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENSE_DETECT;//0x34;
- pNode->port.u32F07_param = CODEC_F07_IN_ENABLE;
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
- if (!pThis->fInReset)
- pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_REAR,
- CODEC_F1C_DEVICE_LINE_OUT,
- CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
- CODEC_F1C_COLOR_BLUE,
- 0x0, 0x4, 0x0);//0x01013040; /* Line Out */
- break;
- case 0xF:
- pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0)
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_UNSOL
- | CODEC_F00_09_CAP_OUT_AMP_PRESENT
- | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(8)|RT_BIT(7)|RT_BIT(2)|RT_BIT(0);
- pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_OUTPUT
- | CODEC_F00_0C_CAP_PRESENSE_DETECT
- /* | CODEC_F00_0C_CAP_TRIGGER_REQUIRED
- | CODEC_F00_0C_CAP_IMPENDANCE_SENSE */;//0x37;
- pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 1);//0x1;
- pNode->port.u32F08_param = 0;
- pNode->port.u32F07_param = CODEC_F07_OUT_ENABLE
- | CODEC_F07_IN_ENABLE;
- if (!pThis->fInReset)
- pNode->port.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_INTERNAL,
- CODEC_F1C_DEVICE_SPEAKER,
- CODEC_F1C_CONNECTION_TYPE_1_8INCHES,
- CODEC_F1C_COLOR_ORANGE,
- 0x0, 0x1, 0x2);//RT_MAKE_U32_FROM_U8(0x12, 0x60, 0x11, 0x01);
- pNode->node.au32F02_param[0] = 0x5;
- pNode->port.u32F09_param = CODEC_MAKE_F09_ANALOG(0, CODEC_F09_ANALOG_NA);//0x7fffffff;
- break;
- case 0x10:
- pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0x0, 0x0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_LSB;//(4<<20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
- pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//RT_BIT(4);
- pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x3);
- pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x08, 0x17, 0x19, 0);
- if (!pThis->fInReset)
- pNode->digout.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_REAR,
- CODEC_F1C_DEVICE_SPDIF_OUT,
- CODEC_F1C_CONNECTION_TYPE_DIN,
- CODEC_F1C_COLOR_BLACK,
- 0x0, 0x3, 0x0);//RT_MAKE_U32_FROM_U8(0x30, 0x10, 0x45, 0x01);
- break;
- case 0x11:
- pNode->node.au32F00_param[9] = (4 << 20) | (3 << 16) | RT_BIT(10) | RT_BIT(9) | RT_BIT(7) | RT_BIT(0);
- pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_EAPD
- | CODEC_F00_0C_CAP_INPUT
- | CODEC_F00_0C_CAP_PRESENSE_DETECT;//RT_BIT(16)| RT_BIT(5)|RT_BIT(2);
- pNode->digin.u32F05_param = CODEC_MAKE_F05(0, 0, 0, CODEC_F05_D3, CODEC_F05_D3);//0x3 << 4 | 0x3; /* PS-Act: D3 -> D3 */
- pNode->digin.u32F07_param = 0;
- pNode->digin.u32F08_param = 0;
- pNode->digin.u32F09_param = CODEC_MAKE_F09_DIGITAL(0, 0);
- pNode->digin.u32F0c_param = 0;
- if (!pThis->fInReset)
- pNode->digin.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_COMPLEX,
- CODEC_F1C_LOCATION_REAR,
- CODEC_F1C_DEVICE_SPDIF_IN,
- CODEC_F1C_CONNECTION_TYPE_OTHER_DIGITAL,
- CODEC_F1C_COLOR_BLACK,
- 0x0, 0x6, 0x0);//(0x1 << 24) | (0xc5 << 16) | (0x10 << 8) | 0x60;
- break;
- case 0x12:
- pNode->adcmux.u32F01_param = 0;
- goto adcmux_init;
- case 0x13:
- pNode->adcmux.u32F01_param = 1;
- adcmux_init:
- pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0x0, 0)
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
- | CODEC_F00_09_CAP_OUT_AMP_PRESENT
- | CODEC_F00_09_CAP_LSB;//(3<<20)|RT_BIT(8)|RT_BIT(3)|RT_BIT(2)|RT_BIT(0);
- pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x7);
- pNode->node.au32F00_param[0x12] = (0x27 << 16)|(0x4 << 8);
- /* STAC 9220 v10 6.21-22.{4,5} both(left and right) out amplefiers inited with 0*/
- memset(pNode->adcmux.B_params, 0, AMPLIFIER_SIZE);
- pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0xe, 0x15, 0xf, 0xb);
- pNode->node.au32F02_param[4] = RT_MAKE_U32_FROM_U8(0xc, 0xd, 0xa, 0x0);
- break;
- case 0x14:
- pNode->node.au32F00_param[9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_BEEP_GEN, 0, 0)
- | CODEC_F00_09_CAP_AMP_FMT_OVERRIDE
- | CODEC_F00_09_CAP_OUT_AMP_PRESENT;//(7 << 20) | RT_BIT(3) | RT_BIT(2);
- pNode->node.au32F00_param[0x12] = (0x17 << 16)|(0x3 << 8)| 0x3;
- pNode->pcbeep.u32F0a_param = 0;
- memset(pNode->pcbeep.B_params, 0, AMPLIFIER_SIZE);
- break;
- case 0x15:
- pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
- | CODEC_F00_09_CAP_LSB;//(4 << 20)|RT_BIT(0);
- pNode->node.au32F00_param[0xc] = CODEC_F00_0C_CAP_INPUT;//RT_BIT(5);
- if (!pThis->fInReset)
- pNode->cdnode.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_FIXED,
- CODEC_F1C_LOCATION_INTERNAL,
- CODEC_F1C_DEVICE_CD,
- CODEC_F1C_CONNECTION_TYPE_ATAPI,
- CODEC_F1C_COLOR_UNKNOWN,
- 0x0, 0x7, 0x0);//RT_MAKE_U32_FROM_U8(0x70, 0x0, 0x33, 0x90);
- break;
- case 0x16:
- pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VOLUME_KNOB, 0x0, 0x0);//(0x6 << 20);
- pNode->node.au32F00_param[0x13] = RT_BIT(7)| 0x7F;
- pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x4);
- pNode->node.au32F02_param[0] = RT_MAKE_U32_FROM_U8(0x2, 0x3, 0x4, 0x5);
- pNode->volumeKnob.u32F08_param = 0;
- pNode->volumeKnob.u32F0f_param = 0x7f;
- break;
- case 0x17:
- pNode->node.au32F02_param[0] = 0x12;
- goto adcvol_init;
- case 0x18:
- pNode->node.au32F02_param[0] = 0x13;
- adcvol_init:
- memset(pNode->adcvol.B_params, 0, AMPLIFIER_SIZE);
-
- pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_SELECTOR, 0, 0)
- | CODEC_F00_09_CAP_L_R_SWAP
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_IN_AMP_PRESENT
- | CODEC_F00_09_CAP_LSB;//(0x3 << 20)|RT_BIT(11)|RT_BIT(8)|RT_BIT(1)|RT_BIT(0);
- pNode->node.au32F00_param[0xe] = CODEC_MAKE_F00_0E(0, 0x1);
- AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_LEFT, 0) = RT_BIT(7);
- AMPLIFIER_REGISTER(pNode->adcvol.B_params, AMPLIFIER_IN, AMPLIFIER_RIGHT, 0) = RT_BIT(7);
- pNode->adcvol.u32F0c_param = 0;
- break;
- case 0x19:
- pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_VENDOR_DEFINED, 0x3, 0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_LSB;//(0xF << 20)|(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
- break;
- case 0x1A:
- pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_AUDIO_OUTPUT, 0x3, 0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_LSB;//(0x3 << 16)|RT_BIT(9)|RT_BIT(0);
- break;
- case 0x1B:
- pNode->node.au32F00_param[0x9] = CODEC_MAKE_F00_09(CODEC_F00_09_TYPE_PIN_COMPLEX, 0, 0)
- | CODEC_F00_09_CAP_DIGITAL
- | CODEC_F00_09_CAP_CONNECTION_LIST
- | CODEC_F00_09_CAP_LSB;//(0x4 << 20)|RT_BIT(9)|RT_BIT(8)|RT_BIT(0);
- pNode->node.au32F00_param[0xE] = CODEC_MAKE_F00_0E(0, 0x1);
- pNode->node.au32F00_param[0xC] = CODEC_F00_0C_CAP_OUTPUT;//0x10;
- pNode->node.au32F02_param[0] = 0x1a;
- pNode->reserved.u32F1c_param = CODEC_MAKE_F1C(CODEC_F1C_PORT_NO_PHYS,
- CODEC_F1C_LOCATION_NA,
- CODEC_F1C_DEVICE_LINE_OUT,
- CODEC_F1C_CONNECTION_TYPE_UNKNOWN,
- CODEC_F1C_COLOR_UNKNOWN,
- 0x0, 0x0, 0xf);//0x4000000f;
- break;
- default:
- break;
- }
- return VINF_SUCCESS;
-}
-
-
-static int stac9220Construct(PHDACODEC pThis)
-{
- unconst(pThis->cTotalNodes) = 0x1C;
- pThis->pfnCodecNodeReset = stac9220ResetNode;
- pThis->pfnDbgListNodes = stac9220DbgNodes;
- pThis->u16VendorId = 0x8384;
- pThis->u16DeviceId = 0x7680;
- pThis->u8BSKU = 0x76;
- pThis->u8AssemblyId = 0x80;
- pThis->paNodes = (PCODECNODE)RTMemAllocZ(sizeof(CODECNODE) * pThis->cTotalNodes);
- if (!pThis->paNodes)
- return VERR_NO_MEMORY;
- pThis->fInReset = false;
-#define STAC9220WIDGET(type) pThis->au8##type##s = g_abStac9220##type##s
- STAC9220WIDGET(Port);
- STAC9220WIDGET(Dac);
- STAC9220WIDGET(Adc);
- STAC9220WIDGET(AdcVol);
- STAC9220WIDGET(AdcMux);
- STAC9220WIDGET(Pcbeep);
- STAC9220WIDGET(SpdifIn);
- STAC9220WIDGET(SpdifOut);
- STAC9220WIDGET(DigInPin);
- STAC9220WIDGET(DigOutPin);
- STAC9220WIDGET(Cd);
- STAC9220WIDGET(VolKnob);
- STAC9220WIDGET(Reserved);
-#undef STAC9220WIDGET
- unconst(pThis->u8AdcVolsLineIn) = 0x17;
- unconst(pThis->u8DacLineOut) = 0x3;
-
- return VINF_SUCCESS;
-}
-
-
-/*
- * Some generic predicate functions.
- */
-
-#define DECLISNODEOFTYPE(type) \
- DECLINLINE(int) hdaCodecIs##type##Node(PHDACODEC pThis, uint8_t cNode) \
- { \
- Assert(pThis->au8##type##s); \
- for (int i = 0; pThis->au8##type##s[i] != 0; ++i) \
- if (pThis->au8##type##s[i] == cNode) \
- return 1; \
- return 0; \
- }
-/* hdaCodecIsPortNode */
-DECLISNODEOFTYPE(Port)
-/* hdaCodecIsDacNode */
-DECLISNODEOFTYPE(Dac)
-/* hdaCodecIsAdcVolNode */
-DECLISNODEOFTYPE(AdcVol)
-/* hdaCodecIsAdcNode */
-DECLISNODEOFTYPE(Adc)
-/* hdaCodecIsAdcMuxNode */
-DECLISNODEOFTYPE(AdcMux)
-/* hdaCodecIsPcbeepNode */
-DECLISNODEOFTYPE(Pcbeep)
-/* hdaCodecIsSpdifOutNode */
-DECLISNODEOFTYPE(SpdifOut)
-/* hdaCodecIsSpdifInNode */
-DECLISNODEOFTYPE(SpdifIn)
-/* hdaCodecIsDigInPinNode */
-DECLISNODEOFTYPE(DigInPin)
-/* hdaCodecIsDigOutPinNode */
-DECLISNODEOFTYPE(DigOutPin)
-/* hdaCodecIsCdNode */
-DECLISNODEOFTYPE(Cd)
-/* hdaCodecIsVolKnobNode */
-DECLISNODEOFTYPE(VolKnob)
-/* hdaCodecIsReservedNode */
-DECLISNODEOFTYPE(Reserved)
-
-
-/*
- * Misc helpers.
- */
-static int hdaCodecToAudVolume(PHDACODEC pThis, AMPLIFIER *pAmp, PDMAUDIOMIXERCTL mt)
-{
- uint32_t dir = AMPLIFIER_OUT;
- ENMSOUNDSOURCE enmSrc;
- switch (mt)
- {
- case PDMAUDIOMIXERCTL_PCM:
- enmSrc = PO_INDEX;
- dir = AMPLIFIER_OUT;
- break;
- case PDMAUDIOMIXERCTL_LINE_IN:
- enmSrc = PI_INDEX;
- dir = AMPLIFIER_IN;
- break;
- default:
- AssertMsgFailedReturn(("Invalid mixer control %ld\n", mt), VERR_INVALID_PARAMETER);
- break;
- }
-
- int mute = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & RT_BIT(7);
- mute |= AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & RT_BIT(7);
- mute >>=7;
- mute &= 0x1;
- uint8_t lVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_LEFT, 0) & 0x7f;
- uint8_t rVol = AMPLIFIER_REGISTER(*pAmp, dir, AMPLIFIER_RIGHT, 0) & 0x7f;
-
- /* The STAC9220 volume controls have 0 to -96dB attenuation range in 128 steps.
- * We have 0 to -96dB range in 256 steps. HDA volume setting of 127 must map
- * to 255 internally (0dB), while HDA volume setting of 0 (-96dB) should map
- * to 1 (rather than zero) internally.
- */
- lVol = (lVol + 1) * (2 * 255) / 256;
- rVol = (rVol + 1) * (2 * 255) / 256;
-
- return pThis->pfnSetVolume(pThis->pHDAState, enmSrc, RT_BOOL(mute), lVol, rVol);
-}
-
-DECLINLINE(void) hdaCodecSetRegister(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset, uint32_t mask)
-{
- Assert((pu32Reg && u8Offset < 32));
- *pu32Reg &= ~(mask << u8Offset);
- *pu32Reg |= (u32Cmd & mask) << u8Offset;
-}
-
-DECLINLINE(void) hdaCodecSetRegisterU8(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
-{
- hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_8BIT_DATA);
-}
-
-DECLINLINE(void) hdaCodecSetRegisterU16(uint32_t *pu32Reg, uint32_t u32Cmd, uint8_t u8Offset)
-{
- hdaCodecSetRegister(pu32Reg, u32Cmd, u8Offset, CODEC_VERB_16BIT_DATA);
-}
-
-
-/*
- * Verb processor functions.
- */
-
-static DECLCALLBACK(int) vrbProcUnimplemented(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- RT_NOREF(pThis, cmd);
- LogFlowFunc(("cmd(raw:%x: cad:%x, d:%c, nid:%x, verb:%x)\n", cmd,
- CODEC_CAD(cmd), CODEC_DIRECT(cmd) ? 'N' : 'Y', CODEC_NID(cmd), CODEC_VERBDATA(cmd)));
- *pResp = 0;
- return VINF_SUCCESS;
-}
-
-#if 0 // unused
-static DECLCALLBACK(int) vrbProcBreak(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- int rc;
- rc = vrbProcUnimplemented(pThis, cmd, pResp);
- *pResp |= CODEC_RESPONSE_UNSOLICITED;
- return rc;
-}
-#endif
-
-/* B-- */
-static DECLCALLBACK(int) vrbProcGetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- /* HDA spec 7.3.3.7 Note A */
- /** @todo: if index out of range response should be 0 */
- uint8_t u8Index = CODEC_GET_AMP_DIRECTION(cmd) == AMPLIFIER_OUT? 0 : CODEC_GET_AMP_INDEX(cmd);
-
- PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- *pResp = AMPLIFIER_REGISTER(pNode->dac.B_params,
- CODEC_GET_AMP_DIRECTION(cmd),
- CODEC_GET_AMP_SIDE(cmd),
- u8Index);
- else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
- *pResp = AMPLIFIER_REGISTER(pNode->adcvol.B_params,
- CODEC_GET_AMP_DIRECTION(cmd),
- CODEC_GET_AMP_SIDE(cmd),
- u8Index);
- else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
- *pResp = AMPLIFIER_REGISTER(pNode->adcmux.B_params,
- CODEC_GET_AMP_DIRECTION(cmd),
- CODEC_GET_AMP_SIDE(cmd),
- u8Index);
- else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
- *pResp = AMPLIFIER_REGISTER(pNode->pcbeep.B_params,
- CODEC_GET_AMP_DIRECTION(cmd),
- CODEC_GET_AMP_SIDE(cmd),
- u8Index);
- else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- *pResp = AMPLIFIER_REGISTER(pNode->port.B_params,
- CODEC_GET_AMP_DIRECTION(cmd),
- CODEC_GET_AMP_SIDE(cmd),
- u8Index);
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- *pResp = AMPLIFIER_REGISTER(pNode->adc.B_params,
- CODEC_GET_AMP_DIRECTION(cmd),
- CODEC_GET_AMP_SIDE(cmd),
- u8Index);
- else
- AssertMsgFailedReturn(("access to fields of %x need to be implemented\n", CODEC_NID(cmd)), VINF_SUCCESS);
- return VINF_SUCCESS;
-}
-
-/* 3-- */
-static DECLCALLBACK(int) vrbProcSetAmplifier(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- bool fIsLeft = false;
- bool fIsRight = false;
- bool fIsOut = false;
- bool fIsIn = false;
- uint8_t u8Index = 0;
- Assert(CODEC_CAD(cmd) == pThis->id);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- PCODECNODE pNode = &pThis->paNodes[CODEC_NID(cmd)];
- AMPLIFIER *pAmplifier;
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- pAmplifier = &pNode->dac.B_params;
- else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
- pAmplifier = &pNode->adcvol.B_params;
- else if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
- pAmplifier = &pNode->adcmux.B_params;
- else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
- pAmplifier = &pNode->pcbeep.B_params;
- else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- pAmplifier = &pNode->port.B_params;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- pAmplifier = &pNode->adc.B_params;
- else
- AssertFailedReturn(VINF_SUCCESS);
-
- fIsOut = CODEC_SET_AMP_IS_OUT_DIRECTION(cmd);
- fIsIn = CODEC_SET_AMP_IS_IN_DIRECTION(cmd);
- fIsRight = CODEC_SET_AMP_IS_RIGHT_SIDE(cmd);
- fIsLeft = CODEC_SET_AMP_IS_LEFT_SIDE(cmd);
- u8Index = CODEC_SET_AMP_INDEX(cmd);
- if ( (!fIsLeft && !fIsRight)
- || (!fIsOut && !fIsIn))
- return VINF_SUCCESS;
- if (fIsIn)
- {
- if (fIsLeft)
- hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_LEFT, u8Index), cmd, 0);
- if (fIsRight)
- hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_IN, AMPLIFIER_RIGHT, u8Index), cmd, 0);
-
- /** @todo Fix ID of u8AdcVolsLineIn! */
- hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_LINE_IN);
- }
- if (fIsOut)
- {
- if (fIsLeft)
- hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_LEFT, u8Index), cmd, 0);
- if (fIsRight)
- hdaCodecSetRegisterU8(&LIFIER_REGISTER(*pAmplifier, AMPLIFIER_OUT, AMPLIFIER_RIGHT, u8Index), cmd, 0);
-
- if (CODEC_NID(cmd) == pThis->u8DacLineOut)
- hdaCodecToAudVolume(pThis, pAmplifier, PDMAUDIOMIXERCTL_PCM);
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) vrbProcGetParameter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F00_PARAM_LENGTH);
- if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F00_PARAM_LENGTH)
- {
- LogFlowFunc(("invalid F00 parameter %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
- return VINF_SUCCESS;
- }
- *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F00_param[cmd & CODEC_VERB_8BIT_DATA];
- return VINF_SUCCESS;
-}
-
-/* F01 */
-static DECLCALLBACK(int) vrbProcGetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param;
- else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
- else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
- return VINF_SUCCESS;
-}
-
-/* 701 */
-static DECLCALLBACK(int) vrbProcSetConSelectCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- uint32_t *pu32Reg;
- if (hdaCodecIsAdcMuxNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcmux.u32F01_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F01_param;
- else if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F01_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F01_param;
- else if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F01_param;
- else
- AssertFailedReturn(VINF_SUCCESS);
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
- return VINF_SUCCESS;
-}
-
-/* F07 */
-static DECLCALLBACK(int) vrbProcGetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param;
- else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
- else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
- else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
- else
- AssertMsgFailed(("Unsupported"));
- return VINF_SUCCESS;
-}
-
-/* 707 */
-static DECLCALLBACK(int) vrbProcSetPinCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- uint32_t *pu32Reg;
- if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F07_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F07_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F07_param;
- else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F07_param;
- else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F07_param;
- else if ( hdaCodecIsReservedNode(pThis, CODEC_NID(cmd))
- && CODEC_NID(cmd) == 0x1b)
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F07_param;
- else
- AssertFailedReturn(VINF_SUCCESS);
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
- return VINF_SUCCESS;
-}
-
-/* F08 */
-static DECLCALLBACK(int) vrbProcGetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
- else if ((cmd) == 1 /* AFG */)
- *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
- else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
- else
- AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
- return VINF_SUCCESS;
-}
-
-/* 708 */
-static DECLCALLBACK(int) vrbProcSetUnsolicitedEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- uint32_t *pu32Reg;
- if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F08_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
- else if (CODEC_NID(cmd) == 1 /* AFG */)
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F08_param;
- else if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F08_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F08_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F08_param;
- else
- AssertMsgFailedReturn(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)), VINF_SUCCESS);
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
- return VINF_SUCCESS;
-}
-
-/* F09 */
-static DECLCALLBACK(int) vrbProcGetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
- else
- AssertMsgFailed(("unsupported operation %x on node: %x\n", CODEC_VERB_CMD8(cmd), CODEC_NID(cmd)));
- return VINF_SUCCESS;
-}
-
-/* 709 */
-static DECLCALLBACK(int) vrbProcSetPinSense(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- uint32_t *pu32Reg;
- if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F09_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F09_param;
- else
- AssertFailedReturn(VINF_SUCCESS);
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) vrbProcGetConnectionListEntry(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- *pResp = 0;
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- Assert((cmd & CODEC_VERB_8BIT_DATA) < CODECNODE_F02_PARAM_LENGTH);
- if ((cmd & CODEC_VERB_8BIT_DATA) >= CODECNODE_F02_PARAM_LENGTH)
- {
- LogFlowFunc(("access to invalid F02 index %d\n", (cmd & CODEC_VERB_8BIT_DATA)));
- return VINF_SUCCESS;
- }
- *pResp = pThis->paNodes[CODEC_NID(cmd)].node.au32F02_param[cmd & CODEC_VERB_8BIT_DATA];
- return VINF_SUCCESS;
-}
-
-/* F03 */
-static DECLCALLBACK(int) vrbProcGetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param;
- return VINF_SUCCESS;
-}
-
-/* 703 */
-static DECLCALLBACK(int) vrbProcSetProcessingState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].adc.u32F03_param, cmd, 0);
- return VINF_SUCCESS;
-}
-
-/* F0D */
-static DECLCALLBACK(int) vrbProcGetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param;
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param;
- return VINF_SUCCESS;
-}
-
-static int codecSetDigitalConverter(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F0d_param, cmd, u8Offset);
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- hdaCodecSetRegisterU8(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F0d_param, cmd, u8Offset);
- return VINF_SUCCESS;
-}
-
-/* 70D */
-static DECLCALLBACK(int) vrbProcSetDigitalConverter1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- return codecSetDigitalConverter(pThis, cmd, 0, pResp);
-}
-
-/* 70E */
-static DECLCALLBACK(int) vrbProcSetDigitalConverter2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- return codecSetDigitalConverter(pThis, cmd, 8, pResp);
-}
-
-/* F20 */
-static DECLCALLBACK(int) vrbProcGetSubId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- if (CODEC_NID(cmd) == 1 /* AFG */)
- *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
- else
- *pResp = 0;
- return VINF_SUCCESS;
-}
-
-static int codecSetSubIdX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- uint32_t *pu32Reg;
- if (CODEC_NID(cmd) == 0x1 /* AFG */)
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F20_param;
- else
- AssertFailedReturn(VINF_SUCCESS);
- hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
- return VINF_SUCCESS;
-}
-
-/* 720 */
-static DECLCALLBACK(int) vrbProcSetSubId0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
- return codecSetSubIdX(pThis, cmd, 0);
-}
-
-/* 721 */
-static DECLCALLBACK(int) vrbProcSetSubId1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
- return codecSetSubIdX(pThis, cmd, 8);
-}
-
-/* 722 */
-static DECLCALLBACK(int) vrbProcSetSubId2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
- return codecSetSubIdX(pThis, cmd, 16);
-}
-
-/* 723 */
-static DECLCALLBACK(int) vrbProcSetSubId3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
- return codecSetSubIdX(pThis, cmd, 24);
-}
-
-static DECLCALLBACK(int) vrbProcReset(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) == 1 /* AFG */);
- if ( CODEC_NID(cmd) == 1 /* AFG */
- && pThis->pfnCodecNodeReset)
- {
- uint8_t i;
- LogFlowFunc(("enters reset\n"));
- Assert(pThis->pfnCodecNodeReset);
- for (i = 0; i < pThis->cTotalNodes; ++i)
- {
- pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
- }
- pThis->fInReset = false;
- LogFlowFunc(("exits reset\n"));
- }
- *pResp = 0;
- return VINF_SUCCESS;
-}
-
-/* F05 */
-static DECLCALLBACK(int) vrbProcGetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (CODEC_NID(cmd) == 1 /* AFG */)
- *pResp = pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
- else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
- else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
- else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
- return VINF_SUCCESS;
-}
-
-/* 705 */
-
-DECLINLINE(void) codecPropogatePowerState(uint32_t *pu32F05_param)
-{
- Assert(pu32F05_param);
- if (!pu32F05_param)
- return;
- bool fReset = CODEC_F05_IS_RESET(*pu32F05_param);
- bool fStopOk = CODEC_F05_IS_STOPOK(*pu32F05_param);
- uint8_t u8SetPowerState = CODEC_F05_SET(*pu32F05_param);
- *pu32F05_param = CODEC_MAKE_F05(fReset, fStopOk, 0, u8SetPowerState, u8SetPowerState);
-}
-
-static DECLCALLBACK(int) vrbProcSetPowerState(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- uint32_t *pu32Reg;
- if (CODEC_NID(cmd) == 1 /* AFG */)
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].afg.u32F05_param;
- else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F05_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F05_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F05_param;
- else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F05_param;
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F05_param;
- else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F05_param;
- else
- AssertFailedReturn(VINF_SUCCESS);
-
- bool fReset = CODEC_F05_IS_RESET(*pu32Reg);
- bool fStopOk = CODEC_F05_IS_STOPOK(*pu32Reg);
-
- if (CODEC_NID(cmd) != 1 /* AFG */)
- {
- /*
- * We shouldn't propogate actual power state, which actual for AFG
- */
- *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0,
- CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param),
- CODEC_F05_SET(cmd));
- }
-
- /* Propagate next power state only if AFG is on or verb modifies AFG power state */
- if ( CODEC_NID(cmd) == 1 /* AFG */
- || !CODEC_F05_ACT(pThis->paNodes[1].afg.u32F05_param))
- {
- *pu32Reg = CODEC_MAKE_F05(fReset, fStopOk, 0, CODEC_F05_SET(cmd), CODEC_F05_SET(cmd));
- if ( CODEC_NID(cmd) == 1 /* AFG */
- && (CODEC_F05_SET(cmd)) == CODEC_F05_D0)
- {
- /* now we're powered on AFG and may propogate power states on nodes */
- const uint8_t *pu8NodeIndex = &pThis->au8Dacs[0];
- while (*(++pu8NodeIndex))
- codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].dac.u32F05_param);
-
- pu8NodeIndex = &pThis->au8Adcs[0];
- while (*(++pu8NodeIndex))
- codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].adc.u32F05_param);
-
- pu8NodeIndex = &pThis->au8DigInPins[0];
- while (*(++pu8NodeIndex))
- codecPropogatePowerState(&pThis->paNodes[*pu8NodeIndex].digin.u32F05_param);
- }
- }
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) vrbProcGetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
- else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
- else if (CODEC_NID(cmd) == 0x1A)
- *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) vrbProcSetStreamId(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- uint32_t *pu32addr;
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- pu32addr = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F06_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- pu32addr = &pThis->paNodes[CODEC_NID(cmd)].adc.u32F06_param;
- else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifout.u32F06_param;
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- pu32addr = &pThis->paNodes[CODEC_NID(cmd)].spdifin.u32F06_param;
- else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- pu32addr = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F06_param;
- else
- AssertFailedReturn(VINF_SUCCESS);
- hdaCodecSetRegisterU8(pu32addr, cmd, 0);
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) vrbProcGetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param;
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param;
- else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param;
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param;
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) vrbProcSetConverterFormat(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].dac.u32A_param, cmd, 0);
- else if (hdaCodecIsAdcNode(pThis, CODEC_NID(cmd)))
- hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].adc.u32A_param, cmd, 0);
- else if (hdaCodecIsSpdifOutNode(pThis, CODEC_NID(cmd)))
- hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifout.u32A_param, cmd, 0);
- else if (hdaCodecIsSpdifInNode(pThis, CODEC_NID(cmd)))
- hdaCodecSetRegisterU16(&pThis->paNodes[CODEC_NID(cmd)].spdifin.u32A_param, cmd, 0);
- return VINF_SUCCESS;
-}
-
-/* F0C */
-static DECLCALLBACK(int) vrbProcGetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
- else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
- return VINF_SUCCESS;
-}
-
-/* 70C */
-static DECLCALLBACK(int) vrbProcSetEAPD_BTLEnabled(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
-
- *pResp = 0;
- uint32_t *pu32Reg;
- if (hdaCodecIsAdcVolNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].adcvol.u32F0c_param;
- else if (hdaCodecIsDacNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].dac.u32F0c_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F0c_param;
- else
- AssertFailedReturn(VINF_SUCCESS);
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
-
- return VINF_SUCCESS;
-}
-
-/* F0F */
-static DECLCALLBACK(int) vrbProcGetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
- return VINF_SUCCESS;
-}
-
-/* 70F */
-static DECLCALLBACK(int) vrbProcSetVolumeKnobCtrl(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- uint32_t *pu32Reg = NULL;
- *pResp = 0;
- if (hdaCodecIsVolKnobNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].volumeKnob.u32F0f_param;
- Assert(pu32Reg);
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
- return VINF_SUCCESS;
-}
-
-/* F17 */
-static DECLCALLBACK(int) vrbProcGetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- /* note: this is true for ALC885 */
- if (CODEC_NID(cmd) == 0x1 /* AFG */)
- *pResp = pThis->paNodes[1].afg.u32F17_param;
- return VINF_SUCCESS;
-}
-
-/* 717 */
-static DECLCALLBACK(int) vrbProcSetGPIOUnsolisted(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- uint32_t *pu32Reg = NULL;
- *pResp = 0;
- if (CODEC_NID(cmd) == 1 /* AFG */)
- pu32Reg = &pThis->paNodes[1].afg.u32F17_param;
- Assert(pu32Reg);
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, 0);
- return VINF_SUCCESS;
-}
-
-/* F1C */
-static DECLCALLBACK(int) vrbProcGetConfig(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- *pResp = 0;
- if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param;
- else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
- else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
- else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- *pResp = pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
- return VINF_SUCCESS;
-}
-
-static int codecSetConfigX(PHDACODEC pThis, uint32_t cmd, uint8_t u8Offset)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- Assert(CODEC_NID(cmd) < pThis->cTotalNodes);
- if (CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- LogFlowFunc(("invalid node address %d\n", CODEC_NID(cmd)));
- return VINF_SUCCESS;
- }
- uint32_t *pu32Reg = NULL;
- if (hdaCodecIsPortNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].port.u32F1c_param;
- else if (hdaCodecIsDigInPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digin.u32F1c_param;
- else if (hdaCodecIsDigOutPinNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].digout.u32F1c_param;
- else if (hdaCodecIsCdNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].cdnode.u32F1c_param;
- else if (hdaCodecIsPcbeepNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].pcbeep.u32F1c_param;
- else if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- pu32Reg = &pThis->paNodes[CODEC_NID(cmd)].reserved.u32F1c_param;
- Assert(pu32Reg);
- if (pu32Reg)
- hdaCodecSetRegisterU8(pu32Reg, cmd, u8Offset);
- return VINF_SUCCESS;
-}
-
-/* 71C */
-static DECLCALLBACK(int) vrbProcSetConfig0(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
- return codecSetConfigX(pThis, cmd, 0);
-}
-
-/* 71D */
-static DECLCALLBACK(int) vrbProcSetConfig1(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
- return codecSetConfigX(pThis, cmd, 8);
-}
-
-/* 71E */
-static DECLCALLBACK(int) vrbProcSetConfig2(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
- return codecSetConfigX(pThis, cmd, 16);
-}
-
-/* 71E */
-static DECLCALLBACK(int) vrbProcSetConfig3(PHDACODEC pThis, uint32_t cmd, uint64_t *pResp)
-{
- *pResp = 0;
- return codecSetConfigX(pThis, cmd, 24);
-}
-
-
-/**
- * HDA codec verb map.
- * @todo Any reason not to use binary search here?
- */
-static const CODECVERB g_aCodecVerbs[] =
-{
-/* verb | verb mask | callback */
-/* ----------- -------------------- ----------------------- */
- { 0x000F0000, CODEC_VERB_8BIT_CMD , vrbProcGetParameter },
- { 0x000F0100, CODEC_VERB_8BIT_CMD , vrbProcGetConSelectCtrl },
- { 0x00070100, CODEC_VERB_8BIT_CMD , vrbProcSetConSelectCtrl },
- { 0x000F0600, CODEC_VERB_8BIT_CMD , vrbProcGetStreamId },
- { 0x00070600, CODEC_VERB_8BIT_CMD , vrbProcSetStreamId },
- { 0x000F0700, CODEC_VERB_8BIT_CMD , vrbProcGetPinCtrl },
- { 0x00070700, CODEC_VERB_8BIT_CMD , vrbProcSetPinCtrl },
- { 0x000F0800, CODEC_VERB_8BIT_CMD , vrbProcGetUnsolicitedEnabled },
- { 0x00070800, CODEC_VERB_8BIT_CMD , vrbProcSetUnsolicitedEnabled },
- { 0x000F0900, CODEC_VERB_8BIT_CMD , vrbProcGetPinSense },
- { 0x00070900, CODEC_VERB_8BIT_CMD , vrbProcSetPinSense },
- { 0x000F0200, CODEC_VERB_8BIT_CMD , vrbProcGetConnectionListEntry },
- { 0x000F0300, CODEC_VERB_8BIT_CMD , vrbProcGetProcessingState },
- { 0x00070300, CODEC_VERB_8BIT_CMD , vrbProcSetProcessingState },
- { 0x000F0D00, CODEC_VERB_8BIT_CMD , vrbProcGetDigitalConverter },
- { 0x00070D00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter1 },
- { 0x00070E00, CODEC_VERB_8BIT_CMD , vrbProcSetDigitalConverter2 },
- { 0x000F2000, CODEC_VERB_8BIT_CMD , vrbProcGetSubId },
- { 0x00072000, CODEC_VERB_8BIT_CMD , vrbProcSetSubId0 },
- { 0x00072100, CODEC_VERB_8BIT_CMD , vrbProcSetSubId1 },
- { 0x00072200, CODEC_VERB_8BIT_CMD , vrbProcSetSubId2 },
- { 0x00072300, CODEC_VERB_8BIT_CMD , vrbProcSetSubId3 },
- { 0x0007FF00, CODEC_VERB_8BIT_CMD , vrbProcReset },
- { 0x000F0500, CODEC_VERB_8BIT_CMD , vrbProcGetPowerState },
- { 0x00070500, CODEC_VERB_8BIT_CMD , vrbProcSetPowerState },
- { 0x000F0C00, CODEC_VERB_8BIT_CMD , vrbProcGetEAPD_BTLEnabled },
- { 0x00070C00, CODEC_VERB_8BIT_CMD , vrbProcSetEAPD_BTLEnabled },
- { 0x000F0F00, CODEC_VERB_8BIT_CMD , vrbProcGetVolumeKnobCtrl },
- { 0x00070F00, CODEC_VERB_8BIT_CMD , vrbProcSetVolumeKnobCtrl },
- { 0x000F1700, CODEC_VERB_8BIT_CMD , vrbProcGetGPIOUnsolisted },
- { 0x00071700, CODEC_VERB_8BIT_CMD , vrbProcSetGPIOUnsolisted },
- { 0x000F1C00, CODEC_VERB_8BIT_CMD , vrbProcGetConfig },
- { 0x00071C00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig0 },
- { 0x00071D00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig1 },
- { 0x00071E00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig2 },
- { 0x00071F00, CODEC_VERB_8BIT_CMD , vrbProcSetConfig3 },
- { 0x000A0000, CODEC_VERB_16BIT_CMD, vrbProcGetConverterFormat },
- { 0x00020000, CODEC_VERB_16BIT_CMD, vrbProcSetConverterFormat },
- { 0x000B0000, CODEC_VERB_16BIT_CMD, vrbProcGetAmplifier },
- { 0x00030000, CODEC_VERB_16BIT_CMD, vrbProcSetAmplifier },
-};
-
-#ifdef DEBUG
-typedef struct CODECDBGINFO
-{
- /** DBGF info helpers. */
- PCDBGFINFOHLP pHlp;
- /** Current recursion level. */
- uint8_t uLevel;
- /** Pointer to codec state. */
- PHDACODEC pThis;
-
-} CODECDBGINFO, *PCODECDBGINFO;
-
-#define CODECDBG_INDENT pInfo->uLevel++;
-#define CODECDBG_UNINDENT if (pInfo->uLevel) pInfo->uLevel--;
-
-#define CODECDBG_PRINT(...) pInfo->pHlp->pfnPrintf(pInfo->pHlp, __VA_ARGS__)
-#define CODECDBG_PRINTI(...) codecDbgPrintf(pInfo, __VA_ARGS__)
-
-static void codecDbgPrintfIndentV(PCODECDBGINFO pInfo, uint16_t uIndent, const char *pszFormat, va_list va)
-{
- char *pszValueFormat;
- if (RTStrAPrintfV(&pszValueFormat, pszFormat, va))
- {
- pInfo->pHlp->pfnPrintf(pInfo->pHlp, "%*s%s", uIndent, "", pszValueFormat);
- RTStrFree(pszValueFormat);
- }
-}
-
-static void codecDbgPrintf(PCODECDBGINFO pInfo, const char *pszFormat, ...)
-{
- va_list va;
- va_start(va, pszFormat);
- codecDbgPrintfIndentV(pInfo, pInfo->uLevel * 4, pszFormat, va);
- va_end(va);
-}
-
-/* Power state */
-static void codecDbgPrintNodeRegF05(PCODECDBGINFO pInfo, uint32_t u32Reg)
-{
- codecDbgPrintf(pInfo, "Power (F05): fReset=%RTbool, fStopOk=%RTbool, Set=%RU8, Act=%RU8\n",
- CODEC_F05_IS_RESET(u32Reg), CODEC_F05_IS_STOPOK(u32Reg), CODEC_F05_SET(u32Reg), CODEC_F05_ACT(u32Reg));
-}
-
-static void codecDbgPrintNodeRegA(PCODECDBGINFO pInfo, uint32_t u32Reg)
-{
- codecDbgPrintf(pInfo, "RegA: %x\n", u32Reg);
-}
-
-static void codecDbgPrintNodeRegF00(PCODECDBGINFO pInfo, uint32_t *paReg00)
-{
- codecDbgPrintf(pInfo, "Parameters (F00):\n");
-
- CODECDBG_INDENT
- codecDbgPrintf(pInfo, "Amplifier Caps:\n");
- uint32_t uReg = paReg00[0xD];
- CODECDBG_INDENT
- codecDbgPrintf(pInfo, "Input Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
- CODEC_F00_0D_NUM_STEPS(uReg),
- CODEC_F00_0D_STEP_SIZE(uReg),
- CODEC_F00_0D_OFFSET(uReg),
- RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
-
- uReg = paReg00[0x12];
- codecDbgPrintf(pInfo, "Output Steps=%02RU8, StepSize=%02RU8, StepOff=%02RU8, fCanMute=%RTbool\n",
- CODEC_F00_12_NUM_STEPS(uReg),
- CODEC_F00_12_STEP_SIZE(uReg),
- CODEC_F00_12_OFFSET(uReg),
- RT_BOOL(CODEC_F00_0D_IS_CAP_MUTE(uReg)));
- CODECDBG_UNINDENT
- CODECDBG_UNINDENT
-}
-
-static void codecDbgPrintNodeAmp(PCODECDBGINFO pInfo, uint32_t *paReg, uint8_t uIdx, uint8_t uDir)
-{
-#define CODECDBG_AMP(reg, chan) \
- codecDbgPrintf(pInfo, "Amp %RU8 %s %s: In=%RTbool, Out=%RTbool, Left=%RTbool, Right=%RTbool, Idx=%RU8, fMute=%RTbool, uGain=%RU8\n", \
- uIdx, chan, uDir == AMPLIFIER_IN ? "In" : "Out", \
- RT_BOOL(CODEC_SET_AMP_IS_IN_DIRECTION(reg)), RT_BOOL(CODEC_SET_AMP_IS_OUT_DIRECTION(reg)), \
- RT_BOOL(CODEC_SET_AMP_IS_LEFT_SIDE(reg)), RT_BOOL(CODEC_SET_AMP_IS_RIGHT_SIDE(reg)), \
- CODEC_SET_AMP_INDEX(reg), RT_BOOL(CODEC_SET_AMP_MUTE(reg)), CODEC_SET_AMP_GAIN(reg));
-
- uint32_t regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_LEFT, uIdx);
- CODECDBG_AMP(regAmp, "Left");
- regAmp = AMPLIFIER_REGISTER(paReg, uDir, AMPLIFIER_RIGHT, uIdx);
- CODECDBG_AMP(regAmp, "Right");
-
-#undef CODECDBG_AMP
-}
-
-#if 0 // unused
-static void codecDbgPrintNodeConnections(PCODECDBGINFO pInfo, PCODECNODE pNode)
-{
- if (pNode->node.au32F00_param[0xE] == 0) /* Directly connected to HDA link. */
- {
- codecDbgPrintf(pInfo, "[HDA LINK]\n");
- return;
- }
-}
-#endif
-
-static void codecDbgPrintNode(PCODECDBGINFO pInfo, PCODECNODE pNode)
-{
- codecDbgPrintf(pInfo, "Node 0x%02x (%02RU8): ", pNode->node.id, pNode->node.id);
-
- if (pNode->node.id == STAC9220_NID_ROOT)
- {
- CODECDBG_PRINT("ROOT\n");
- }
- else if (pNode->node.id == STAC9220_NID_AFG)
- {
- CODECDBG_PRINT("AFG\n");
- CODECDBG_INDENT
- codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
- codecDbgPrintNodeRegF05(pInfo, pNode->afg.u32F05_param);
- CODECDBG_UNINDENT
- }
- else if (hdaCodecIsPortNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("PORT\n");
- }
- else if (hdaCodecIsDacNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("DAC\n");
- CODECDBG_INDENT
- codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
- codecDbgPrintNodeRegF05(pInfo, pNode->dac.u32F05_param);
- codecDbgPrintNodeRegA (pInfo, pNode->dac.u32A_param);
- codecDbgPrintNodeAmp (pInfo, pNode->dac.B_params, 0, AMPLIFIER_OUT);
- CODECDBG_UNINDENT
- }
- else if (hdaCodecIsAdcVolNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("ADC VOLUME\n");
- CODECDBG_INDENT
- codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
- codecDbgPrintNodeRegA (pInfo, pNode->adcvol.u32A_params);
- codecDbgPrintNodeAmp (pInfo, pNode->adcvol.B_params, 0, AMPLIFIER_IN);
- CODECDBG_UNINDENT
- }
- else if (hdaCodecIsAdcNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("ADC\n");
- CODECDBG_INDENT
- codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
- codecDbgPrintNodeRegF05(pInfo, pNode->adc.u32F05_param);
- codecDbgPrintNodeRegA (pInfo, pNode->adc.u32A_param);
- codecDbgPrintNodeAmp (pInfo, pNode->adc.B_params, 0, AMPLIFIER_IN);
- CODECDBG_UNINDENT
- }
- else if (hdaCodecIsAdcMuxNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("ADC MUX\n");
- CODECDBG_INDENT
- codecDbgPrintNodeRegF00(pInfo, pNode->node.au32F00_param);
- codecDbgPrintNodeRegA (pInfo, pNode->adcmux.u32A_param);
- codecDbgPrintNodeAmp (pInfo, pNode->adcmux.B_params, 0, AMPLIFIER_IN);
- CODECDBG_UNINDENT
- }
- else if (hdaCodecIsPcbeepNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("PC BEEP\n");
- }
- else if (hdaCodecIsSpdifOutNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("SPDIF OUT\n");
- }
- else if (hdaCodecIsSpdifInNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("SPDIF IN\n");
- }
- else if (hdaCodecIsDigInPinNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("DIGITAL IN PIN\n");
- }
- else if (hdaCodecIsDigOutPinNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("DIGITAL OUT PIN\n");
- }
- else if (hdaCodecIsCdNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("CD\n");
- }
- else if (hdaCodecIsVolKnobNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("VOLUME KNOB\n");
- }
- else if (hdaCodecIsReservedNode(pInfo->pThis, pNode->node.id))
- {
- CODECDBG_PRINT("RESERVED\n");
- }
- else
- CODECDBG_PRINT("UNKNOWN TYPE 0x%x\n", pNode->node.id);
-}
-
-static DECLCALLBACK(void) codecDbgListNodes(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- RT_NOREF(pszArgs);
- pHlp->pfnPrintf(pHlp, "HDA LINK\n");
-
- CODECDBGINFO dbgInfo;
- dbgInfo.pHlp = pHlp;
- dbgInfo.pThis = pThis;
- dbgInfo.uLevel = 0;
-
- PCODECDBGINFO pInfo = &dbgInfo;
-
- CODECDBG_INDENT
- for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
- {
- PCODECNODE pNode = &pThis->paNodes[i];
- if (pNode->node.au32F00_param[0xE] == 0) /* Start with all nodes connected directly to the HDA (Azalia) link. */
- codecDbgPrintNode(&dbgInfo, pNode);
- }
- CODECDBG_UNINDENT
-}
-
-static DECLCALLBACK(void) codecDbgSelector(PHDACODEC pThis, PCDBGFINFOHLP pHlp, const char *pszArgs)
-{
- RT_NOREF(pThis, pHlp, pszArgs);
-}
-
-#endif /* DEBUG */
-
-static DECLCALLBACK(int) codecLookup(PHDACODEC pThis, uint32_t cmd, PPFNHDACODECVERBPROCESSOR pfn)
-{
- Assert(CODEC_CAD(cmd) == pThis->id);
- if (hdaCodecIsReservedNode(pThis, CODEC_NID(cmd)))
- LogFlowFunc(("cmd %x was addressed to reserved node\n", cmd));
-
- if ( CODEC_VERBDATA(cmd) == 0
- || CODEC_NID(cmd) >= pThis->cTotalNodes)
- {
- *pfn = vrbProcUnimplemented;
- /// @todo r=michaln: There needs to be a counter to avoid log flooding (see e.g. DevRTC.cpp)
- LogFlowFunc(("cmd %x was ignored\n", cmd));
- return VINF_SUCCESS;
- }
-
- for (int i = 0; i < pThis->cVerbs; ++i)
- {
- if ((CODEC_VERBDATA(cmd) & pThis->paVerbs[i].mask) == pThis->paVerbs[i].verb)
- {
- *pfn = pThis->paVerbs[i].pfn;
- return VINF_SUCCESS;
- }
- }
-
- *pfn = vrbProcUnimplemented;
- LogFlowFunc(("callback for %x wasn't found\n", CODEC_VERBDATA(cmd)));
- return VINF_SUCCESS;
-}
-
-/*
- * APIs exposed to DevHDA.
- */
-
-/**
- *
- * routines open one of the voices (IN, OUT) with corresponding parameters.
- * this routine could be called from HDA on setting/resseting sound format.
- *
- * @todo Probably passed settings should be verified (if AFG's declared proposed
- * format) before enabling.
- */
-int hdaCodecOpenStream(PHDACODEC pThis, ENMSOUNDSOURCE enmSoundSource, PPDMAUDIOSTREAMCFG pCfg)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- int rc;
- switch (enmSoundSource)
- {
- case PI_INDEX:
- rc = pThis->pfnOpenIn(pThis->pHDAState, "hda.in", PDMAUDIORECSOURCE_LINE_IN, pCfg);
- break;
-#ifdef VBOX_WITH_HDA_MIC_IN
- case MC_INDEX:
- rc = pThis->pfnOpenIn(pThis->pHDAState, "hda.mc", PDMAUDIORECSOURCE_MIC, pCfg);
- break;
-#endif
- case PO_INDEX:
- rc = pThis->pfnOpenOut(pThis->pHDAState, "hda.out", pCfg);
- break;
-
- default:
- AssertMsgFailed(("Index %ld not implemented\n", enmSoundSource));
- rc = VERR_NOT_IMPLEMENTED;
- }
-
- LogFlowFuncLeaveRC(rc);
- return rc;
-}
-
-int hdaCodecSaveState(PHDACODEC pThis, PSSMHANDLE pSSM)
-{
- AssertLogRelMsgReturn(pThis->cTotalNodes == 0x1c, ("cTotalNodes=%#x, should be 0x1c", pThis->cTotalNodes),
- VERR_INTERNAL_ERROR);
- SSMR3PutU32(pSSM, pThis->cTotalNodes);
- for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
- SSMR3PutStructEx(pSSM, &pThis->paNodes[idxNode].SavedState, sizeof(pThis->paNodes[idxNode].SavedState),
- 0 /*fFlags*/, g_aCodecNodeFields, NULL /*pvUser*/);
- return VINF_SUCCESS;
-}
-
-int hdaCodecLoadState(PHDACODEC pThis, PSSMHANDLE pSSM, uint32_t uVersion)
-{
- PCSSMFIELD pFields;
- uint32_t fFlags;
- switch (uVersion)
- {
- case HDA_SSM_VERSION_1:
- AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
- pFields = g_aCodecNodeFieldsV1;
- fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
- break;
-
- case HDA_SSM_VERSION_2:
- case HDA_SSM_VERSION_3:
- AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
- pFields = g_aCodecNodeFields;
- fFlags = SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED;
- break;
-
- /* Since version 4 a flexible node count is supported. */
- case HDA_SSM_VERSION_4:
- case HDA_SSM_VERSION_5:
- case HDA_SSM_VERSION:
- {
- uint32_t cNodes;
- int rc2 = SSMR3GetU32(pSSM, &cNodes);
- AssertRCReturn(rc2, rc2);
- if (cNodes != 0x1c)
- return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
- AssertReturn(pThis->cTotalNodes == 0x1c, VERR_INTERNAL_ERROR);
-
- pFields = g_aCodecNodeFields;
- fFlags = 0;
- break;
- }
-
- default:
- return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
- }
-
- for (unsigned idxNode = 0; idxNode < pThis->cTotalNodes; ++idxNode)
- {
- uint8_t idOld = pThis->paNodes[idxNode].SavedState.Core.id;
- int rc = SSMR3GetStructEx(pSSM, &pThis->paNodes[idxNode].SavedState,
- sizeof(pThis->paNodes[idxNode].SavedState),
- fFlags, pFields, NULL);
- if (RT_FAILURE(rc))
- return rc;
- AssertLogRelMsgReturn(idOld == pThis->paNodes[idxNode].SavedState.Core.id,
- ("loaded %#x, expected %#x\n", pThis->paNodes[idxNode].SavedState.Core.id, idOld),
- VERR_SSM_DATA_UNIT_FORMAT_CHANGED);
- }
-
- /*
- * Update stuff after changing the state.
- */
- if (hdaCodecIsDacNode(pThis, pThis->u8DacLineOut))
- hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_PCM);
- else if (hdaCodecIsSpdifOutNode(pThis, pThis->u8DacLineOut))
- hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].spdifout.B_params, PDMAUDIOMIXERCTL_PCM);
- hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
-
- return VINF_SUCCESS;
-}
-
-int hdaCodecDestruct(PHDACODEC pThis)
-{
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
-
- if (pThis->paNodes)
- {
- RTMemFree(pThis->paNodes);
- pThis->paNodes = NULL;
- }
-
- return VINF_SUCCESS;
-}
-
-int hdaCodecConstruct(PPDMDEVINS pDevIns, PHDACODEC pThis,
- uint16_t uLUN, PCFGMNODE pCfg)
-{
- AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
- AssertPtrReturn(pThis, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- pThis->id = uLUN;
- pThis->paVerbs = &g_aCodecVerbs[0];
- pThis->cVerbs = RT_ELEMENTS(g_aCodecVerbs);
-
- pThis->pfnLookup = codecLookup;
-#ifdef DEBUG
- pThis->pfnDbgSelector = codecDbgSelector;
- pThis->pfnDbgListNodes = codecDbgListNodes;
-#endif
- int rc = stac9220Construct(pThis);
- AssertRC(rc);
-
- /* common root node initializers */
- pThis->paNodes[0].node.au32F00_param[0] = CODEC_MAKE_F00_00(pThis->u16VendorId, pThis->u16DeviceId);
- pThis->paNodes[0].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x1, 0x1);
- /* common AFG node initializers */
- pThis->paNodes[1].node.au32F00_param[4] = CODEC_MAKE_F00_04(0x2, pThis->cTotalNodes - 2);
- pThis->paNodes[1].node.au32F00_param[5] = CODEC_MAKE_F00_05(1, CODEC_F00_05_AFG);
- pThis->paNodes[1].afg.u32F20_param = CODEC_MAKE_F20(pThis->u16VendorId, pThis->u8BSKU, pThis->u8AssemblyId);
-
- /* This codec uses a fixed setting (44.1 kHz, 16-bit signed, 2 channels). */
- pThis->strmCfg.uHz = 44100;
- pThis->strmCfg.cChannels = 2;
- pThis->strmCfg.enmFormat = AUD_FMT_S16;
- pThis->strmCfg.enmEndianness = PDMAUDIOHOSTENDIANNESS;
-
- hdaCodecOpenStream(pThis, PI_INDEX, &pThis->strmCfg);
-#ifdef VBOX_WITH_HDA_MIC_IN
- hdaCodecOpenStream(pThis, MC_INDEX, &pThis->strmCfg);
-#endif
- hdaCodecOpenStream(pThis, PO_INDEX, &pThis->strmCfg);
-
- /* Initialize the AFG node with the fixed setting. */
- pThis->paNodes[1].node.au32F00_param[0xA] = CODEC_F00_0A_44_1KHZ | CODEC_F00_0A_16_BIT;
-
- AssertPtr(pThis->paNodes);
- AssertPtr(pThis->pfnCodecNodeReset);
-
- for (uint8_t i = 0; i < pThis->cTotalNodes; i++)
- pThis->pfnCodecNodeReset(pThis, i, &pThis->paNodes[i]);
-
- hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8DacLineOut].dac.B_params, PDMAUDIOMIXERCTL_PCM);
- hdaCodecToAudVolume(pThis, &pThis->paNodes[pThis->u8AdcVolsLineIn].adcvol.B_params, PDMAUDIOMIXERCTL_LINE_IN);
-
- return VINF_SUCCESS;
-}
-
diff --git a/src/VBox/Devices/Audio_50/Makefile.kup b/src/VBox/Devices/Audio_50/Makefile.kup
deleted file mode 100644
index e69de29..0000000
diff --git a/src/VBox/Devices/Audio_50/alsa_mangling.h b/src/VBox/Devices/Audio_50/alsa_mangling.h
deleted file mode 100644
index fde5840..0000000
--- a/src/VBox/Devices/Audio_50/alsa_mangling.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/** @file
- *
- * Mangle libasound symbols. This is necessary on hosts which don't
- * support the -fvisibility gcc switch.
- */
-
-/*
- * Copyright (C) 2013-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef AUDIO_ALSA_MANGLING_H
-#define AUDIO_ALSA_MANGLING_H
-
-#define ALSA_MANGLER(symbol) VBox_##symbol
-
-#define snd_pcm_hw_params_any ALSA_MANGLER(snd_pcm_hw_params_any)
-#define snd_pcm_close ALSA_MANGLER(snd_pcm_close)
-#define snd_pcm_avail_update ALSA_MANGLER(snd_pcm_avail_update)
-#define snd_pcm_hw_params_set_channels_near ALSA_MANGLER(snd_pcm_hw_params_set_channels_near)
-#define snd_pcm_hw_params_set_period_time_near ALSA_MANGLER(snd_pcm_hw_params_set_period_time_near)
-#define snd_pcm_prepare ALSA_MANGLER(snd_pcm_prepare)
-#define snd_pcm_sw_params_sizeof ALSA_MANGLER(snd_pcm_sw_params_sizeof)
-#define snd_pcm_hw_params_set_period_size_near ALSA_MANGLER(snd_pcm_hw_params_set_period_size_near)
-#define snd_pcm_hw_params_get_period_size ALSA_MANGLER(snd_pcm_hw_params_get_period_size)
-#define snd_pcm_hw_params ALSA_MANGLER(snd_pcm_hw_params)
-#define snd_pcm_hw_params_sizeof ALSA_MANGLER(snd_pcm_hw_params_sizeof)
-#define snd_pcm_state ALSA_MANGLER(snd_pcm_state)
-#define snd_pcm_open ALSA_MANGLER(snd_pcm_open)
-#define snd_lib_error_set_handler ALSA_MANGLER(snd_lib_error_set_handler)
-#define snd_pcm_sw_params ALSA_MANGLER(snd_pcm_sw_params)
-#define snd_pcm_hw_params_get_period_size_min ALSA_MANGLER(snd_pcm_hw_params_get_period_size_min)
-#define snd_pcm_writei ALSA_MANGLER(snd_pcm_writei)
-#define snd_pcm_readi ALSA_MANGLER(snd_pcm_readi)
-#define snd_strerror ALSA_MANGLER(snd_strerror)
-#define snd_pcm_drop ALSA_MANGLER(snd_pcm_drop)
-#define snd_pcm_resume ALSA_MANGLER(snd_pcm_resume)
-#define snd_pcm_hw_params_get_buffer_size ALSA_MANGLER(snd_pcm_hw_params_get_buffer_size)
-#define snd_pcm_hw_params_set_rate_near ALSA_MANGLER(snd_pcm_hw_params_set_rate_near)
-#define snd_pcm_hw_params_set_access ALSA_MANGLER(snd_pcm_hw_params_set_access)
-#define snd_pcm_hw_params_set_buffer_time_near ALSA_MANGLER(snd_pcm_hw_params_set_buffer_time_near)
-#define snd_pcm_hw_params_set_buffer_size_near ALSA_MANGLER(snd_pcm_hw_params_set_buffer_size_near)
-#define snd_pcm_hw_params_get_buffer_size_min ALSA_MANGLER(snd_pcm_hw_params_get_buffer_size_min)
-#define snd_pcm_hw_params_set_format ALSA_MANGLER(snd_pcm_hw_params_set_format)
-#define snd_pcm_sw_params_current ALSA_MANGLER(snd_pcm_sw_params_current)
-#define snd_pcm_sw_params_set_start_threshold ALSA_MANGLER(snd_pcm_sw_params_set_start_threshold)
-
-#endif /* !AUDIO_ALSA_MANGLING_H */
diff --git a/src/VBox/Devices/Audio_50/alsa_stubs.c b/src/VBox/Devices/Audio_50/alsa_stubs.c
deleted file mode 100644
index cda485b..0000000
--- a/src/VBox/Devices/Audio_50/alsa_stubs.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/* $Id: alsa_stubs.c $ */
-/** @file
- * Stubs for libasound.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <iprt/assert.h>
-#include <iprt/ldr.h>
-#include <VBox/log.h>
-#include <VBox/err.h>
-
-#include <alsa/asoundlib.h>
-
-#include "alsa_stubs.h"
-
-#define VBOX_ALSA_LIB "libasound.so.2"
-
-#define PROXY_STUB(function, rettype, signature, shortsig) \
- static rettype (*pfn_ ## function) signature; \
- \
- rettype VBox_##function signature; \
- rettype VBox_##function signature \
- { \
- return pfn_ ## function shortsig; \
- }
-
-PROXY_STUB(snd_pcm_hw_params_any, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params),
- (pcm, params))
-PROXY_STUB(snd_pcm_close, int, (snd_pcm_t *pcm), (pcm))
-PROXY_STUB(snd_pcm_avail_update, snd_pcm_sframes_t, (snd_pcm_t *pcm),
- (pcm))
-PROXY_STUB(snd_pcm_hw_params_set_channels_near, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val),
- (pcm, params, val))
-PROXY_STUB(snd_pcm_hw_params_set_period_time_near, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir),
- (pcm, params, val, dir))
-PROXY_STUB(snd_pcm_prepare, int, (snd_pcm_t *pcm), (pcm))
-PROXY_STUB(snd_pcm_sw_params_sizeof, size_t, (void), ())
-PROXY_STUB(snd_pcm_hw_params_set_period_size_near, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir),
- (pcm, params, val, dir))
-PROXY_STUB(snd_pcm_hw_params_get_period_size, int,
- (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir),
- (params, frames, dir))
-PROXY_STUB(snd_pcm_hw_params, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params),
- (pcm, params))
-PROXY_STUB(snd_pcm_hw_params_sizeof, size_t, (void), ())
-PROXY_STUB(snd_pcm_state, snd_pcm_state_t, (snd_pcm_t *pcm), (pcm))
-PROXY_STUB(snd_pcm_open, int,
- (snd_pcm_t **pcm, const char *name, snd_pcm_stream_t stream, int mode),
- (pcm, name, stream, mode))
-PROXY_STUB(snd_lib_error_set_handler, int, (snd_lib_error_handler_t handler),
- (handler))
-PROXY_STUB(snd_pcm_sw_params, int,
- (snd_pcm_t *pcm, snd_pcm_sw_params_t *params),
- (pcm, params))
-PROXY_STUB(snd_pcm_hw_params_get_period_size_min, int,
- (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir),
- (params, frames, dir))
-PROXY_STUB(snd_pcm_writei, snd_pcm_sframes_t,
- (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size),
- (pcm, buffer, size))
-PROXY_STUB(snd_pcm_readi, snd_pcm_sframes_t,
- (snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size),
- (pcm, buffer, size))
-PROXY_STUB(snd_strerror, const char *, (int errnum), (errnum))
-PROXY_STUB(snd_pcm_drop, int, (snd_pcm_t *pcm), (pcm))
-PROXY_STUB(snd_pcm_resume, int, (snd_pcm_t *pcm), (pcm))
-PROXY_STUB(snd_pcm_hw_params_get_buffer_size, int,
- (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val),
- (params, val))
-PROXY_STUB(snd_pcm_hw_params_set_rate_near, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir),
- (pcm, params, val, dir))
-PROXY_STUB(snd_pcm_hw_params_set_access, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access),
- (pcm, params, _access))
-PROXY_STUB(snd_pcm_hw_params_set_buffer_time_near, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir),
- (pcm, params, val, dir))
-PROXY_STUB(snd_pcm_hw_params_set_buffer_size_near, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val),
- (pcm, params, val))
-PROXY_STUB(snd_pcm_hw_params_get_buffer_size_min, int,
- (const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val),
- (params, val))
-PROXY_STUB(snd_pcm_hw_params_set_format, int,
- (snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val),
- (pcm, params, val))
-PROXY_STUB(snd_pcm_sw_params_current, int,
- (snd_pcm_t *pcm, snd_pcm_sw_params_t *params),
- (pcm, params))
-PROXY_STUB(snd_pcm_sw_params_set_start_threshold, int,
- (snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val),
- (pcm, params, val))
-
-typedef struct
-{
- const char *name;
- void (**fn)(void);
-} SHARED_FUNC;
-
-#define ELEMENT(function) { #function , (void (**)(void)) & pfn_ ## function }
-static SHARED_FUNC SharedFuncs[] =
-{
- ELEMENT(snd_pcm_hw_params_any),
- ELEMENT(snd_pcm_close),
- ELEMENT(snd_pcm_avail_update),
- ELEMENT(snd_pcm_hw_params_set_channels_near),
- ELEMENT(snd_pcm_hw_params_set_period_time_near),
- ELEMENT(snd_pcm_prepare),
- ELEMENT(snd_pcm_sw_params_sizeof),
- ELEMENT(snd_pcm_hw_params_set_period_size_near),
- ELEMENT(snd_pcm_hw_params_get_period_size),
- ELEMENT(snd_pcm_hw_params),
- ELEMENT(snd_pcm_hw_params_sizeof),
- ELEMENT(snd_pcm_state),
- ELEMENT(snd_pcm_open),
- ELEMENT(snd_lib_error_set_handler),
- ELEMENT(snd_pcm_sw_params),
- ELEMENT(snd_pcm_hw_params_get_period_size_min),
- ELEMENT(snd_pcm_writei),
- ELEMENT(snd_pcm_readi),
- ELEMENT(snd_strerror),
- ELEMENT(snd_pcm_drop),
- ELEMENT(snd_pcm_resume),
- ELEMENT(snd_pcm_hw_params_get_buffer_size),
- ELEMENT(snd_pcm_hw_params_set_rate_near),
- ELEMENT(snd_pcm_hw_params_set_access),
- ELEMENT(snd_pcm_hw_params_set_buffer_time_near),
- ELEMENT(snd_pcm_hw_params_set_buffer_size_near),
- ELEMENT(snd_pcm_hw_params_get_buffer_size_min),
- ELEMENT(snd_pcm_hw_params_set_format),
- ELEMENT(snd_pcm_sw_params_current),
- ELEMENT(snd_pcm_sw_params_set_start_threshold),
-};
-#undef ELEMENT
-
-/**
- * Try to dynamically load the ALSA libraries. This function is not
- * thread-safe, and should be called before attempting to use any of the
- * ALSA functions.
- *
- * @returns iprt status code
- */
-int audioLoadAlsaLib(void)
-{
- int rc = VINF_SUCCESS;
- unsigned i;
- static enum { NO = 0, YES, FAIL } isLibLoaded = NO;
- RTLDRMOD hLib;
-
- LogFlowFunc(("\n"));
- /* If this is not NO then the function has obviously been called twice,
- which is likely to be a bug. */
- if (NO != isLibLoaded)
- {
- AssertMsgFailed(("isLibLoaded == %s\n", YES == isLibLoaded ? "YES" : "NO"));
- return YES == isLibLoaded ? VINF_SUCCESS : VERR_NOT_SUPPORTED;
- }
- isLibLoaded = FAIL;
- rc = RTLdrLoad(VBOX_ALSA_LIB, &hLib);
- if (RT_FAILURE(rc))
- {
- LogRelFunc(("Failed to load library %s\n", VBOX_ALSA_LIB));
- return rc;
- }
- for (i=0; i<RT_ELEMENTS(SharedFuncs); i++)
- {
- rc = RTLdrGetSymbol(hLib, SharedFuncs[i].name, (void**)SharedFuncs[i].fn);
- if (RT_FAILURE(rc))
- return rc;
- }
- isLibLoaded = YES;
- return rc;
-}
diff --git a/src/VBox/Devices/Audio_50/alsa_stubs.h b/src/VBox/Devices/Audio_50/alsa_stubs.h
deleted file mode 100644
index 889add3..0000000
--- a/src/VBox/Devices/Audio_50/alsa_stubs.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/** @file
- *
- * Stubs for libasound.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef AUDIO_ALSA_STUBS_H
-# define AUDIO_ALSA_STUBS_H
-extern int audioLoadAlsaLib(void);
-#endif
diff --git a/src/VBox/Devices/Audio_50/pulse_mangling.h b/src/VBox/Devices/Audio_50/pulse_mangling.h
deleted file mode 100644
index 8b02ef3..0000000
--- a/src/VBox/Devices/Audio_50/pulse_mangling.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/** @file
- *
- * Mangle libpulse symbols. This is necessary on hosts which don't
- * support the -fvisibility gcc switch.
- */
-
-/*
- * Copyright (C) 2013-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef AUDIO_PULSE_MANGLING_H
-#define AUDIO_PULSE_MANGLING_H
-
-#define PULSE_MANGLER(symbol) VBox_##symbol
-
-#define pa_stream_connect_playback PULSE_MANGLER(pa_stream_connect_playback)
-#define pa_stream_connect_record PULSE_MANGLER(pa_stream_connect_record)
-#define pa_stream_disconnect PULSE_MANGLER(pa_stream_disconnect)
-#define pa_stream_get_sample_spec PULSE_MANGLER(pa_stream_get_sample_spec)
-#define pa_stream_set_latency_update_callback PULSE_MANGLER(pa_stream_set_latency_update_callback)
-#define pa_stream_write PULSE_MANGLER(pa_stream_write)
-#define pa_stream_unref PULSE_MANGLER(pa_stream_unref)
-#define pa_stream_get_state PULSE_MANGLER(pa_stream_get_state)
-#define pa_stream_set_state_callback PULSE_MANGLER(pa_stream_set_state_callback)
-#define pa_stream_flush PULSE_MANGLER(pa_stream_flush)
-#define pa_stream_drain PULSE_MANGLER(pa_stream_drain)
-#define pa_stream_trigger PULSE_MANGLER(pa_stream_trigger)
-#define pa_stream_new PULSE_MANGLER(pa_stream_new)
-#define pa_stream_get_buffer_attr PULSE_MANGLER(pa_stream_get_buffer_attr)
-#define pa_stream_peek PULSE_MANGLER(pa_stream_peek)
-#define pa_stream_cork PULSE_MANGLER(pa_stream_cork)
-#define pa_stream_drop PULSE_MANGLER(pa_stream_drop)
-#define pa_stream_writable_size PULSE_MANGLER(pa_stream_writable_size)
-#define pa_context_connect PULSE_MANGLER(pa_context_connect)
-#define pa_context_disconnect PULSE_MANGLER(pa_context_disconnect)
-#define pa_context_get_state PULSE_MANGLER(pa_context_get_state)
-#define pa_context_unref PULSE_MANGLER(pa_context_unref)
-#define pa_context_errno PULSE_MANGLER(pa_context_errno)
-#define pa_context_new PULSE_MANGLER(pa_context_new)
-#define pa_context_set_state_callback PULSE_MANGLER(pa_context_set_state_callback)
-#define pa_threaded_mainloop_stop PULSE_MANGLER(pa_threaded_mainloop_stop)
-#define pa_threaded_mainloop_get_api PULSE_MANGLER(pa_threaded_mainloop_get_api)
-#define pa_threaded_mainloop_free PULSE_MANGLER(pa_threaded_mainloop_free)
-#define pa_threaded_mainloop_signal PULSE_MANGLER(pa_threaded_mainloop_signal)
-#define pa_threaded_mainloop_unlock PULSE_MANGLER(pa_threaded_mainloop_unlock)
-#define pa_threaded_mainloop_new PULSE_MANGLER(pa_threaded_mainloop_new)
-#define pa_threaded_mainloop_wait PULSE_MANGLER(pa_threaded_mainloop_wait)
-#define pa_threaded_mainloop_start PULSE_MANGLER(pa_threaded_mainloop_start)
-#define pa_threaded_mainloop_lock PULSE_MANGLER(pa_threaded_mainloop_lock)
-#define pa_bytes_per_second PULSE_MANGLER(pa_bytes_per_second)
-#define pa_frame_size PULSE_MANGLER(pa_frame_size)
-#define pa_sample_format_to_string PULSE_MANGLER(pa_sample_format_to_string)
-#define pa_sample_spec_valid PULSE_MANGLER(pa_sample_spec_valid)
-#define pa_channel_map_init_auto PULSE_MANGLER(pa_channel_map_init_auto)
-#define pa_operation_unref PULSE_MANGLER(pa_operation_unref)
-#define pa_operation_get_state PULSE_MANGLER(pa_operation_get_state)
-#define pa_operation_cancel PULSE_MANGLER(pa_operation_cancel)
-#define pa_strerror PULSE_MANGLER(pa_strerror)
-#define pa_stream_readable_size PULSE_MANGLER(pa_stream_readable_size)
-
-#endif /* !AUDIO_PULSE_MANGLING_H */
diff --git a/src/VBox/Devices/Audio_50/pulse_stubs.c b/src/VBox/Devices/Audio_50/pulse_stubs.c
deleted file mode 100644
index c38c090..0000000
--- a/src/VBox/Devices/Audio_50/pulse_stubs.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/* $Id: pulse_stubs.c $ */
-/** @file
- * Stubs for libpulse.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
-#include <iprt/assert.h>
-#include <iprt/ldr.h>
-#include <VBox/log.h>
-#include <VBox/err.h>
-
-#include <pulse/pulseaudio.h>
-
-#include "pulse_stubs.h"
-
-#define VBOX_PULSE_LIB "libpulse.so.0"
-
-#define PROXY_STUB(function, rettype, signature, shortsig) \
- static rettype (*g_pfn_ ## function) signature; \
- \
- rettype VBox_##function signature; \
- rettype VBox_##function signature \
- { \
- return g_pfn_ ## function shortsig; \
- }
-
-#define PROXY_STUB_VOID(function, signature, shortsig) \
- static void (*g_pfn_ ## function) signature; \
- \
- void VBox_##function signature; \
- void VBox_##function signature \
- { \
- g_pfn_ ## function shortsig; \
- }
-
-#if PA_PROTOCOL_VERSION >= 16
-PROXY_STUB (pa_stream_connect_playback, int,
- (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
- pa_stream_flags_t flags, const pa_cvolume *volume, pa_stream *sync_stream),
- (s, dev, attr, flags, volume, sync_stream))
-#else
-PROXY_STUB (pa_stream_connect_playback, int,
- (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
- pa_stream_flags_t flags, pa_cvolume *volume, pa_stream *sync_stream),
- (s, dev, attr, flags, volume, sync_stream))
-#endif
-PROXY_STUB (pa_stream_connect_record, int,
- (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
- pa_stream_flags_t flags),
- (s, dev, attr, flags))
-PROXY_STUB (pa_stream_disconnect, int,
- (pa_stream *s),
- (s))
-PROXY_STUB (pa_stream_get_sample_spec, const pa_sample_spec*,
- (pa_stream *s),
- (s))
-PROXY_STUB_VOID(pa_stream_set_latency_update_callback,
- (pa_stream *p, pa_stream_notify_cb_t cb, void *userdata),
- (p, cb, userdata))
-PROXY_STUB (pa_stream_write, int,
- (pa_stream *p, const void *data, size_t bytes, pa_free_cb_t free_cb,
- int64_t offset, pa_seek_mode_t seek),
- (p, data, bytes, free_cb, offset, seek))
-PROXY_STUB_VOID(pa_stream_unref,
- (pa_stream *s),
- (s))
-PROXY_STUB (pa_stream_get_state, pa_stream_state_t,
- (pa_stream *p),
- (p))
-PROXY_STUB_VOID(pa_stream_set_state_callback,
- (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
- (s, cb, userdata))
-PROXY_STUB (pa_stream_flush, pa_operation*,
- (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
- (s, cb, userdata))
-PROXY_STUB (pa_stream_drain, pa_operation*,
- (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
- (s, cb, userdata))
-PROXY_STUB (pa_stream_trigger, pa_operation*,
- (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
- (s, cb, userdata))
-PROXY_STUB (pa_stream_new, pa_stream*,
- (pa_context *c, const char *name, const pa_sample_spec *ss,
- const pa_channel_map *map),
- (c, name, ss, map))
-PROXY_STUB (pa_stream_get_buffer_attr, const pa_buffer_attr*,
- (pa_stream *s),
- (s))
-PROXY_STUB (pa_stream_peek, int,
- (pa_stream *p, const void **data, size_t *bytes),
- (p, data, bytes))
-PROXY_STUB (pa_stream_cork, pa_operation*,
- (pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata),
- (s, b, cb, userdata))
-PROXY_STUB (pa_stream_drop, int,
- (pa_stream *p),
- (p))
-PROXY_STUB (pa_stream_writable_size, size_t,
- (pa_stream *p),
- (p))
-PROXY_STUB (pa_context_connect, int,
- (pa_context *c, const char *server, pa_context_flags_t flags,
- const pa_spawn_api *api),
- (c, server, flags, api))
-PROXY_STUB_VOID(pa_context_disconnect,
- (pa_context *c),
- (c))
-PROXY_STUB (pa_context_get_state, pa_context_state_t,
- (pa_context *c),
- (c))
-PROXY_STUB_VOID(pa_context_unref,
- (pa_context *c),
- (c))
-PROXY_STUB (pa_context_errno, int,
- (pa_context *c),
- (c))
-PROXY_STUB (pa_context_new, pa_context*,
- (pa_mainloop_api *mainloop, const char *name),
- (mainloop, name))
-PROXY_STUB_VOID(pa_context_set_state_callback,
- (pa_context *c, pa_context_notify_cb_t cb, void *userdata),
- (c, cb, userdata))
-PROXY_STUB_VOID(pa_threaded_mainloop_stop,
- (pa_threaded_mainloop *m),
- (m))
-PROXY_STUB (pa_threaded_mainloop_get_api, pa_mainloop_api*,
- (pa_threaded_mainloop *m),
- (m))
-PROXY_STUB_VOID(pa_threaded_mainloop_free,
- (pa_threaded_mainloop* m),
- (m))
-PROXY_STUB_VOID(pa_threaded_mainloop_signal,
- (pa_threaded_mainloop *m, int wait_for_accept),
- (m, wait_for_accept))
-PROXY_STUB_VOID(pa_threaded_mainloop_unlock,
- (pa_threaded_mainloop *m),
- (m))
-PROXY_STUB (pa_threaded_mainloop_new, pa_threaded_mainloop *,
- (void),
- ())
-PROXY_STUB_VOID(pa_threaded_mainloop_wait,
- (pa_threaded_mainloop *m),
- (m))
-PROXY_STUB (pa_threaded_mainloop_start, int,
- (pa_threaded_mainloop *m),
- (m))
-PROXY_STUB_VOID(pa_threaded_mainloop_lock,
- (pa_threaded_mainloop *m),
- (m))
-PROXY_STUB (pa_bytes_per_second, size_t,
- (const pa_sample_spec *spec),
- (spec))
-PROXY_STUB (pa_frame_size, size_t,
- (const pa_sample_spec *spec),
- (spec))
-PROXY_STUB (pa_sample_format_to_string, const char*,
- (pa_sample_format_t f),
- (f))
-PROXY_STUB (pa_sample_spec_valid, int,
- (const pa_sample_spec *spec),
- (spec))
-PROXY_STUB (pa_channel_map_init_auto, pa_channel_map*,
- (pa_channel_map *m, unsigned channels, pa_channel_map_def_t def),
- (m, channels, def))
-PROXY_STUB_VOID(pa_operation_unref,
- (pa_operation *o),
- (o))
-PROXY_STUB (pa_operation_get_state, pa_operation_state_t,
- (pa_operation *o),
- (o))
-PROXY_STUB_VOID(pa_operation_cancel,
- (pa_operation *o),
- (o))
-PROXY_STUB (pa_strerror, const char*,
- (int error),
- (error))
-PROXY_STUB (pa_stream_readable_size, size_t,
- (pa_stream *p),
- (p))
-
-
-typedef struct
-{
- const char *name;
- void (**fn)(void);
-} SHARED_FUNC;
-
-#define ELEMENT(function) { #function , (void (**)(void)) & g_pfn_ ## function }
-static SHARED_FUNC SharedFuncs[] =
-{
- ELEMENT(pa_stream_connect_playback),
- ELEMENT(pa_stream_connect_record),
- ELEMENT(pa_stream_disconnect),
- ELEMENT(pa_stream_get_sample_spec),
- ELEMENT(pa_stream_set_latency_update_callback),
- ELEMENT(pa_stream_write),
- ELEMENT(pa_stream_unref),
- ELEMENT(pa_stream_get_state),
- ELEMENT(pa_stream_set_state_callback),
- ELEMENT(pa_stream_flush),
- ELEMENT(pa_stream_drain),
- ELEMENT(pa_stream_trigger),
- ELEMENT(pa_stream_new),
- ELEMENT(pa_stream_get_buffer_attr),
- ELEMENT(pa_stream_peek),
- ELEMENT(pa_stream_cork),
- ELEMENT(pa_stream_drop),
- ELEMENT(pa_stream_writable_size),
- ELEMENT(pa_context_connect),
- ELEMENT(pa_context_disconnect),
- ELEMENT(pa_context_get_state),
- ELEMENT(pa_context_unref),
- ELEMENT(pa_context_errno),
- ELEMENT(pa_context_new),
- ELEMENT(pa_context_set_state_callback),
- ELEMENT(pa_threaded_mainloop_stop),
- ELEMENT(pa_threaded_mainloop_get_api),
- ELEMENT(pa_threaded_mainloop_free),
- ELEMENT(pa_threaded_mainloop_signal),
- ELEMENT(pa_threaded_mainloop_unlock),
- ELEMENT(pa_threaded_mainloop_new),
- ELEMENT(pa_threaded_mainloop_wait),
- ELEMENT(pa_threaded_mainloop_start),
- ELEMENT(pa_threaded_mainloop_lock),
- ELEMENT(pa_bytes_per_second),
- ELEMENT(pa_frame_size),
- ELEMENT(pa_sample_format_to_string),
- ELEMENT(pa_sample_spec_valid),
- ELEMENT(pa_channel_map_init_auto),
- ELEMENT(pa_operation_unref),
- ELEMENT(pa_operation_get_state),
- ELEMENT(pa_operation_cancel),
- ELEMENT(pa_strerror),
- ELEMENT(pa_stream_readable_size)
-};
-#undef ELEMENT
-
-/**
- * Try to dynamically load the PulseAudio libraries. This function is not
- * thread-safe, and should be called before attempting to use any of the
- * PulseAudio functions.
- *
- * @returns iprt status code
- */
-int audioLoadPulseLib(void)
-{
- int rc = VINF_SUCCESS;
- unsigned i;
- static enum { NO = 0, YES, FAIL } isLibLoaded = NO;
- RTLDRMOD hLib;
-
- LogFlowFunc(("\n"));
- /* If this is not NO then the function has obviously been called twice,
- which is likely to be a bug. */
- if (NO != isLibLoaded)
- {
- AssertMsgFailed(("isLibLoaded == %s\n", YES == isLibLoaded ? "YES" : "NO"));
- return YES == isLibLoaded ? VINF_SUCCESS : VERR_NOT_SUPPORTED;
- }
- isLibLoaded = FAIL;
- rc = RTLdrLoad(VBOX_PULSE_LIB, &hLib);
- if (RT_FAILURE(rc))
- {
- LogRelFunc(("Failed to load library %s\n", VBOX_PULSE_LIB));
- return rc;
- }
- for (i=0; i<RT_ELEMENTS(SharedFuncs); i++)
- {
- rc = RTLdrGetSymbol(hLib, SharedFuncs[i].name, (void**)SharedFuncs[i].fn);
- if (RT_FAILURE(rc))
- return rc;
- }
- isLibLoaded = YES;
- return rc;
-}
-
diff --git a/src/VBox/Devices/Audio_50/pulse_stubs.h b/src/VBox/Devices/Audio_50/pulse_stubs.h
deleted file mode 100644
index af393d3..0000000
--- a/src/VBox/Devices/Audio_50/pulse_stubs.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/** @file
- *
- * Stubs for libpulse.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef AUDIO_PULSE_STUBS_H
-#define AUDIO_PULSE_STUBS_H
-extern int audioLoadPulseLib(void);
-#endif
diff --git a/src/VBox/Devices/Audio_50/testcase/Makefile.kmk b/src/VBox/Devices/Audio_50/testcase/Makefile.kmk
deleted file mode 100644
index 8a0d8fe..0000000
--- a/src/VBox/Devices/Audio_50/testcase/Makefile.kmk
+++ /dev/null
@@ -1,41 +0,0 @@
-# $Id: Makefile.kmk $
-## @file
-# Sub-Makefile for the audio testcases.
-#
-
-#
-# Copyright (C) 2014-2015 Oracle Corporation
-#
-# This file is part of VirtualBox Open Source Edition (OSE), as
-# available from http://www.virtualbox.org. This file is free software;
-# you can redistribute it and/or modify it under the terms of the GNU
-# General Public License (GPL) as published by the Free Software
-# Foundation, in version 2 as it comes in the "COPYING" file of the
-# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
-# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
-#
-
-SUB_DEPTH = ../../../../..
-include $(KBUILD_PATH)/subheader.kmk
-
-if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBOX_ONLY_SDK)
-
- PROGRAMS += tstAudioMixBuffer
- TESTING += $(tstAudioMixBuffer_0_OUTDIR)/tstAudioMixBuffer.run
-
- tstAudioMixBuffer_TEMPLATE = VBOXR3TSTEXE
- tstAudioMixBuffer_DEFS += TESTCASE $(if-expr defined(VBOX_WITH_AUDIO_50),VBOX_WITH_AUDIO_50,)
- tstAudioMixBuffer_SOURCES = \
- tstAudioMixBuffer.cpp \
- ../AudioMixBuffer.cpp \
- ../DrvAudioCommon.cpp
- tstAudioMixBuffer_LIBS = $(LIB_RUNTIME)
-
- $$(tstAudioMixBuffer_0_OUTDIR)/tstAudioMixBuffer.run: $$(tstAudioMixBuffer_1_STAGE_TARGET)
- export VBOX_LOG_DEST=nofile; $(tstAudioMixBuffer_1_STAGE_TARGET) quiet
- $(QUIET)$(APPEND) -t "$@" "done"
-
-endif
-
-include $(FILE_KBUILD_SUB_FOOTER)
-
diff --git a/src/VBox/Devices/Audio_50/testcase/tstAudioMixBuffer.cpp b/src/VBox/Devices/Audio_50/testcase/tstAudioMixBuffer.cpp
deleted file mode 100644
index b297c93..0000000
--- a/src/VBox/Devices/Audio_50/testcase/tstAudioMixBuffer.cpp
+++ /dev/null
@@ -1,591 +0,0 @@
-/* $Id: tstAudioMixBuffer.cpp $ */
-/** @file
- * Audio testcase - Mixing buffer.
- */
-
-/*
- * Copyright (C) 2014-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#include <iprt/err.h>
-#include <iprt/initterm.h>
-#include <iprt/mem.h>
-#include <iprt/rand.h>
-#include <iprt/stream.h>
-#include <iprt/string.h>
-#include <iprt/test.h>
-
-
-#include "../AudioMixBuffer.h"
-#include "../DrvAudio.h"
-
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
-
-static int tstSingle(RTTEST hTest)
-{
- RTTestSubF(hTest, "Single buffer");
-
- PDMAUDIOSTREAMCFG config =
- {
- 44100, /* Hz */
- 2 /* Channels */,
- AUD_FMT_S16 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
- PDMPCMPROPS props;
-
- int rc = DrvAudioStreamCfgToProps(&config, &props);
- AssertRC(rc);
-
- uint32_t cBufSize = _1K;
-
- /*
- * General stuff.
- */
- PDMAUDIOMIXBUF mb;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&mb, "Single", &props, cBufSize));
- RTTESTI_CHECK(AudioMixBufSize(&mb) == cBufSize);
- RTTESTI_CHECK(AUDIOMIXBUF_B2S(&mb, AudioMixBufSizeBytes(&mb)) == cBufSize);
- RTTESTI_CHECK(AUDIOMIXBUF_S2B(&mb, AudioMixBufSize(&mb)) == AudioMixBufSizeBytes(&mb));
- RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize);
- RTTESTI_CHECK(AUDIOMIXBUF_S2B(&mb, AudioMixBufFree(&mb)) == AudioMixBufFreeBytes(&mb));
-
- /*
- * Absolute writes.
- */
- uint32_t read = 0, written = 0, written_abs = 0;
- int8_t samples8 [2] = { 0x12, 0x34 };
- int16_t samples16[2] = { 0xAA, 0xBB };
- int32_t samples32[2] = { 0xCC, 0xDD };
-
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0, &samples8, sizeof(samples8), &written));
- RTTESTI_CHECK(written == 0 /* Samples */);
-
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0, &samples16, sizeof(samples16), &written));
- RTTESTI_CHECK(written == 1 /* Samples */);
-
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 2, &samples32, sizeof(samples32), &written));
- RTTESTI_CHECK(written == 2 /* Samples */);
- written_abs = 0;
-
- /* Beyond buffer. */
- RTTESTI_CHECK_RC(AudioMixBufWriteAt(&mb, AudioMixBufSize(&mb) + 1, &samples16, sizeof(samples16),
- &written), VERR_BUFFER_OVERFLOW);
-
- /*
- * Circular writes.
- */
- uint32_t cToWrite = AudioMixBufSize(&mb) - written_abs - 1; /* -1 as padding plus -2 samples for above. */
- for (uint32_t i = 0; i < cToWrite; i++)
- {
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &written));
- RTTESTI_CHECK(written == 1);
- }
- RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
- RTTESTI_CHECK(AudioMixBufFree(&mb) == 1);
- RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, 1U));
- RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cToWrite + written_abs /* + last absolute write */);
-
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &samples16, sizeof(samples16), &written));
- RTTESTI_CHECK(written == 1);
- RTTESTI_CHECK(AudioMixBufFree(&mb) == 0);
- RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == (uint32_t)AUDIOMIXBUF_S2B(&mb, 0));
- RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cBufSize);
-
- /* Circular reads. */
- uint32_t cToRead = AudioMixBufSize(&mb) - written_abs - 1;
- for (uint32_t i = 0; i < cToWrite; i++)
- {
- RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &read));
- RTTESTI_CHECK(read == 1);
- AudioMixBufFinish(&mb, read);
- }
- RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
- RTTESTI_CHECK(AudioMixBufFree(&mb) == AudioMixBufSize(&mb) - written_abs - 1);
- RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - written_abs - 1));
- RTTESTI_CHECK(AudioMixBufProcessed(&mb) == cBufSize - cToRead + written_abs);
-
- RTTESTI_CHECK_RC_OK(AudioMixBufReadCirc(&mb, &samples16, sizeof(samples16), &read));
- RTTESTI_CHECK(read == 1);
- AudioMixBufFinish(&mb, read);
- RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize - written_abs);
- RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_S2B(&mb, cBufSize - written_abs));
- RTTESTI_CHECK(AudioMixBufProcessed(&mb) == written_abs);
-
- AudioMixBufDestroy(&mb);
-
- return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
-}
-
-static int tstParentChild(RTTEST hTest)
-{
- RTTestSubF(hTest, "2 Children -> Parent");
-
- uint32_t cBufSize = _1K;
-
- PDMAUDIOSTREAMCFG cfg_p =
- {
- 44100, /* Hz */
- 2 /* Channels */,
- AUD_FMT_S16 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
- PDMPCMPROPS props;
-
- int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
- AssertRC(rc);
-
- PDMAUDIOMIXBUF parent;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &props, cBufSize));
-
- PDMAUDIOSTREAMCFG cfg_c1 = /* Upmixing to parent */
- {
- 22100, /* Hz */
- 2 /* Channels */,
- AUD_FMT_S16 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
-
- rc = DrvAudioStreamCfgToProps(&cfg_c1, &props);
- AssertRC(rc);
-
- PDMAUDIOMIXBUF child1;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child1, "Child1", &props, cBufSize));
- RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child1, &parent));
-
- PDMAUDIOSTREAMCFG cfg_c2 = /* Downmixing to parent */
- {
- 48000, /* Hz */
- 2 /* Channels */,
- AUD_FMT_S16 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
-
- rc = DrvAudioStreamCfgToProps(&cfg_c2, &props);
- AssertRC(rc);
-
- PDMAUDIOMIXBUF child2;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child2, "Child2", &props, cBufSize));
- RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child2, &parent));
-
- /*
- * Writing + mixing from child/children -> parent, sequential.
- */
- uint32_t cbBuf = _1K;
- char pvBuf[_1K];
- int16_t samples[32] = { 0xAA, 0xBB };
- uint32_t read , written, mixed, temp;
-
- //unused//uint32_t cChild1Free = cBufSize;
- //unused//uint32_t cChild1Mixed = 0;
- //unused//uint32_t cSamplesParent1 = 16;
- uint32_t cSamplesChild1 = 16;
-
- //unused//uint32_t cChild2Free = cBufSize;
- //unused//uint32_t cChild2Mixed = 0;
- //unused//uint32_t cSamplesParent2 = 16;
- uint32_t cSamplesChild2 = 16;
-
- uint32_t t = RTRandU32() % 64;
-
- for (uint32_t i = 0; i < t; i++)
- {
- RTTestPrintf(hTest, RTTESTLVL_DEBUG, "i=%RU32\n", i);
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child1, 0, &samples, sizeof(samples), &written));
- RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild1, ("Child1: Expected %RU32 written samples, got %RU32\n", cSamplesChild1, written));
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child1, written, &mixed));
- temp = AudioMixBufProcessed(&parent) - AudioMixBufMixed(&child2);
- RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child1) == temp, ("Child1: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child1), temp));
-
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child2, 0, &samples, sizeof(samples), &written));
- RTTESTI_CHECK_MSG_BREAK(written == cSamplesChild2, ("Child2: Expected %RU32 written samples, got %RU32\n", cSamplesChild2, written));
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child2, written, &mixed));
- temp = AudioMixBufProcessed(&parent) - AudioMixBufMixed(&child1);
- RTTESTI_CHECK_MSG_BREAK(AudioMixBufMixed(&child2) == temp, ("Child2: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child2), temp));
- }
-
- RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child1) + AudioMixBufMixed(&child2));
-
- for (;;)
- {
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, pvBuf, cbBuf, &read));
- if (!read)
- break;
- AudioMixBufFinish(&parent, read);
- }
-
- RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
- RTTESTI_CHECK(AudioMixBufMixed(&child1) == 0);
- RTTESTI_CHECK(AudioMixBufMixed(&child2) == 0);
-
- AudioMixBufDestroy(&parent);
- AudioMixBufDestroy(&child1);
- AudioMixBufDestroy(&child2);
-
- return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
-}
-
-/* Test 8-bit sample conversion (8-bit -> internal -> 8-bit). */
-static int tstConversion8(RTTEST hTest)
-{
- unsigned i;
- uint32_t cBufSize = 256;
- PDMPCMPROPS props;
-
-
- RTTestSubF(hTest, "Sample conversion");
-
- PDMAUDIOSTREAMCFG cfg_p =
- {
- 44100, /* Hz */
- 1 /* Channels */,
- AUD_FMT_U8 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
-
- int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
- AssertRC(rc);
-
- PDMAUDIOMIXBUF parent;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &props, cBufSize));
-
- /* Child uses half the sample rate; that ensures the mixing engine can't
- * take shortcuts and performs conversion. Because conversion to double
- * the sample rate effectively inserts one additional sample between every
- * two source samples, N source samples will be converted to N * 2 - 1
- * samples. However, the last source sample will be saved for later
- * interpolation and not immediately output.
- */
- PDMAUDIOSTREAMCFG cfg_c = /* Upmixing to parent */
- {
- 22050, /* Hz */
- 1 /* Channels */,
- AUD_FMT_U8 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
-
- rc = DrvAudioStreamCfgToProps(&cfg_c, &props);
- AssertRC(rc);
-
- PDMAUDIOMIXBUF child;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &props, cBufSize));
- RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
-
- /* 8-bit unsigned samples. Often used with SB16 device. */
- uint8_t samples[16] = { 0xAA, 0xBB, 0, 1, 43, 125, 126, 127,
- 128, 129, 130, 131, 132, UINT8_MAX - 1, UINT8_MAX, 0 };
-
- /*
- * Writing + mixing from child -> parent, sequential.
- */
- uint32_t cbBuf = 256;
- char achBuf[256];
- uint32_t read, written, mixed, temp;
-
- //unused//uint32_t cChildFree = cBufSize;
- //unused//uint32_t cChildMixed = 0;
- uint32_t cSamplesChild = 16;
- uint32_t cSamplesParent = cSamplesChild * 2 - 2;
- uint32_t cSamplesRead = 0;
-
- /**** 8-bit unsigned samples ****/
- RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Conversion test %uHz %uch 8-bit\n", cfg_c.uHz, cfg_c.cChannels);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
- RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
- RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
- temp = AudioMixBufProcessed(&parent);
- RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
-
- RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child));
-
- for (;;)
- {
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
- if (!read)
- break;
- cSamplesRead += read;
- AudioMixBufFinish(&parent, read);
- }
- RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
-
- /* Check that the samples came out unharmed. Every other sample is interpolated and we ignore it. */
- /* NB: This also checks that the default volume setting is 0dB attenuation. */
- uint8_t *pSrc8 = &samples[0];
- uint8_t *pDst8 = (uint8_t *)achBuf;
-
- for (i = 0; i < cSamplesChild - 1; ++i)
- {
- RTTESTI_CHECK_MSG(*pSrc8 == *pDst8, ("index %u: Dst=%d, Src=%d\n", i, *pDst8, *pSrc8));
- pSrc8 += 1;
- pDst8 += 2;
- }
-
- RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
- RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
-
- AudioMixBufDestroy(&parent);
- AudioMixBufDestroy(&child);
-
- return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
-}
-
-/* Test 16-bit sample conversion (16-bit -> internal -> 16-bit). */
-static int tstConversion16(RTTEST hTest)
-{
- unsigned i;
- uint32_t cBufSize = 256;
- PDMPCMPROPS props;
-
-
- RTTestSubF(hTest, "Sample conversion 16-bit");
-
- PDMAUDIOSTREAMCFG cfg_p =
- {
- 44100, /* Hz */
- 1 /* Channels */,
- AUD_FMT_S16 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
-
- int rc = DrvAudioStreamCfgToProps(&cfg_p, &props);
- AssertRC(rc);
-
- PDMAUDIOMIXBUF parent;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &props, cBufSize));
-
- PDMAUDIOSTREAMCFG cfg_c = /* Upmixing to parent */
- {
- 22050, /* Hz */
- 1 /* Channels */,
- AUD_FMT_S16 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
-
- rc = DrvAudioStreamCfgToProps(&cfg_c, &props);
- AssertRC(rc);
-
- PDMAUDIOMIXBUF child;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &props, cBufSize));
- RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
-
- /* 16-bit signed. More or less exclusively used as output, and usually as input, too. */
- int16_t samples[16] = { 0xAA, 0xBB, INT16_MIN, INT16_MIN + 1, INT16_MIN / 2, -3, -2, -1,
- 0, 1, 2, 3, INT16_MAX / 2, INT16_MAX - 1, INT16_MAX, 0 };
-
- /*
- * Writing + mixing from child -> parent, sequential.
- */
- uint32_t cbBuf = 256;
- char achBuf[256];
- uint32_t read, written, mixed, temp;
-
- //unused//uint32_t cChildFree = cBufSize;
- //unused//uint32_t cChildMixed = 0;
- uint32_t cSamplesChild = 16;
- uint32_t cSamplesParent = cSamplesChild * 2 - 2;
- uint32_t cSamplesRead = 0;
-
- /**** 16-bit signed samples ****/
- RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Conversion test %uHz %uch 16-bit\n", cfg_c.uHz, cfg_c.cChannels);
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
- RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
- RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
- temp = AudioMixBufProcessed(&parent);
- RTTESTI_CHECK_MSG(AudioMixBufMixed(&child) == temp, ("Child: Expected %RU32 mixed samples, got %RU32\n", AudioMixBufMixed(&child), temp));
-
- RTTESTI_CHECK(AudioMixBufProcessed(&parent) == AudioMixBufMixed(&child));
-
- for (;;)
- {
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
- if (!read)
- break;
- cSamplesRead += read;
- AudioMixBufFinish(&parent, read);
- }
- RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
-
- /* Check that the samples came out unharmed. Every other sample is interpolated and we ignore it. */
- /* NB: This also checks that the default volume setting is 0dB attenuation. */
- int16_t *pSrc16 = &samples[0];
- int16_t *pDst16 = (int16_t *)achBuf;
-
- for (i = 0; i < cSamplesChild - 1; ++i)
- {
- RTTESTI_CHECK_MSG(*pSrc16 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
- pSrc16 += 1;
- pDst16 += 2;
- }
-
- RTTESTI_CHECK(AudioMixBufProcessed(&parent) == 0);
- RTTESTI_CHECK(AudioMixBufMixed(&child) == 0);
-
- AudioMixBufDestroy(&parent);
- AudioMixBufDestroy(&child);
-
- return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
-}
-
-/* Test volume control. */
-static int tstVolume(RTTEST hTest)
-{
- unsigned i;
- uint32_t cBufSize = 256;
- PDMPCMPROPS props;
-
-
- RTTestSubF(hTest, "Volume control");
-
- /* Same for parent/child. */
- PDMAUDIOSTREAMCFG cfg =
- {
- 44100, /* Hz */
- 2 /* Channels */,
- AUD_FMT_S16 /* Format */,
- PDMAUDIOENDIANNESS_LITTLE /* ENDIANNESS */
- };
-
- int rc = DrvAudioStreamCfgToProps(&cfg, &props);
- AssertRC(rc);
-
- PDMAUDIOVOLUME vol = { false, 0, 0 }; /* Not muted. */
- PDMAUDIOMIXBUF parent;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &props, cBufSize));
-
- PDMAUDIOMIXBUF child;
- RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &props, cBufSize));
- RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
-
- /* A few 16-bit signed samples. */
- int16_t samples[16] = { INT16_MIN, INT16_MIN + 1, -128, -64, -4, -1, 0, 1,
- 2, 255, 256, INT16_MAX / 2, INT16_MAX - 2, INT16_MAX - 1, INT16_MAX, 0 };
-
- /*
- * Writing + mixing from child -> parent.
- */
- uint32_t cbBuf = 256;
- char achBuf[256];
- uint32_t read, written, mixed;
-
- //unused//uint32_t cChildFree = cBufSize;
- //unused//uint32_t cChildMixed = 0;
- uint32_t cSamplesChild = 8;
- uint32_t cSamplesParent = cSamplesChild;
- uint32_t cSamplesRead;
- int16_t *pSrc16;
- int16_t *pDst16;
-
- /**** Volume control test ****/
- RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Volume control test %uHz %uch \n", cfg.uHz, cfg.cChannels);
-
- /* 1) Full volume/0dB attenuation (255). */
- vol.uLeft = vol.uRight = 255;
- AudioMixBufSetVolume(&child, &vol);
-
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
- RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
- RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
-
- cSamplesRead = 0;
- for (;;)
- {
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
- if (!read)
- break;
- cSamplesRead += read;
- AudioMixBufFinish(&parent, read);
- }
- RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
-
- /* Check that at 0dB the samples came out unharmed. */
- pSrc16 = &samples[0];
- pDst16 = (int16_t *)achBuf;
-
- for (i = 0; i < cSamplesParent * 2 /* stereo */; ++i)
- {
- RTTESTI_CHECK_MSG(*pSrc16 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
- ++pSrc16;
- ++pDst16;
- }
- AudioMixBufReset(&child);
-
- /* 2) Half volume/-6dB attenuation (16 steps down). */
- vol.uLeft = vol.uRight = 255 - 16;
- AudioMixBufSetVolume(&child, &vol);
-
- RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&child, 0, &samples, sizeof(samples), &written));
- RTTESTI_CHECK_MSG(written == cSamplesChild, ("Child: Expected %RU32 written samples, got %RU32\n", cSamplesChild, written));
- RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, written, &mixed));
-
- cSamplesRead = 0;
- for (;;)
- {
- RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufReadCirc(&parent, achBuf, cbBuf, &read));
- if (!read)
- break;
- cSamplesRead += read;
- AudioMixBufFinish(&parent, read);
- }
- RTTESTI_CHECK_MSG(cSamplesRead == cSamplesParent, ("Parent: Expected %RU32 mixed samples, got %RU32\n", cSamplesParent, cSamplesRead));
-
- /* Check that at -6dB the sample values are halved. */
- pSrc16 = &samples[0];
- pDst16 = (int16_t *)achBuf;
-
- for (i = 0; i < cSamplesParent * 2 /* stereo */; ++i)
- {
- /* Watch out! For negative values, x >> 1 is not the same as x / 2. */
- RTTESTI_CHECK_MSG(*pSrc16 >> 1 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
- ++pSrc16;
- ++pDst16;
- }
-
- AudioMixBufDestroy(&parent);
- AudioMixBufDestroy(&child);
-
- return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
-}
-
-int main(int argc, char **argv)
-{
- RTR3InitExe(argc, &argv, 0);
-
- /*
- * Initialize IPRT and create the test.
- */
- RTTEST hTest;
- int rc = RTTestInitAndCreate("tstAudioMixBuffer", &hTest);
- if (rc)
- return rc;
- RTTestBanner(hTest);
-
- rc = tstSingle(hTest);
- if (RT_SUCCESS(rc))
- rc = tstParentChild(hTest);
- if (RT_SUCCESS(rc))
- rc = tstConversion8(hTest);
- if (RT_SUCCESS(rc))
- rc = tstConversion16(hTest);
- if (RT_SUCCESS(rc))
- rc = tstVolume(hTest);
-
- /*
- * Summary
- */
- return RTTestSummaryAndDestroy(hTest);
-}
diff --git a/src/VBox/Devices/Bus/DevPCI.cpp b/src/VBox/Devices/Bus/DevPCI.cpp
index f49358d..bd724f3 100644
--- a/src/VBox/Devices/Bus/DevPCI.cpp
+++ b/src/VBox/Devices/Bus/DevPCI.cpp
@@ -997,14 +997,14 @@ static void pci_bios_init_device(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDe
* This does not change anything really as the access to the device is not going
* through the bridge but we want to be compliant to the spec.
*/
- if ((pGlobals->pci_bios_io_addr % 4096) != 0)
- pGlobals->pci_bios_io_addr = RT_ALIGN_32(pGlobals->pci_bios_io_addr, 4*1024);
+ if ((pGlobals->pci_bios_io_addr % _4K) != 0)
+ pGlobals->pci_bios_io_addr = RT_ALIGN_32(pGlobals->pci_bios_io_addr, _4K);
Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->pci_bios_io_addr));
pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->pci_bios_io_addr >> 8) & 0xf0);
/* The MMIO range for the bridge must be aligned to a 1MB boundary. */
- if ((pGlobals->pci_bios_mem_addr % (1024 * 1024)) != 0)
- pGlobals->pci_bios_mem_addr = RT_ALIGN_32(pGlobals->pci_bios_mem_addr, 1024*1024);
+ if ((pGlobals->pci_bios_mem_addr % _1M) != 0)
+ pGlobals->pci_bios_mem_addr = RT_ALIGN_32(pGlobals->pci_bios_mem_addr, _1M);
Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->pci_bios_mem_addr));
pci_config_writew(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->pci_bios_mem_addr >> 16) & UINT32_C(0xffff0));
@@ -1025,18 +1025,18 @@ static void pci_bios_init_device(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDe
* The result with a real bridge is that no I/O transactions are passed to the secondary
* interface. Again this doesn't really matter here but we want to be compliant to the spec.
*/
- if ((u32IoAddressBase != pGlobals->pci_bios_io_addr) && ((pGlobals->pci_bios_io_addr % 4096) != 0))
+ if ((u32IoAddressBase != pGlobals->pci_bios_io_addr) && ((pGlobals->pci_bios_io_addr % _4K) != 0))
{
/* The upper boundary must be one byte less than a 4KB boundary. */
- pGlobals->pci_bios_io_addr = RT_ALIGN_32(pGlobals->pci_bios_io_addr, 4*1024);
+ pGlobals->pci_bios_io_addr = RT_ALIGN_32(pGlobals->pci_bios_io_addr, _4K);
}
pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->pci_bios_io_addr >> 8) & 0xf0) - 1);
/* Same with the MMIO limit register but with 1MB boundary here. */
- if ((u32MMIOAddressBase != pGlobals->pci_bios_mem_addr) && ((pGlobals->pci_bios_mem_addr % (1024 * 1024)) != 0))
+ if ((u32MMIOAddressBase != pGlobals->pci_bios_mem_addr) && ((pGlobals->pci_bios_mem_addr % _1M) != 0))
{
/* The upper boundary must be one byte less than a 1MB boundary. */
- pGlobals->pci_bios_mem_addr = RT_ALIGN_32(pGlobals->pci_bios_mem_addr, 1024*1024);
+ pGlobals->pci_bios_mem_addr = RT_ALIGN_32(pGlobals->pci_bios_mem_addr, _1M);
}
pci_config_writew(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->pci_bios_mem_addr >> 16) & UINT32_C(0xfff0)) - 1);
diff --git a/src/VBox/Devices/Bus/DevPciIch9.cpp b/src/VBox/Devices/Bus/DevPciIch9.cpp
index 6273c3b..11042d6 100644
--- a/src/VBox/Devices/Bus/DevPciIch9.cpp
+++ b/src/VBox/Devices/Bus/DevPciIch9.cpp
@@ -45,6 +45,7 @@
#include <iprt/string.h>
#ifdef IN_RING3
# include <iprt/mem.h>
+# include <iprt/uuid.h>
#endif
#include "PciInline.h"
@@ -194,6 +195,7 @@ static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PPDMDEVINS pDevIns, PPDMPCIDE
static DECLCALLBACK(void) ich9pciConfigWriteDev(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t u32Address, uint32_t val, unsigned len);
DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t uBus);
static void ich9pciBiosInitAllDevicesOnBus(PICH9PCIGLOBALS pGlobals, uint8_t uBus);
+static bool ich9pciBiosInitAllDevicesPrefetchableOnBus(PICH9PCIGLOBALS pGlobals, uint8_t uBus, bool fUse64Bit, bool fDryrun);
#endif
// See 7.2.2. PCI Express Enhanced Configuration Mechanism for details of address
@@ -567,7 +569,8 @@ DECLINLINE(int) ich9pciSlotGetPirq(uint8_t uBus, uint8_t uDevFn, int iIrqNum)
return (iIrqNum + iSlotAddend) & 3;
}
-/* irqs corresponding to PCI irqs A-D, must match pci_irq_list in rombios.c */
+/* irqs corresponding to PCI irqs A-D, must match pci_irq_list in pcibios.inc */
+/** @todo r=klaus inconsistent! ich9 doesn't implement PIRQ yet, so both needs to be addressed and tested thoroughly. */
static const uint8_t aPciIrqs[4] = { 11, 10, 9, 5 };
#endif /* IN_RING3 */
@@ -662,6 +665,8 @@ static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPDM
{
pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
+ /** @todo r=klaus: implement PIRQ handling (if APIC isn't active). Needed for legacy OSes which don't use the APIC stuff. */
+
/* Send interrupt to I/O APIC only now. */
if (fIsAcpiDevice)
/*
@@ -917,7 +922,8 @@ static void ich9pciUpdateMappings(PDMPCIDEV* pDev, bool fP2PBridge)
{
uint64_t uLast, uNew;
- int iCmd = ich9pciGetWord(pDev, VBOX_PCI_COMMAND);
+ /* safe, only needs to go to the config space array */
+ int iCmd = PDMPciDevGetWord(pDev, VBOX_PCI_COMMAND);
for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
{
/* Skip over BAR2..BAR5 for bridges, as they have a different meaning there. */
@@ -939,8 +945,8 @@ static void ich9pciUpdateMappings(PDMPCIDEV* pDev, bool fP2PBridge)
/* port IO region */
if (iCmd & VBOX_PCI_COMMAND_IO)
{
- /* IO access allowed */
- uNew = ich9pciGetDWord(pDev, uConfigReg);
+ /* safe, only needs to go to the config space array */
+ uNew = PDMPciDevGetDWord(pDev, uConfigReg);
uNew &= ~(iRegionSize - 1);
uLast = uNew + iRegionSize - 1;
/* only 64K ioports on PC */
@@ -954,9 +960,13 @@ static void ich9pciUpdateMappings(PDMPCIDEV* pDev, bool fP2PBridge)
/* MMIO region */
if (iCmd & VBOX_PCI_COMMAND_MEMORY)
{
- uNew = ich9pciGetDWord(pDev, uConfigReg);
+ /* safe, only needs to go to the config space array */
+ uNew = PDMPciDevGetDWord(pDev, uConfigReg);
if (f64Bit)
- uNew |= (uint64_t)ich9pciGetDWord(pDev, uConfigReg + 4) << 32;
+ {
+ /* safe, only needs to go to the config space array */
+ uNew |= (uint64_t)PDMPciDevGetDWord(pDev, uConfigReg + 4) << 32;
+ }
/* the ROM slot has a specific enable bit */
if (iRegion == PCI_ROM_SLOT && !(uNew & 1))
@@ -1669,17 +1679,17 @@ static void ich9pciBiosInitBridge(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_
* This does not change anything really as the access to the device is not going
* through the bridge but we want to be compliant to the spec.
*/
- if ((pGlobals->uPciBiosIo % 4096) != 0)
+ if ((pGlobals->uPciBiosIo % _4K) != 0)
{
- pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
+ pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, _4K);
Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosIo));
}
ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->uPciBiosIo >> 8) & 0xf0, 1);
/* The MMIO range for the bridge must be aligned to a 1MB boundary. */
- if ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0)
+ if ((pGlobals->uPciBiosMmio % _1M) != 0)
{
- pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
+ pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, _1M);
Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosMmio));
}
ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xffff0), 2);
@@ -1699,8 +1709,8 @@ static void ich9pciBiosInitBridge(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_
if (u32IoAddressBase != pGlobals->uPciBiosIo)
{
/* Need again alignment to a 4KB boundary. */
- pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
- ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->uPciBiosIo >> 8) & 0xf0) - 1, 1);
+ pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, _4K);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->uPciBiosIo -1) >> 8) & 0xf0, 1);
}
else
{
@@ -1709,10 +1719,10 @@ static void ich9pciBiosInitBridge(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_
}
/* Same with the MMIO limit register but with 1MB boundary here. */
- if ((u32MMIOAddressBase != pGlobals->uPciBiosMmio) && ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0))
+ if (u32MMIOAddressBase != pGlobals->uPciBiosMmio)
{
- pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
- ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xfff0)) - 1, 2);
+ pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, _1M);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->uPciBiosMmio - 1) >> 16) & UINT32_C(0xfff0), 2);
}
else
{
@@ -1726,22 +1736,30 @@ static void ich9pciBiosInitBridge(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_
* the base register than in the limit register.
*/
ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0, 2);
- ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0, 2);
- ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, 0x00, 4);
- ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00, 4);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0000, 2);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, 0x00000000, 4);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00000000, 4);
}
-static void ich9pciBiosInitDeviceBARs(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
+static int ichpciBiosInitDeviceGetRegions(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
{
uint8_t uHeaderType = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_HEADER_TYPE, 1) & 0x7f;
- int cRegions = 0;
if (uHeaderType == 0x00)
/* Ignore ROM region here, which is included in VBOX_PCI_NUM_REGIONS. */
- cRegions = VBOX_PCI_NUM_REGIONS - 1;
+ return PCI_NUM_REGIONS - 1;
else if (uHeaderType == 0x01)
/* PCI bridges have 2 BARs. */
- cRegions = 2;
+ return 2;
+ else
+ {
+ AssertMsgFailed(("invalid header type %#x\n", uHeaderType));
+ return 0;
+ }
+}
+static void ich9pciBiosInitDeviceBARs(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
+{
+ int cRegions = ichpciBiosInitDeviceGetRegions(pGlobals, uBus, uDevFn);
bool fSuppressMem = false;
bool fActiveMemRegion = false;
bool fActiveIORegion = false;
@@ -1779,8 +1797,8 @@ static void ich9pciBiosInitDeviceBARs(PICH9PCIGLOBALS pGlobals, uint8_t uBus, ui
{
ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address+4, UINT32_C(0xffffffff), 4);
- cbRegSize64 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
- cbRegSize64 |= ((uint64_t)ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address+4, 4) << 32);
+ cbRegSize64 = RT_MAKE_U64(ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4),
+ ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address+4, 4));
cbRegSize64 &= ~UINT64_C(0x0f);
cbRegSize64 = (~cbRegSize64) + 1;
@@ -1880,6 +1898,196 @@ static void ich9pciBiosInitDeviceBARs(PICH9PCIGLOBALS pGlobals, uint8_t uBus, ui
ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
}
+static bool ich9pciBiosInitDevicePrefetchableBARs(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, bool fUse64Bit, bool fDryrun)
+{
+ int cRegions = ichpciBiosInitDeviceGetRegions(pGlobals, uBus, uDevFn);
+ bool fActiveMemRegion = false;
+ for (int iRegion = 0; iRegion < cRegions; iRegion++)
+ {
+ uint32_t u32Address = ich9pciGetRegionReg(iRegion);
+ uint8_t u8ResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 1);
+ bool fPrefetch = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_IO)))
+ == PCI_ADDRESS_SPACE_MEM_PREFETCH;
+ bool f64Bit = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
+ == PCI_ADDRESS_SPACE_BAR64;
+ uint64_t cbRegSize64 = 0;
+
+ /* Everything besides prefetchable regions has been set up already. */
+ if (!fPrefetch)
+ continue;
+
+ if (f64Bit)
+ {
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address+4, UINT32_C(0xffffffff), 4);
+ cbRegSize64 = RT_MAKE_U64(ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4),
+ ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address+4, 4));
+ cbRegSize64 &= ~UINT64_C(0x0f);
+ cbRegSize64 = (~cbRegSize64) + 1;
+ }
+ else
+ {
+ uint32_t cbRegSize32;
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
+ cbRegSize32 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
+ cbRegSize32 &= ~UINT32_C(0x0f);
+ cbRegSize32 = (~cbRegSize32) + 1;
+
+ cbRegSize64 = cbRegSize32;
+ }
+ Log2(("%s: Size of region %u for device %d on bus %d is %lld\n", __FUNCTION__, iRegion, uDevFn, uBus, cbRegSize64));
+
+ if (cbRegSize64)
+ {
+ uint64_t uNew;
+ if (!fUse64Bit)
+ {
+ uNew = pGlobals->uPciBiosMmio;
+ /* Align starting address to region size. */
+ uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
+ /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. */
+ if ( !uNew
+ || (uNew <= UINT32_C(0xffffffff) && uNew + cbRegSize64 - 1 >= UINT32_C(0xfec00000))
+ || uNew >= _4G)
+ {
+ Assert(fDryrun);
+ return true;
+ }
+ if (!fDryrun)
+ {
+ LogFunc(("Start address of MMIO region %u is %#x\n", iRegion, uNew));
+ ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, uNew);
+ fActiveMemRegion = true;
+ }
+ pGlobals->uPciBiosMmio = uNew + cbRegSize64;
+ }
+ else
+ {
+ /* Can't handle 32-bit BARs when forcing 64-bit allocs. */
+ if (!f64Bit)
+ {
+ Assert(fDryrun);
+ return true;
+ }
+ uNew = pGlobals->uPciBiosMmio64;
+ /* Align starting address to region size. */
+ uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
+ pGlobals->uPciBiosMmio64 = uNew + cbRegSize64;
+ if (!fDryrun)
+ {
+ LogFunc(("Start address of 64-bit MMIO region %u/%u is %#llx\n", iRegion, iRegion + 1, uNew));
+ ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, uNew);
+ fActiveMemRegion = true;
+ }
+ }
+
+ if (f64Bit)
+ iRegion++; /* skip next region */
+ }
+ }
+
+ if (!fDryrun)
+ {
+ /* Update the command word appropriately. */
+ uint8_t uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 2);
+ if (fActiveMemRegion)
+ uCmd |= VBOX_PCI_COMMAND_MEMORY; /* Enable MMIO access. */
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
+ }
+ else
+ Assert(!fActiveMemRegion);
+
+ return false;
+}
+
+static bool ich9pciBiosInitBridgePrefetchable(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, bool fUse64Bit, bool fDryrun)
+{
+ Log(("BIOS init bridge (prefetch): %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
+
+ pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, _1M);
+ pGlobals->uPciBiosMmio64 = RT_ALIGN_64(pGlobals->uPciBiosMmio64, _1M);
+
+ /* Save values to compare later to. */
+ uint32_t u32MMIOAddressBase = pGlobals->uPciBiosMmio;
+ uint64_t u64MMIOAddressBase = pGlobals->uPciBiosMmio64;
+
+ uint8_t uBridgeBus = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_SECONDARY_BUS, 1);
+
+ /* Init all devices behind the bridge (recursing to further buses). */
+ bool fRes = ich9pciBiosInitAllDevicesPrefetchableOnBus(pGlobals, uBridgeBus, fUse64Bit, fDryrun);
+ if (fDryrun)
+ return fRes;
+ Assert(!fRes);
+
+ /* Set prefetchable MMIO limit register with 1MB boundary. */
+ uint64_t uBase, uLimit;
+ if (fUse64Bit)
+ {
+ if (u64MMIOAddressBase == pGlobals->uPciBiosMmio64)
+ return false;
+ uBase = u64MMIOAddressBase;
+ uLimit = RT_ALIGN_64(pGlobals->uPciBiosMmio64, _1M) - 1;
+ }
+ else
+ {
+ if (u32MMIOAddressBase == pGlobals->uPciBiosMmio)
+ return false;
+ uBase = u32MMIOAddressBase;
+ uLimit = RT_ALIGN_32(pGlobals->uPciBiosMmio, _1M) - 1;
+ }
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, uBase >> 32, 4);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_BASE, (uint32_t)(uBase >> 16) & UINT32_C(0xfff0), 2);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, uLimit >> 32, 4);
+ ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, (uint32_t)(uLimit >> 16) & UINT32_C(0xfff0), 2);
+
+ return false;
+}
+
+static bool ich9pciBiosInitAllDevicesPrefetchableOnBus(PICH9PCIGLOBALS pGlobals, uint8_t uBus, bool fUse64Bit, bool fDryrun)
+{
+ /* First pass: assign resources to all devices. */
+ for (uint32_t uDevFn = 0; uDevFn < 256; uDevFn++)
+ {
+ /* check if device is present */
+ uint16_t uVendor = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_VENDOR_ID, 2);
+ if (uVendor == 0xffff)
+ continue;
+
+ Log(("BIOS init device (prefetch): %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
+
+ /* prefetchable memory mappings */
+ bool fRes = ich9pciBiosInitDevicePrefetchableBARs(pGlobals, uBus, uDevFn, fUse64Bit, fDryrun);
+ if (fRes)
+ {
+ Assert(fDryrun);
+ return fRes;
+ }
+ }
+
+ /* Second pass: handle bridges recursively. */
+ for (uint32_t uDevFn = 0; uDevFn < 256; uDevFn++)
+ {
+ /* check if device is present */
+ uint16_t uVendor = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_VENDOR_ID, 2);
+ if (uVendor == 0xffff)
+ continue;
+
+ /* only handle PCI-to-PCI bridges */
+ uint16_t uDevClass = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_CLASS_DEVICE, 2);
+ if (uDevClass != 0x0604)
+ continue;
+
+ Log(("BIOS init bridge (prefetch): %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
+ bool fRes = ich9pciBiosInitBridgePrefetchable(pGlobals, uBus, uDevFn, fUse64Bit, fDryrun);
+ if (fRes)
+ {
+ Assert(fDryrun);
+ return fRes;
+ }
+ }
+ return false;
+}
+
static void ich9pciBiosInitAllDevicesOnBus(PICH9PCIGLOBALS pGlobals, uint8_t uBus)
{
/* First pass: assign resources to all devices and map the interrupt. */
@@ -1986,6 +2194,44 @@ static void ich9pciBiosInitAllDevicesOnBus(PICH9PCIGLOBALS pGlobals, uint8_t uBu
Log(("BIOS init bridge: %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
ich9pciBiosInitBridge(pGlobals, uBus, uDevFn);
}
+
+ /* Third pass (only for bus 0): set up prefetchable bars recursively. */
+ if (uBus == 0)
+ {
+ for (uint32_t uDevFn = 0; uDevFn < 256; uDevFn++)
+ {
+ /* check if device is present */
+ uint16_t uVendor = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_VENDOR_ID, 2);
+ if (uVendor == 0xffff)
+ continue;
+
+ /* only handle PCI-to-PCI bridges */
+ uint16_t uDevClass = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_CLASS_DEVICE, 2);
+ if (uDevClass != 0x0604)
+ continue;
+
+ Log(("BIOS init prefetchable memory behind bridge: %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
+ /* Save values for the prefetchable dryruns. */
+ uint32_t u32MMIOAddressBase = pGlobals->uPciBiosMmio;
+ uint64_t u64MMIOAddressBase = pGlobals->uPciBiosMmio64;
+
+ bool fProbe = ich9pciBiosInitBridgePrefetchable(pGlobals, uBus, uDevFn, false /* fUse64Bit */, true /* fDryrun */);
+ pGlobals->uPciBiosMmio = u32MMIOAddressBase;
+ pGlobals->uPciBiosMmio64 = u64MMIOAddressBase;
+ if (fProbe)
+ {
+ fProbe = ich9pciBiosInitBridgePrefetchable(pGlobals, uBus, uDevFn, true /* fUse64Bit */, true /* fDryrun */);
+ pGlobals->uPciBiosMmio = u32MMIOAddressBase;
+ pGlobals->uPciBiosMmio64 = u64MMIOAddressBase;
+ if (fProbe)
+ LogRel(("PCI: unresolvable prefetchable memory behind bridge %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
+ else
+ ich9pciBiosInitBridgePrefetchable(pGlobals, uBus, uDevFn, true /* fUse64Bit */, false /* fDryrun */);
+ }
+ else
+ ich9pciBiosInitBridgePrefetchable(pGlobals, uBus, uDevFn, false /* fUse64Bit */, false /* fDryrun */);
+ }
+ }
}
/**
@@ -2021,7 +2267,7 @@ static uint8_t ich9pciInitBridgeTopology(PICH9PCIGLOBALS pGlobals, PICH9PCIBUS p
AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
("Device is not a PCI bridge but on the list of PCI bridges\n"));
PICH9PCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PICH9PCIBUS);
- uint8_t uMaxChildSubBus = ich9pciInitBridgeTopology(pGlobals, pChildBus, pChildBus->iBus);
+ uint8_t uMaxChildSubBus = ich9pciInitBridgeTopology(pGlobals, pChildBus, pBus->iBus);
uMaxSubNum = RT_MAX(uMaxSubNum, uMaxChildSubBus);
}
if (pBus->iBus != 0)
@@ -2055,6 +2301,8 @@ static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
+ /** @todo r=klaus this needs to do the same elcr magic as DevPCI.cpp, as the BIOS can't be trusted to do the right thing. Of course it's more difficult than with the old code, as there are bridges to be handled. The interrupt routing needs to be taken into account. Also I highly suspect that the chipset has 8 interrupt lines which we might be able to use for handling things on the root bus better (by treating them as devices on the mainboard). */
+
/*
* Set the start addresses.
*/
@@ -2093,7 +2341,7 @@ static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t u32Address, unsigned len)
{
NOREF(pDevIns);
- if ((u32Address + len) > 256 && (u32Address + len) < 4096)
+ if ((u32Address + len) > 256 && (u32Address + len) < _4K)
{
LogRel(("PCI: %8s/%u: Read from extended register %d fallen back to generic code\n",
pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, u32Address));
@@ -2197,7 +2445,7 @@ static DECLCALLBACK(void) ich9pciConfigWriteDev(PPDMDEVINS pDevIns, PPDMPCIDEV p
NOREF(pDevIns);
Assert(len <= 4);
- if ((u32Address + len) > 256 && (u32Address + len) < 4096)
+ if ((u32Address + len) > 256 && (u32Address + len) < _4K)
{
LogRel(("PCI: %8s/%u: Write to extended register %d fallen back to generic code\n",
pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, u32Address));
@@ -2340,6 +2588,22 @@ static DECLCALLBACK(void) ich9pciConfigWriteDev(PPDMDEVINS pDevIns, PPDMPCIDEV p
fUpdateMappings = true;
break;
}
+ else if ( addr == VBOX_PCI_IO_BASE
+ || addr == VBOX_PCI_IO_LIMIT
+ || addr == VBOX_PCI_MEMORY_BASE
+ || addr == VBOX_PCI_MEMORY_LIMIT
+ || addr == VBOX_PCI_PREF_MEMORY_BASE
+ || addr == VBOX_PCI_PREF_MEMORY_LIMIT)
+ {
+ /* All bridge address decoders have the low 4 bits
+ * as readonly, and all but the prefetchable ones
+ * have the low 4 bits as 0 (the prefetchable have
+ * it as 1 to show the 64-bit decoder support. */
+ u8Val &= 0xf0;
+ if ( addr == VBOX_PCI_PREF_MEMORY_BASE
+ || addr == VBOX_PCI_PREF_MEMORY_LIMIT)
+ u8Val |= 0x01;
+ }
/* fall thru (bridge config space which isn't a BAR) */
}
default:
@@ -2404,10 +2668,10 @@ static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bo
printIndent(pHlp, iIndent + 2);
if (pciDevIsMsiCapable(pPciDev))
- pHlp->pfnPrintf(pHlp, "MSI:%s ", MsiIsEnabled(pPciDev) ? "on" : "off");
+ pHlp->pfnPrintf(pHlp, "MSI: %s ", MsiIsEnabled(pPciDev) ? "on" : "off");
if (pciDevIsMsixCapable(pPciDev))
- pHlp->pfnPrintf(pHlp, "MSI-X:%s ", MsixIsEnabled(pPciDev) ? "on" : "off");
+ pHlp->pfnPrintf(pHlp, "MSI-X: %s ", MsixIsEnabled(pPciDev) ? "on" : "off");
pHlp->pfnPrintf(pHlp, "\n");
}
@@ -2498,7 +2762,8 @@ static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bo
uint8_t uSecondary = ich9pciGetByte(&pBusSub->aPciDev, VBOX_PCI_SECONDARY_BUS);
uint8_t uSubordinate = ich9pciGetByte(&pBusSub->aPciDev, VBOX_PCI_SUBORDINATE_BUS);
printIndent(pHlp, iIndent);
- pHlp->pfnPrintf(pHlp, "bridge topology: primary=%d secondary=%d subordinate=%d\n",
+ pHlp->pfnPrintf(pHlp, "%02x:%02x.%d: bridge topology: primary=%d secondary=%d subordinate=%d\n",
+ uPrimary, pBusSub->aPciDev.uDevFn >> 3, pBusSub->aPciDev.uDevFn & 7,
uPrimary, uSecondary, uSubordinate);
if ( uPrimary != PDMPciDevGetByte(&pBusSub->aPciDev, VBOX_PCI_PRIMARY_BUS)
|| uSecondary != PDMPciDevGetByte(&pBusSub->aPciDev, VBOX_PCI_SECONDARY_BUS)
@@ -2511,20 +2776,44 @@ static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bo
PDMPciDevGetByte(&pBusSub->aPciDev, VBOX_PCI_SUBORDINATE_BUS));
}
printIndent(pHlp, iIndent);
- pHlp->pfnPrintf(pHlp, "behind bridge: I/O %#06x..%#06x\n",
- (ich9pciGetByte(&pBusSub->aPciDev, VBOX_PCI_IO_BASE) & 0xf0) << 8,
- (ich9pciGetByte(&pBusSub->aPciDev, VBOX_PCI_IO_LIMIT) & 0xf0) << 8 | 0xfff);
+ pHlp->pfnPrintf(pHlp, "behind bridge: ");
+ uint8_t uIoBase = ich9pciGetByte(&pBusSub->aPciDev, VBOX_PCI_IO_BASE);
+ uint8_t uIoLimit = ich9pciGetByte(&pBusSub->aPciDev, VBOX_PCI_IO_LIMIT);
+ pHlp->pfnPrintf(pHlp, "I/O %#06x..%#06x",
+ (uIoBase & 0xf0) << 8,
+ (uIoLimit & 0xf0) << 8 | 0xfff);
+ if (uIoBase > uIoLimit)
+ pHlp->pfnPrintf(pHlp, " (IGNORED)");
+ pHlp->pfnPrintf(pHlp, "\n");
printIndent(pHlp, iIndent);
- pHlp->pfnPrintf(pHlp, "behind bridge: memory %#010x..%#010x\n",
- (ich9pciGetWord(&pBusSub->aPciDev, VBOX_PCI_MEMORY_BASE) & 0xfff0) << 16,
- (ich9pciGetWord(&pBusSub->aPciDev, VBOX_PCI_MEMORY_LIMIT) & 0xfff0) << 16 | 0xfffff);
+ pHlp->pfnPrintf(pHlp, "behind bridge: ");
+ uint32_t uMemoryBase = ich9pciGetWord(&pBusSub->aPciDev, VBOX_PCI_MEMORY_BASE);
+ uint32_t uMemoryLimit = ich9pciGetWord(&pBusSub->aPciDev, VBOX_PCI_MEMORY_LIMIT);
+ pHlp->pfnPrintf(pHlp, "memory %#010x..%#010x",
+ (uMemoryBase & 0xfff0) << 16,
+ (uMemoryLimit & 0xfff0) << 16 | 0xfffff);
+ if (uMemoryBase > uMemoryLimit)
+ pHlp->pfnPrintf(pHlp, " (IGNORED)");
+ pHlp->pfnPrintf(pHlp, "\n");
printIndent(pHlp, iIndent);
- pHlp->pfnPrintf(pHlp, "behind bridge: prefetch memory %#010x..%#010x\n",
- ( ((uint64_t)ich9pciGetDWord(&pBusSub->aPciDev, VBOX_PCI_PREF_BASE_UPPER32) << 32)
- | (ich9pciGetWord(&pBusSub->aPciDev, VBOX_PCI_MEMORY_BASE) & 0xfff0) << 16),
- ( ((uint64_t)ich9pciGetDWord(&pBusSub->aPciDev, VBOX_PCI_PREF_LIMIT_UPPER32) << 32)
- | (ich9pciGetWord(&pBusSub->aPciDev, VBOX_PCI_MEMORY_LIMIT) & 0xfff0) << 16)
- | 0xfffff);
+ pHlp->pfnPrintf(pHlp, "behind bridge: ");
+ uint32_t uPrefMemoryRegBase = ich9pciGetWord(&pBusSub->aPciDev, VBOX_PCI_PREF_MEMORY_BASE);
+ uint32_t uPrefMemoryRegLimit = ich9pciGetWord(&pBusSub->aPciDev, VBOX_PCI_PREF_MEMORY_LIMIT);
+ uint64_t uPrefMemoryBase = (uPrefMemoryRegBase & 0xfff0) << 16;
+ uint64_t uPrefMemoryLimit = (uPrefMemoryRegLimit & 0xfff0) << 16 | 0xfffff;
+ if ( (uPrefMemoryRegBase & 0xf) == 1
+ && (uPrefMemoryRegLimit & 0xf) == 1)
+ {
+ uPrefMemoryBase |= (uint64_t)ich9pciGetDWord(&pBusSub->aPciDev, VBOX_PCI_PREF_BASE_UPPER32) << 32;
+ uPrefMemoryLimit |= (uint64_t)ich9pciGetDWord(&pBusSub->aPciDev, VBOX_PCI_PREF_LIMIT_UPPER32) << 32;
+ pHlp->pfnPrintf(pHlp, "64-bit ");
+ }
+ else
+ pHlp->pfnPrintf(pHlp, "32-bit ");
+ pHlp->pfnPrintf(pHlp, "prefetch memory %#018llx..%#018llx", uPrefMemoryBase, uPrefMemoryLimit);
+ if (uPrefMemoryBase > uPrefMemoryLimit)
+ pHlp->pfnPrintf(pHlp, " (IGNORED)");
+ pHlp->pfnPrintf(pHlp, "\n");
ich9pciBusInfo(pBusSub, pHlp, iIndent + 1, fRegisters);
}
}
@@ -2541,18 +2830,12 @@ static DECLCALLBACK(void) ich9pciInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, co
{
PICH9PCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
- if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
- {
- ich9pciBusInfo(pBus, pHlp, 0, false);
- }
+ if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic"))
+ ich9pciBusInfo(pBus, pHlp, 0, false /*fRegisters*/);
else if (!strcmp(pszArgs, "verbose"))
- {
- ich9pciBusInfo(pBus, pHlp, 0, true);
- }
+ ich9pciBusInfo(pBus, pHlp, 0, true /*fRegisters*/);
else
- {
pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
- }
}
@@ -2655,7 +2938,7 @@ static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns, int iInstance, PCF
*/
/** @todo Disabled for now because this causes error messages with Linux guests.
* The guest loads the x38_edac device which tries to map a memory region
- * using an address given at place 0x48 - 0x4f in the PCi config space.
+ * using an address given at place 0x48 - 0x4f in the PCI config space.
* This fails. because we don't register such a region.
*/
#if 0
@@ -2845,6 +3128,20 @@ static DECLCALLBACK(void) ich9pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelt
}
/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) ich9pcibridgeQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+ PPDMDEVINS pDevIns = RT_FROM_MEMBER(pInterface, PDMDEVINS, IBase);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevIns->IBase);
+ /* Special access to the PDMPCIDEV structure of a ich9pcibridge instance. */
+ PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIICH9BRIDGEPDMPCIDEV, &pBus->aPciDev);
+ return NULL;
+}
+
+
+/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
@@ -2856,7 +3153,7 @@ static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
/*
* Validate and read configuration.
*/
- if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
+ if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0" "ExpressEnabled\0"))
return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
/* check if RC code is enabled. */
@@ -2874,6 +3171,15 @@ static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
+ /* check if we're supposed to implement a PCIe bridge. */
+ bool fExpress;
+ rc = CFGMR3QueryBoolDef(pCfg, "ExpressEnabled", &fExpress, false);
+ if (RT_FAILURE(rc))
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("Configuration error: Failed to query boolean value \"ExpressEnabled\""));
+
+ pDevIns->IBase.pfnQueryInterface = ich9pcibridgeQueryInterface;
+
/*
* Init data and register the PCI bus.
*/
@@ -2881,6 +3187,8 @@ static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
pBus->pDevInsR3 = pDevIns;
pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
+ /** @todo r=klaus figure out how to extend this to allow PCIe config space
+ * extension, which increases the config space frorm 256 bytes to 4K. */
pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->apDevices));
PDMPCIBUSREG PciBusReg;
@@ -2913,14 +3221,74 @@ static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
* Fill in PCI configs and add them to the bus.
*/
PDMPciDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
- PDMPciDevSetDeviceId( &pBus->aPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
- PDMPciDevSetRevisionId(&pBus->aPciDev, 0xf2);
+ if (fExpress)
+ {
+ PDMPciDevSetDeviceId(&pBus->aPciDev, 0x29e1); /* 82X38/X48 Express Host-Primary PCI Express Bridge. */
+ PDMPciDevSetRevisionId(&pBus->aPciDev, 0x01);
+ }
+ else
+ {
+ PDMPciDevSetDeviceId( &pBus->aPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
+ PDMPciDevSetRevisionId(&pBus->aPciDev, 0xf2);
+ }
PDMPciDevSetClassSub( &pBus->aPciDev, 0x04); /* pci2pci */
PDMPciDevSetClassBase( &pBus->aPciDev, 0x06); /* PCI_bridge */
- PDMPciDevSetClassProg( &pBus->aPciDev, 0x01); /* Supports subtractive decoding. */
+ if (fExpress)
+ PDMPciDevSetClassProg(&pBus->aPciDev, 0x00); /* Normal decoding. */
+ else
+ PDMPciDevSetClassProg( &pBus->aPciDev, 0x01); /* Supports subtractive decoding. */
PDMPciDevSetHeaderType(&pBus->aPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
- PDMPciDevSetCommand( &pBus->aPciDev, 0x00);
- PDMPciDevSetStatus( &pBus->aPciDev, 0x20); /* 66MHz Capable. */
+ if (fExpress)
+ {
+ PDMPciDevSetCommand(&pBus->aPciDev, VBOX_PCI_COMMAND_SERR);
+ PDMPciDevSetStatus(&pBus->aPciDev, VBOX_PCI_STATUS_CAP_LIST); /* Has capabilities. */
+ PDMPciDevSetByte(&pBus->aPciDev, VBOX_PCI_CACHE_LINE_SIZE, 8); /* 32 bytes */
+ /* PCI Express */
+ PDMPciDevSetByte(&pBus->aPciDev, 0xa0 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
+ PDMPciDevSetByte(&pBus->aPciDev, 0xa0 + 1, 0); /* next */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 2,
+ /* version */ 0x2
+ | /* Root Complex Integrated Endpoint */ (VBOX_PCI_EXP_TYPE_ROOT_INT_EP << 4));
+ PDMPciDevSetDWord(&pBus->aPciDev, 0xa0 + 4, VBOX_PCI_EXP_DEVCAP_RBE); /* Device capabilities. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 8, 0x0000); /* Device control. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 10, 0x0000); /* Device status. */
+ PDMPciDevSetDWord(&pBus->aPciDev, 0xa0 + 12,
+ /* Max Link Speed */ 2
+ | /* Maximum Link Width */ (16 << 4)
+ | /* Active State Power Management (ASPM) Sopport */ (0 << 10)
+ | VBOX_PCI_EXP_LNKCAP_LBNC
+ | /* Port Number */ ((2 + iInstance) << 24)); /* Link capabilities. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 16, VBOX_PCI_EXP_LNKCTL_CLOCK); /* Link control. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 18,
+ /* Current Link Speed */ 2
+ | /* Negotiated Link Width */ (16 << 4)
+ | VBOX_PCI_EXP_LNKSTA_SL_CLK); /* Link status. */
+ PDMPciDevSetDWord(&pBus->aPciDev, 0xa0 + 20,
+ /* Slot Power Limit Value */ (75 << 7)
+ | /* Physical Slot Number */ (0 << 19)); /* Slot capabilities. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 24, 0x0000); /* Slot control. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 26, 0x0000); /* Slot status. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 28, 0x0000); /* Root control. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 30, 0x0000); /* Root capabilities. */
+ PDMPciDevSetDWord(&pBus->aPciDev, 0xa0 + 32, 0x00000000); /* Root status. */
+ PDMPciDevSetDWord(&pBus->aPciDev, 0xa0 + 36, 0x00000000); /* Device capabilities 2. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 40, 0x0000); /* Device control 2. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 42, 0x0000); /* Device status 2. */
+ PDMPciDevSetDWord(&pBus->aPciDev, 0xa0 + 44,
+ /* Supported Link Speeds Vector */ (2 << 1)); /* Link capabilities 2. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 48,
+ /* Target Link Speed */ 2); /* Link control 2. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 50, 0x0000); /* Link status 2. */
+ PDMPciDevSetDWord(&pBus->aPciDev, 0xa0 + 52, 0x00000000); /* Slot capabilities 2. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 56, 0x0000); /* Slot control 2. */
+ PDMPciDevSetWord(&pBus->aPciDev, 0xa0 + 58, 0x0000); /* Slot status 2. */
+ PDMPciDevSetCapabilityList(&pBus->aPciDev, 0xa0);
+ }
+ else
+ {
+ PDMPciDevSetCommand(&pBus->aPciDev, 0x00);
+ PDMPciDevSetStatus(&pBus->aPciDev, 0x20); /* 66MHz Capable. */
+ }
PDMPciDevSetInterruptLine(&pBus->aPciDev, 0x00); /* This device does not assert interrupts. */
/*
@@ -2929,6 +3297,12 @@ static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
*/
PDMPciDevSetInterruptPin (&pBus->aPciDev, 0x00);
+ if (fExpress)
+ {
+ /** @todo r=klaus set up the PCIe config space beyond the old 256 byte
+ * limit, containing additional capability descriptors. */
+ }
+
/*
* Register this PCI bridge. The called function will take care on which bus we will get registered.
*/
diff --git a/src/VBox/Devices/EFI/DevEFI.cpp b/src/VBox/Devices/EFI/DevEFI.cpp
index 996b73f..d0f3eec 100644
--- a/src/VBox/Devices/EFI/DevEFI.cpp
+++ b/src/VBox/Devices/EFI/DevEFI.cpp
@@ -190,14 +190,6 @@ typedef struct DEVEFI
/** Number of virtual CPUs. (Config) */
uint32_t cCpus;
- /** RAM below 4GB (in bytes). (Config) */
- uint32_t cbBelow4GB;
- /** RAM above 4GB (in bytes). (Config) */
- uint64_t cbAbove4GB;
- /** The total amount of memory. */
- uint64_t cbRam;
- /** The size of the RAM hole below 4GB. */
- uint64_t cbRamHole;
/** The size of the DMI tables. */
uint16_t cbDmiTables;
@@ -1743,23 +1735,28 @@ static DECLCALLBACK(int) efiInitComplete(PPDMDEVINS pDevIns)
{
PDEVEFI pThis = PDMINS_2_DATA(pDevIns, PDEVEFI);
+ PVM pVM = PDMDevHlpGetVM(pDevIns);
+ uint64_t const cbRamSize = MMR3PhysGetRamSize(pVM);
+ uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
+ uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
+ NOREF(cbAbove4GB);
+
/*
* Memory sizes.
*/
- uint64_t const offRamHole = _4G - pThis->cbRamHole;
uint32_t u32Low = 0;
uint32_t u32Chunks = 0;
- if (pThis->cbRam > 16 * _1M)
+ if (cbRamSize > 16 * _1M)
{
- u32Low = (uint32_t)RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000));
+ u32Low = RT_MIN(cbBelow4GB, UINT32_C(0xffe00000));
u32Chunks = (u32Low - 16U * _1M) / _64K;
}
cmosWrite(pDevIns, 0x34, RT_BYTE1(u32Chunks));
cmosWrite(pDevIns, 0x35, RT_BYTE2(u32Chunks));
- if (u32Low < pThis->cbRam)
+ if (u32Low < cbRamSize)
{
- uint64_t u64 = pThis->cbRam - u32Low;
+ uint64_t u64 = cbRamSize - u32Low;
u32Chunks = (uint32_t)(u64 / _64K);
cmosWrite(pDevIns, 0x5b, RT_BYTE1(u32Chunks));
cmosWrite(pDevIns, 0x5c, RT_BYTE2(u32Chunks));
@@ -2141,8 +2138,6 @@ static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
*/
if (!CFGMR3AreValuesValid(pCfg,
"EfiRom\0"
- "RamSize\0"
- "RamHoleSize\0"
"NumCPUs\0"
"UUID\0"
"IOAPIC\0"
@@ -2222,16 +2217,6 @@ static DECLCALLBACK(int) efiConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMN
memcpy(&pThis->aUuid, &uuid, sizeof pThis->aUuid);
/*
- * RAM sizes
- */
- rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
- AssertLogRelRCReturn(rc, rc);
- rc = CFGMR3QueryU64(pCfg, "RamHoleSize", &pThis->cbRamHole);
- AssertLogRelRCReturn(rc, rc);
- pThis->cbBelow4GB = RT_MIN(pThis->cbRam, _4G - pThis->cbRamHole);
- pThis->cbAbove4GB = pThis->cbRam - pThis->cbBelow4GB;
-
- /*
* Get the system EFI ROM file name.
*/
rc = CFGMR3QueryStringAlloc(pCfg, "EfiRom", &pThis->pszEfiRomFile);
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd
index d5b9dad..4c48f16 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI32.fd differ
diff --git a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd
index 661492e..6761f5f 100644
Binary files a/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd and b/src/VBox/Devices/EFI/FirmwareBin/VBoxEFI64.fd differ
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
index bccf268..d5909a4 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.asm
@@ -7293,7 +7293,7 @@ vesa_pm_end: ; 0xc4514 LB 0x1
section _DATA progbits vstart=0x4600 align=1 ; size=0x371f class=DATA group=DGROUP
_msg_vga_init: ; 0xc4600 LB 0x2f
- db 'Oracle VM VirtualBox Version 5.1.14 VGA BIOS', 00dh, 00ah, 000h
+ db 'Oracle VM VirtualBox Version 5.1.16 VGA BIOS', 00dh, 00ah, 000h
_vga_modes: ; 0xc462f LB 0x80
db 000h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 001h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
db 002h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 003h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
@@ -8188,7 +8188,7 @@ _vbebios_vendor_name: ; 0xc7c73 LB 0x13
_vbebios_product_name: ; 0xc7c86 LB 0x21
db 'Oracle VM VirtualBox VBE Adapter', 000h
_vbebios_product_revision: ; 0xc7ca7 LB 0x24
- db 'Oracle VM VirtualBox Version 5.1.14', 000h
+ db 'Oracle VM VirtualBox Version 5.1.16', 000h
_vbebios_info_string: ; 0xc7ccb LB 0x2b
db 'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
_no_vbebios_info_string: ; 0xc7cf6 LB 0x29
@@ -8247,4 +8247,4 @@ section CONST2 progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
- db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0c0h
+ db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0bch
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
index 3a7818a..61c3082 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative286.md5sum
@@ -1 +1 @@
-66a87d595db40d8be27d3858c116ecfa *VBoxVgaBios286.rom
+cb5fd4c3a5a780d2448db9f4fe7e5300 *VBoxVgaBios286.rom
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
index 88efd62..af03e64 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.asm
@@ -6769,7 +6769,7 @@ vesa_pm_end: ; 0xc4514 LB 0x1
section _DATA progbits vstart=0x4600 align=1 ; size=0x371f class=DATA group=DGROUP
_msg_vga_init: ; 0xc4600 LB 0x2f
- db 'Oracle VM VirtualBox Version 5.1.14 VGA BIOS', 00dh, 00ah, 000h
+ db 'Oracle VM VirtualBox Version 5.1.16 VGA BIOS', 00dh, 00ah, 000h
_vga_modes: ; 0xc462f LB 0x80
db 000h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 001h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
db 002h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 003h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
@@ -7664,7 +7664,7 @@ _vbebios_vendor_name: ; 0xc7c73 LB 0x13
_vbebios_product_name: ; 0xc7c86 LB 0x21
db 'Oracle VM VirtualBox VBE Adapter', 000h
_vbebios_product_revision: ; 0xc7ca7 LB 0x24
- db 'Oracle VM VirtualBox Version 5.1.14', 000h
+ db 'Oracle VM VirtualBox Version 5.1.16', 000h
_vbebios_info_string: ; 0xc7ccb LB 0x2b
db 'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
_no_vbebios_info_string: ; 0xc7cf6 LB 0x29
@@ -7723,4 +7723,4 @@ section CONST2 progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
- db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0b5h
+ db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 0b1h
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
index 2bf5306..17e17a1 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative386.md5sum
@@ -1 +1 @@
-309c3495246bb19390b897316241c49f *VBoxVgaBios386.rom
+f6f800a57b52a323c27ef04dcfdb7468 *VBoxVgaBios386.rom
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
index 15d836b..8ba6508 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.asm
@@ -7434,7 +7434,7 @@ vesa_pm_end: ; 0xc4514 LB 0x1
section _DATA progbits vstart=0x4600 align=1 ; size=0x371f class=DATA group=DGROUP
_msg_vga_init: ; 0xc4600 LB 0x2f
- db 'Oracle VM VirtualBox Version 5.1.14 VGA BIOS', 00dh, 00ah, 000h
+ db 'Oracle VM VirtualBox Version 5.1.16 VGA BIOS', 00dh, 00ah, 000h
_vga_modes: ; 0xc462f LB 0x80
db 000h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 001h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
db 002h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h, 003h, 000h, 000h, 004h, 000h, 0b8h, 0ffh, 002h
@@ -8329,7 +8329,7 @@ _vbebios_vendor_name: ; 0xc7c73 LB 0x13
_vbebios_product_name: ; 0xc7c86 LB 0x21
db 'Oracle VM VirtualBox VBE Adapter', 000h
_vbebios_product_revision: ; 0xc7ca7 LB 0x24
- db 'Oracle VM VirtualBox Version 5.1.14', 000h
+ db 'Oracle VM VirtualBox Version 5.1.16', 000h
_vbebios_info_string: ; 0xc7ccb LB 0x2b
db 'VirtualBox VBE Display Adapter enabled', 00dh, 00ah, 00dh, 00ah, 000h
_no_vbebios_info_string: ; 0xc7cf6 LB 0x29
@@ -8388,4 +8388,4 @@ section CONST2 progbits vstart=0x7d20 align=1 ; size=0x0 class=DATA group=DGROUP
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
- db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 047h
+ db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 043h
diff --git a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
index bdcba9e..0d678c2 100644
--- a/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
+++ b/src/VBox/Devices/Graphics/BIOS/VBoxVgaBiosAlternative8086.md5sum
@@ -1 +1 @@
-95f66ba7097d50ee351fb0f22651d793 *VBoxVgaBios8086.rom
+13123527ba806b6216dcbd3b4b435c1e *VBoxVgaBios8086.rom
diff --git a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
index f1945d1..8653df8 100644
--- a/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
+++ b/src/VBox/Devices/Graphics/DevVGA_VBVA.cpp
@@ -2123,7 +2123,7 @@ static int vbvaHandleQueryConf32(PVGASTATE pVGAState, VBVACONF32 *pConf32)
else if (u32Index == VBOX_VBVA_CONF32_HOST_HEAP_SIZE)
{
/** @todo a value calculated from the vram size */
- pConf32->u32Value = 64*_1K;
+ pConf32->u32Value = _64K;
}
else if ( u32Index == VBOX_VBVA_CONF32_MODE_HINT_REPORTING
|| u32Index == VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING)
diff --git a/src/VBox/Devices/Makefile.kmk b/src/VBox/Devices/Makefile.kmk
index c89b433..05b6164 100644
--- a/src/VBox/Devices/Makefile.kmk
+++ b/src/VBox/Devices/Makefile.kmk
@@ -25,7 +25,7 @@ endif
# Include sub-makefiles.
include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
-include $(PATH_SUB_CURRENT)/$(VBOX_AUDIO_PATH_SOURCES)/testcase/Makefile.kmk
+include $(PATH_SUB_CURRENT)/Audio/testcase/Makefile.kmk
include $(PATH_SUB_CURRENT)/Input/testcase/Makefile.kmk
ifdef VBOX_WITH_TESTCASES
include $(PATH_SUB_CURRENT)/Samples/Makefile.kmk
@@ -380,7 +380,7 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
$(PATH_ROOT)/src/VBox/ExtPacks/Puel/UsbWebcam/DrvHostWebcam/DrvHostWebcam.cpp \
$(PATH_ROOT)/src/VBox/ExtPacks/Puel/UsbWebcam/DrvHostWebcam/JPEGEnc.cpp
$(PATH_ROOT)/src/VBox/ExtPacks/Puel/UsbWebcam/DrvHostWebcam/JPEGEnc.cpp_INCS = \
- $(PATH_ROOT)/src/libs/jpeg-8a
+ $(VBOX_JPEG_INCS)
VBoxDD_SOURCES.linux += \
$(PATH_ROOT)/src/VBox/ExtPacks/Puel/UsbWebcam/DrvHostWebcam/HostWebcam-v4l2.cpp
VBoxDD_LIBS += \
@@ -532,61 +532,54 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
# --- Audio bits. ---
- if 0 # Not stable yet.
- VBoxDD_DEFS += VBOX_WITH_HDA_INTERLEAVING_STREAMS_SUPPORT
- VBoxDD_DEFS += VBOX_WITH_HDA_51_SURROUND
- endif
-
# Enable Audio Queues implementation for macOS hosts (Core Audio backend).
VBoxDD_DEFS.darwin += VBOX_WITH_AUDIO_CA_QUEUES
- VBoxDD_DEFS += $(if-expr defined(VBOX_WITH_AUDIO_50),VBOX_WITH_AUDIO_50,)
-
VBoxDD_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DevIchAc97.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/DevSB16.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/DevHDA.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/HDACodec.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/AudioMixBuffer.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/AudioMixer.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvAudio.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvAudioCommon.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvHostNullAudio.cpp
+ Audio/DevIchAc97.cpp \
+ Audio/DevSB16.cpp \
+ Audio/DevHDA.cpp \
+ Audio/HDACodec.cpp \
+ Audio/AudioMixBuffer.cpp \
+ Audio/AudioMixer.cpp \
+ Audio/DrvAudio.cpp \
+ Audio/DrvAudioCommon.cpp \
+ Audio/DrvHostNullAudio.cpp
ifdef VBOX_WITH_AUDIO_DEBUG
VBoxDD_DEFS += VBOX_WITH_AUDIO_DEBUG
VBoxDD_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvHostDebugAudio.cpp
+ Audio/DrvHostDebugAudio.cpp
endif
ifeq ($(KBUILD_TARGET),darwin)
VBoxDD_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvHostCoreAudio.cpp
+ Audio/DrvHostCoreAudio.cpp
endif
ifeq ($(KBUILD_TARGET),win)
VBoxDD_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvHostDSound.cpp
+ Audio/DrvHostDSound.cpp
endif
ifdef VBOX_WITH_AUDIO_OSS
VBoxDD_DEFS += VBOX_WITH_AUDIO_OSS
VBoxDD_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvHostOSSAudio.cpp
+ Audio/DrvHostOSSAudio.cpp
endif
ifdef VBOX_WITH_AUDIO_ALSA
VBoxDD_DEFS += VBOX_WITH_AUDIO_ALSA
VBoxDD_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvHostALSAAudio.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/alsa_stubs.c
+ Audio/DrvHostALSAAudio.cpp \
+ Audio/alsa_stubs.c
endif
ifdef VBOX_WITH_AUDIO_PULSE
VBoxDD_DEFS += VBOX_WITH_AUDIO_PULSE
VBoxDD_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DrvHostPulseAudio.cpp \
- $(VBOX_AUDIO_PATH_SOURCES)/pulse_stubs.c
+ Audio/DrvHostPulseAudio.cpp \
+ Audio/pulse_stubs.c
endif
# --- WARNING! SLIRP MESS AHEAD! ;-) ---
@@ -883,9 +876,8 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Parallel/DevParallel.cpp \
VMMDev/VMMDevTesting.cpp
- VBoxDDRC_DEFS += $(if-expr defined(VBOX_WITH_AUDIO_50),VBOX_WITH_AUDIO_50,)
VBoxDDRC_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DevHDA.cpp
+ Audio/DevHDA.cpp
ifdef VBOX_WITH_E1000
VBoxDDRC_DEFS += VBOX_WITH_E1000
@@ -1051,9 +1043,8 @@ if !defined(VBOX_ONLY_EXTPACKS) # Goes on almost to the end of the file.
Network/DrvIntNet.cpp \
Network/DrvDedicatedNic.cpp
- VBoxDDR0_DEFS += $(if-expr defined(VBOX_WITH_AUDIO_50),VBOX_WITH_AUDIO_50,)
VBoxDDR0_SOURCES += \
- $(VBOX_AUDIO_PATH_SOURCES)/DevHDA.cpp
+ Audio/DevHDA.cpp
VBoxDDR0_SOURCES.win += Parallel/DrvHostParallel.cpp
diff --git a/src/VBox/Devices/Network/DrvNAT.cpp b/src/VBox/Devices/Network/DrvNAT.cpp
index 340a269..0ae7948 100644
--- a/src/VBox/Devices/Network/DrvNAT.cpp
+++ b/src/VBox/Devices/Network/DrvNAT.cpp
@@ -1478,6 +1478,9 @@ static DECLCALLBACK(void) drvNATDestruct(PPDMDRVINS pDrvIns)
RTReqQueueDestroy(pThis->hUrgRecvReqQueue);
pThis->hUrgRecvReqQueue = NIL_RTREQQUEUE;
+ RTReqQueueDestroy(pThis->hRecvReqQueue);
+ pThis->hRecvReqQueue = NIL_RTREQQUEUE;
+
RTSemEventDestroy(pThis->EventRecv);
pThis->EventRecv = NIL_RTSEMEVENT;
@@ -1490,6 +1493,11 @@ static DECLCALLBACK(void) drvNATDestruct(PPDMDRVINS pDrvIns)
if (RTCritSectIsInitialized(&pThis->XmitLock))
RTCritSectDelete(&pThis->XmitLock);
+#ifndef RT_OS_WINDOWS
+ RTPipeClose(pThis->hPipeRead);
+ RTPipeClose(pThis->hPipeWrite);
+#endif
+
#ifdef RT_OS_DARWIN
/* Cleanup the DNS watcher. */
CFRunLoopRef hRunLoopMain = CFRunLoopGetMain();
@@ -1711,14 +1719,11 @@ static DECLCALLBACK(int) drvNATConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uin
rc = RTSemEventCreate(&pThis->EventRecv);
AssertRCReturn(rc, rc);
- rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pUrgRecvThread, pThis, drvNATUrgRecv,
- drvNATUrgRecvWakeup, 128 * _1K, RTTHREADTYPE_IO, "NATURGRX");
- AssertRCReturn(rc, rc);
-
- rc = RTSemEventCreate(&pThis->EventRecv);
+ rc = RTSemEventCreate(&pThis->EventUrgRecv);
AssertRCReturn(rc, rc);
- rc = RTSemEventCreate(&pThis->EventUrgRecv);
+ rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pUrgRecvThread, pThis, drvNATUrgRecv,
+ drvNATUrgRecvWakeup, 128 * _1K, RTTHREADTYPE_IO, "NATURGRX");
AssertRCReturn(rc, rc);
rc = RTReqQueueCreate(&pThis->hHostResQueue);
diff --git a/src/VBox/Devices/Network/lwip-new/src/api/tcpip.c b/src/VBox/Devices/Network/lwip-new/src/api/tcpip.c
index a6a6c69..9555a75 100644
--- a/src/VBox/Devices/Network/lwip-new/src/api/tcpip.c
+++ b/src/VBox/Devices/Network/lwip-new/src/api/tcpip.c
@@ -153,6 +153,7 @@ tcpip_thread(void *arg)
if (msg->msg.cb.function != NULL) {
msg->msg.cb.function(msg->msg.cb.ctx);
}
+ memp_free(MEMP_TCPIP_MSG_API, msg);
goto terminate;
#endif
diff --git a/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp b/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp
index 45cae6b..0529649 100644
--- a/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp
+++ b/src/VBox/Devices/Network/lwip-new/vbox/VBoxLwipCore.cpp
@@ -132,7 +132,7 @@ int vboxLwipCoreInitialize(PFNRT1 pfnCallback, void *pvCallbackArg)
lwipRc = sys_sem_new(&g_LwipCore.LwipTcpIpSem, 0);
if (lwipRc != ERR_OK)
{
- LogFlow(("%s: sys_sem_new error %d\n", __FUNCTION__, lwipRc));
+ LogFlowFunc(("sys_sem_new error %d\n", lwipRc));
goto done;
}
@@ -143,7 +143,7 @@ int vboxLwipCoreInitialize(PFNRT1 pfnCallback, void *pvCallbackArg)
lwipRc = tcpip_callback(lwipCoreUserCallback, &callback);
if (lwipRc != ERR_OK)
{
- LogFlow(("%s: tcpip_callback error %d\n", __FUNCTION__, lwipRc));
+ LogFlowFunc(("tcpip_callback error %d\n", lwipRc));
goto done;
}
}
@@ -190,24 +190,25 @@ void vboxLwipCoreFinalize(PFNRT1 pfnCallback, void *pvCallbackArg)
* is tcpip_msg::sem, but it seems to be unused and may be
* gone in future versions of lwip.
*/
- struct tcpip_msg msg;
- msg.type = TCPIP_MSG_CALLBACK_TERMINATE;
- msg.msg.cb.function = lwipCoreFiniDone;
- msg.msg.cb.ctx = &callback;
-
- lwipRc = tcpip_callbackmsg((struct tcpip_callback_msg *)&msg);
- if (lwipRc != ERR_OK)
+ struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
+ if (msg)
{
- LogFlow(("%s: tcpip_callback_msg error %d\n", __FUNCTION__, lwipRc));
+ msg->type = TCPIP_MSG_CALLBACK_TERMINATE;
+ msg->msg.cb.function = lwipCoreFiniDone;
+ msg->msg.cb.ctx = &callback;
+
+ lwipRc = tcpip_callbackmsg((struct tcpip_callback_msg *)msg);
+ if (lwipRc != ERR_OK)
+ LogFlowFunc(("tcpip_callback_msg error %d\n", lwipRc));
}
+ else
+ LogFlowFunc(("memp_malloc no memory\n"));
}
else
{
lwipRc = tcpip_callback(lwipCoreUserCallback, &callback);
if (lwipRc != ERR_OK)
- {
- LogFlow(("%s: tcpip_callback error %d\n", __FUNCTION__, lwipRc));
- }
+ LogFlowFunc(("tcpip_callback error %d\n", lwipRc));
}
if (lwipRc == ERR_OK)
diff --git a/src/VBox/Devices/Network/slirp/ip_input.c b/src/VBox/Devices/Network/slirp/ip_input.c
index 5c43297..f7c839a 100644
--- a/src/VBox/Devices/Network/slirp/ip_input.c
+++ b/src/VBox/Devices/Network/slirp/ip_input.c
@@ -140,7 +140,7 @@ ip_input(PNATState pData, struct mbuf *m)
hlen = ip->ip_hl << 2;
if ( hlen < sizeof(struct ip)
- || hlen > m->m_len)
+ || hlen > mlen)
{
/* min header length */
ipstat.ips_badhlen++; /* or packet too short */
@@ -184,7 +184,7 @@ ip_input(PNATState pData, struct mbuf *m)
/* Should drop packet if mbuf too long? hmmm... */
if (mlen > ip->ip_len)
- m_adj(m, ip->ip_len - m->m_len);
+ m_adj(m, ip->ip_len - mlen);
/* source must be unicast */
if ((ip->ip_src.s_addr & RT_N2H_U32_C(0xe0000000)) == RT_N2H_U32_C(0xe0000000))
diff --git a/src/VBox/Devices/Network/slirp/slirp.c b/src/VBox/Devices/Network/slirp/slirp.c
index 5014d39..ae17729 100644
--- a/src/VBox/Devices/Network/slirp/slirp.c
+++ b/src/VBox/Devices/Network/slirp/slirp.c
@@ -561,6 +561,12 @@ void slirp_term(PNATState pData)
LIST_REMOVE(ac, list);
RTMemFree(ac);
}
+ while (!LIST_EMPTY(&pData->port_forward_rule_head))
+ {
+ struct port_forward_rule *rule = LIST_FIRST(&pData->port_forward_rule_head);
+ LIST_REMOVE(rule, list);
+ RTMemFree(rule);
+ }
slirpTftpTerm(pData);
bootp_dhcp_fini(pData);
m_fini(pData);
diff --git a/src/VBox/Devices/Network/slirp/socket.c b/src/VBox/Devices/Network/slirp/socket.c
index 9ed8abf..d2e2535 100644
--- a/src/VBox/Devices/Network/slirp/socket.c
+++ b/src/VBox/Devices/Network/slirp/socket.c
@@ -1132,7 +1132,7 @@ sofcantrcvmore(struct socket *so)
* indication. As far as I can tell the only way to detect
* this on Linux is to check if shutdown() succeeds here (but
* see below).
- *
+ *
* OTOH on OS X shutdown() "helpfully" checks if remote has
* already closed and then always returns ENOTCONN
* immediately.
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
index fd8737f..b165223 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.asm
@@ -1115,7 +1115,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcde class=DATA group=DGROUP
section CONST2 progbits vstart=0xd8e align=1 ; size=0x3fa class=DATA group=DGROUP
_bios_cvs_version_string: ; 0xf0d8e LB 0x12
- db 'VirtualBox 5.1.14', 000h
+ db 'VirtualBox 5.1.16', 000h
_bios_prefix_string: ; 0xf0da0 LB 0x8
db 'BIOS: ', 000h, 000h
_isotag: ; 0xf0da8 LB 0x6
@@ -17798,4 +17798,4 @@ biosorg_check_before_or_at_0FFEEh: ; 0xfff80 LB 0x70
db 'XM'
cpu_reset: ; 0xffff0 LB 0x10
jmp far 0f000h:0e05bh ; ea 5b e0 00 f0
- db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 056h
+ db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 054h
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
index 5a7c9d9..76beb62 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative286.md5sum
@@ -1 +1 @@
-86778e11757d6e0bf6fcc2ea86562af3 *VBoxPcBios286.rom
+ddf193883558a1ce6db9d4b6f655fb48 *VBoxPcBios286.rom
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
index 17e39ab..84da474 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.asm
@@ -1078,7 +1078,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcde class=DATA group=DGROUP
section CONST2 progbits vstart=0xd8e align=1 ; size=0x3fa class=DATA group=DGROUP
_bios_cvs_version_string: ; 0xf0d8e LB 0x12
- db 'VirtualBox 5.1.14', 000h
+ db 'VirtualBox 5.1.16', 000h
_bios_prefix_string: ; 0xf0da0 LB 0x8
db 'BIOS: ', 000h, 000h
_isotag: ; 0xf0da8 LB 0x6
@@ -17197,4 +17197,4 @@ biosorg_check_before_or_at_0FFEEh: ; 0xfff80 LB 0x70
db 'XM'
cpu_reset: ; 0xffff0 LB 0x10
jmp far 0f000h:0e05bh ; ea 5b e0 00 f0
- db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 0e7h
+ db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fch, 0e5h
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
index 3451cd0..76d860c 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative386.md5sum
@@ -1 +1 @@
-463264b1d9ad1b4f0486e4e85cd5b1e5 *VBoxPcBios386.rom
+96f77f81e0b36fc998c855cb73084c7a *VBoxPcBios386.rom
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
index f5320c7..0d32107 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.asm
@@ -1115,7 +1115,7 @@ section CONST progbits vstart=0xb0 align=1 ; size=0xcde class=DATA group=DGROUP
section CONST2 progbits vstart=0xd8e align=1 ; size=0x3fa class=DATA group=DGROUP
_bios_cvs_version_string: ; 0xf0d8e LB 0x12
- db 'VirtualBox 5.1.14', 000h
+ db 'VirtualBox 5.1.16', 000h
_bios_prefix_string: ; 0xf0da0 LB 0x8
db 'BIOS: ', 000h, 000h
_isotag: ; 0xf0da8 LB 0x6
@@ -18273,4 +18273,4 @@ biosorg_check_before_or_at_0FFEEh: ; 0xfff80 LB 0x70
db 'XM'
cpu_reset: ; 0xffff0 LB 0x10
jmp far 0f000h:0e05bh ; ea 5b e0 00 f0
- db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fbh, 004h
+ db 030h, 036h, 02fh, 032h, 033h, 02fh, 039h, 039h, 000h, 0fbh, 002h
diff --git a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
index 124bd30..707677c 100644
--- a/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
+++ b/src/VBox/Devices/PC/BIOS/VBoxBiosAlternative8086.md5sum
@@ -1 +1 @@
-c048f16803d5500df9d2f3edd43147a7 *VBoxPcBios8086.rom
+dbb72c2d4a81e99b8a2c44a67fa3ffc5 *VBoxPcBios8086.rom
diff --git a/src/VBox/Devices/PC/DevACPI.cpp b/src/VBox/Devices/PC/DevACPI.cpp
index d0cf09e..f36d42c 100644
--- a/src/VBox/Devices/PC/DevACPI.cpp
+++ b/src/VBox/Devices/PC/DevACPI.cpp
@@ -170,7 +170,7 @@ enum
SYSTEM_INFO_INDEX_SERIAL2_IRQ = 6,
SYSTEM_INFO_INDEX_SERIAL3_IOBASE = 7,
SYSTEM_INFO_INDEX_SERIAL3_IRQ = 8,
- SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH= 9,
+ SYSTEM_INFO_INDEX_PREF64_MEMORY_MIN = 9,
SYSTEM_INFO_INDEX_RTC_STATUS = 10,
SYSTEM_INFO_INDEX_CPU_LOCKED = 11, /**< Contains a flag indicating whether the CPU is locked or not */
SYSTEM_INFO_INDEX_CPU_LOCK_CHECK = 12, /**< For which CPU the lock status should be checked */
@@ -191,7 +191,8 @@ enum
SYSTEM_INFO_INDEX_PARALLEL0_IRQ = 27,
SYSTEM_INFO_INDEX_PARALLEL1_IOBASE = 28,
SYSTEM_INFO_INDEX_PARALLEL1_IRQ = 29,
- SYSTEM_INFO_INDEX_END = 30,
+ SYSTEM_INFO_INDEX_PREF64_MEMORY_MAX = 30,
+ SYSTEM_INFO_INDEX_END = 31,
SYSTEM_INFO_INDEX_INVALID = 0x80,
SYSTEM_INFO_INDEX_VALID = 0x200
};
@@ -307,8 +308,10 @@ typedef struct ACPIState
uint32_t uSystemInfoIndex;
uint64_t u64RamSize;
- /** The number of bytes above 4GB. */
- uint64_t cbRamHigh;
+ /** Offset of the 64-bit prefetchable memory window. */
+ uint64_t u64PciPref64Min;
+ /** Limit of the 64-bit prefetchable memory window. */
+ uint64_t u64PciPref64Max;
/** The number of bytes below 4GB. */
uint32_t cbRamLow;
@@ -359,6 +362,8 @@ typedef struct ACPIState
bool fCpuHotPlug;
/** If MCFG ACPI table shown to the guest */
bool fUseMcfg;
+ /** if the 64-bit prefetchable memory window is shown to the guest */
+ bool fPciPref64Enabled;
/** Primary NIC PCI address. */
uint32_t u32NicPciAddress;
/** Primary audio card PCI address. */
@@ -1323,9 +1328,14 @@ PDMBOTHCBDECL(int) acpiR3SysInfoDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOP
*pu32 = pThis->cbRamLow;
break;
- case SYSTEM_INFO_INDEX_HIGH_MEMORY_LENGTH:
- *pu32 = pThis->cbRamHigh >> 16; /* 64KB units */
- Assert(((uint64_t)*pu32 << 16) == pThis->cbRamHigh);
+ case SYSTEM_INFO_INDEX_PREF64_MEMORY_MIN:
+ *pu32 = pThis->u64PciPref64Min >> 16; /* 64KB units */
+ Assert(((uint64_t)*pu32 << 16) == pThis->u64PciPref64Min);
+ break;
+
+ case SYSTEM_INFO_INDEX_PREF64_MEMORY_MAX:
+ *pu32 = pThis->u64PciPref64Max >> 16; /* 64KB units */
+ Assert(((uint64_t)*pu32 << 16) == pThis->u64PciPref64Max);
break;
case SYSTEM_INFO_INDEX_USE_IOAPIC:
@@ -1891,6 +1901,7 @@ PDMBOTHCBDECL(int) acpiR3DhexWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Po
break;
case 2:
Log(("%#6x\n", u32 & 0xffff));
+ break;
case 4:
Log(("%#10x\n", u32));
break;
@@ -3116,30 +3127,29 @@ static int acpiR3PlantTables(ACPIState *pThis)
cbRsdt += cAddr*sizeof(uint32_t); /* each entry: 32 bits phys. address. */
cbXsdt += cAddr*sizeof(uint64_t); /* each entry: 64 bits phys. address. */
- rc = CFGMR3QueryU64(pThis->pDevInsR3->pCfg, "RamSize", &pThis->u64RamSize);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pThis->pDevInsR3, rc,
- N_("Configuration error: Querying \"RamSize\" as integer failed"));
-
- uint32_t cbRamHole;
- rc = CFGMR3QueryU32Def(pThis->pDevInsR3->pCfg, "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pThis->pDevInsR3, rc,
- N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
-
/*
- * Calculate the sizes for the high and low regions.
+ * Calculate the sizes for the low region and for the 64-bit prefetchable memory.
+ * The latter starts never below 4G.
*/
- const uint64_t offRamHole = _4G - cbRamHole;
- pThis->cbRamHigh = offRamHole < pThis->u64RamSize ? pThis->u64RamSize - offRamHole : 0;
- uint64_t cbRamLow = offRamHole < pThis->u64RamSize ? offRamHole : pThis->u64RamSize;
- if (cbRamLow > UINT32_C(0xffe00000)) /* See MEM3. */
+ PVM pVM = PDMDevHlpGetVM(pThis->pDevInsR3);
+ uint32_t cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
+ uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
+
+ pThis->u64RamSize = MMR3PhysGetRamSize(pVM);
+ if (pThis->fPciPref64Enabled)
+ {
+ /* Activate MEM4. See also DevPciIch9.cpp / ich9pciFakePCIBIOS() / uPciBiosMmio64 */
+ pThis->u64PciPref64Min = _4G + cbAbove4GB;
+ LogRel(("ACPI: enabling 64-bit prefetch root bus resource %#018RX64..%#018RX64\n",
+ pThis->u64PciPref64Min, pThis->u64PciPref64Max-1));
+ }
+ if (cbBelow4GB > UINT32_C(0xffe00000)) /* See MEM3. */
{
/* Note: This is also enforced by DevPcBios.cpp. */
- LogRel(("ACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbRamLow));
- cbRamLow = UINT32_C(0xffe00000);
+ LogRel(("ACPI: Clipping cbRamLow=%#RX64 down to 0xffe00000.\n", cbBelow4GB));
+ cbBelow4GB = UINT32_C(0xffe00000);
}
- pThis->cbRamLow = (uint32_t)cbRamLow;
+ pThis->cbRamLow = cbBelow4GB;
GCPhysCur = 0;
GCPhysRsdt = GCPhysCur;
@@ -3547,8 +3557,6 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
* Validate and read the configuration.
*/
if (!CFGMR3AreValuesValid(pCfg,
- "RamSize\0"
- "RamHoleSize\0"
"IOAPIC\0"
"NumCPUs\0"
"GCEnabled\0"
@@ -3557,6 +3565,8 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
"McfgEnabled\0"
"McfgBase\0"
"McfgLength\0"
+ "PciPref64Enabled\0"
+ "PciPref64LimitGB\0"
"SmcEnabled\0"
"FdcEnabled\0"
"ShowRtc\0"
@@ -3624,6 +3634,20 @@ static DECLCALLBACK(int) acpiR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFG
N_("Configuration error: Failed to read \"McfgLength\""));
pThis->fUseMcfg = (pThis->u64PciConfigMMioAddress != 0) && (pThis->u64PciConfigMMioLength != 0);
+ /* query whether we are supposed to set up the 64-bit prefetchable memory window */
+ rc = CFGMR3QueryBoolDef(pCfg, "PciPref64Enabled", &pThis->fPciPref64Enabled, false);
+ if (RT_FAILURE(rc))
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("Configuration error: Failed to read \"PciPref64Enabled\""));
+
+ /* query the limit of the the 64-bit prefetchable memory window */
+ uint64_t u64PciPref64MaxGB;
+ rc = CFGMR3QueryU64Def(pCfg, "PciPref64LimitGB", &u64PciPref64MaxGB, 64);
+ if (RT_FAILURE(rc))
+ return PDMDEV_SET_ERROR(pDevIns, rc,
+ N_("Configuration error: Failed to read \"PciPref64LimitGB\""));
+ pThis->u64PciPref64Max = _1G64 * u64PciPref64MaxGB;
+
/* query whether we are supposed to present custom table */
pThis->fUseCust = false;
diff --git a/src/VBox/Devices/PC/DevFwCommon.cpp b/src/VBox/Devices/PC/DevFwCommon.cpp
index 91b7c16..d6ba819 100644
--- a/src/VBox/Devices/PC/DevFwCommon.cpp
+++ b/src/VBox/Devices/PC/DevFwCommon.cpp
@@ -819,11 +819,7 @@ int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, P
/***************************************
* DMI Physical Memory Array (Type 16) *
***************************************/
- uint64_t u64RamSize;
- rc = CFGMR3QueryU64(pCfg, "RamSize", &u64RamSize);
- if (RT_FAILURE (rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed to read \"RamSize\""));
+ uint64_t const cbRamSize = MMR3PhysGetRamSize(PDMDevHlpGetVM(pDevIns));
PDMIRAMARRAY pMemArray = (PDMIRAMARRAY)pszStr;
DMI_CHECK_SIZE(sizeof(*pMemArray));
@@ -837,7 +833,16 @@ int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, P
pMemArray->u8Location = 0x03; /* Motherboard */
pMemArray->u8Use = 0x03; /* System memory */
pMemArray->u8MemErrorCorrection = 0x01; /* Other */
- pMemArray->u32MaxCapacity = (uint32_t)(u64RamSize / _1K); /* RAM size in K */
+ if (cbRamSize / _1K > INT32_MAX)
+ {
+ /** @todo 2TB-1K limit. In such cases we probably need to provide multiple type-16 descriptors.
+ * Or use 0x8000'0000 = 'capacity unknown'? */
+ AssertLogRelMsgFailed(("DMI: RAM size %#RX64 does not fit into type-16 descriptor, clipping to %#RX64\n",
+ cbRamSize, (uint64_t)INT32_MAX * _1K));
+ pMemArray->u32MaxCapacity = INT32_MAX;
+ }
+ else
+ pMemArray->u32MaxCapacity = (int32_t)(cbRamSize / _1K); /* RAM size in K */
pMemArray->u16MemErrorHandle = 0xfffe; /* No error info structure */
pMemArray->u16NumberOfMemDevices = 1;
DMI_TERM_STRUCT;
@@ -858,7 +863,17 @@ int FwCommonPlantDMITable(PPDMDEVINS pDevIns, uint8_t *pTable, unsigned cbMax, P
pMemDev->u16MemErrHandle = 0xfffe; /* system doesn't provide this information */
pMemDev->u16TotalWidth = 0xffff; /* Unknown */
pMemDev->u16DataWidth = 0xffff; /* Unknown */
- int16_t u16RamSizeM = (uint16_t)(u64RamSize / _1M);
+ int16_t u16RamSizeM;
+ if (cbRamSize / _1M > INT16_MAX)
+ {
+ /** @todo 32G-1M limit. Provide multiple type-17 descriptors.
+ * The highest bit of u16Size must be 0 to specify 'GB' units / 1 would be 'KB' */
+ AssertLogRelMsgFailed(("DMI: RAM size %#RX64 too big for one type-17 descriptor, clipping to %#RX64\n",
+ cbRamSize, (uint64_t)INT16_MAX * _1M));
+ u16RamSizeM = INT16_MAX;
+ }
+ else
+ u16RamSizeM = (uint16_t)(cbRamSize / _1M);
if (u16RamSizeM == 0)
u16RamSizeM = 0x400; /* 1G */
pMemDev->u16Size = u16RamSizeM; /* RAM size */
diff --git a/src/VBox/Devices/PC/DevPcBios.cpp b/src/VBox/Devices/PC/DevPcBios.cpp
index 34acb48..b72f9a6 100644
--- a/src/VBox/Devices/PC/DevPcBios.cpp
+++ b/src/VBox/Devices/PC/DevPcBios.cpp
@@ -154,10 +154,6 @@ typedef struct DEVPCBIOS
/** Boot devices (ordered). */
DEVPCBIOSBOOT aenmBootDevice[4];
- /** RAM size (in bytes). */
- uint64_t cbRam;
- /** RAM hole size (in bytes). */
- uint32_t cbRamHole;
/** Bochs shutdown index. */
uint32_t iShutdown;
/** Floppy device. */
@@ -620,51 +616,49 @@ static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
PPDMIMEDIA apHDs[4] = {0};
LogFlow(("pcbiosInitComplete:\n"));
+ PVM pVM = PDMDevHlpGetVM(pDevIns);
+ uint64_t const cbRamSize = MMR3PhysGetRamSize(pVM);
+ uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
+ uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
+
/*
* Memory sizes.
*/
/* base memory. */
- u32 = pThis->cbRam > 640 ? 640 : (uint32_t)pThis->cbRam / _1K; /* <-- this test is wrong, but it doesn't matter since we never assign less than 1MB */
- pcbiosCmosWrite(pDevIns, 0x15, u32 & 0xff); /* 15h - Base Memory in K, Low Byte */
- pcbiosCmosWrite(pDevIns, 0x16, u32 >> 8); /* 16h - Base Memory in K, High Byte */
+ u32 = cbRamSize > 640 ? 640 : (uint32_t)cbRamSize / _1K; /* <-- this test is wrong, but it doesn't matter since we never assign less than 1MB */
+ pcbiosCmosWrite(pDevIns, 0x15, RT_BYTE1(u32)); /* 15h - Base Memory in K, Low Byte */
+ pcbiosCmosWrite(pDevIns, 0x16, RT_BYTE2(u32)); /* 16h - Base Memory in K, High Byte */
/* Extended memory, up to 65MB */
- u32 = pThis->cbRam >= 65 * _1M ? 0xffff : ((uint32_t)pThis->cbRam - _1M) / _1K;
- pcbiosCmosWrite(pDevIns, 0x17, u32 & 0xff); /* 17h - Extended Memory in K, Low Byte */
- pcbiosCmosWrite(pDevIns, 0x18, u32 >> 8); /* 18h - Extended Memory in K, High Byte */
- pcbiosCmosWrite(pDevIns, 0x30, u32 & 0xff); /* 30h - Extended Memory in K, Low Byte */
- pcbiosCmosWrite(pDevIns, 0x31, u32 >> 8); /* 31h - Extended Memory in K, High Byte */
+ u32 = cbRamSize >= 65 * _1M ? 0xffff : ((uint32_t)cbRamSize - _1M) / _1K;
+ pcbiosCmosWrite(pDevIns, 0x17, RT_BYTE1(u32)); /* 17h - Extended Memory in K, Low Byte */
+ pcbiosCmosWrite(pDevIns, 0x18, RT_BYTE2(u32)); /* 18h - Extended Memory in K, High Byte */
+ pcbiosCmosWrite(pDevIns, 0x30, RT_BYTE1(u32)); /* 30h - Extended Memory in K, Low Byte */
+ pcbiosCmosWrite(pDevIns, 0x31, RT_BYTE2(u32)); /* 31h - Extended Memory in K, High Byte */
/* Bochs BIOS specific? Anyway, it's the amount of memory above 16MB
and below 4GB (as it can only hold 4GB+16M). We have to chop off the
top 2MB or it conflict with what the ACPI tables return. (Should these
be adjusted, we still have to chop it at 0xfffc0000 or it'll conflict
with the high BIOS mapping.) */
- uint64_t const offRamHole = _4G - pThis->cbRamHole;
- if (pThis->cbRam > 16 * _1M)
- u32 = (uint32_t)( (RT_MIN(RT_MIN(pThis->cbRam, offRamHole), UINT32_C(0xffe00000)) - 16U * _1M) / _64K );
+ if (cbRamSize > 16 * _1M)
+ u32 = (RT_MIN(cbBelow4GB, UINT32_C(0xffe00000)) - 16U * _1M) / _64K;
else
u32 = 0;
- pcbiosCmosWrite(pDevIns, 0x34, u32 & 0xff);
- pcbiosCmosWrite(pDevIns, 0x35, u32 >> 8);
+ pcbiosCmosWrite(pDevIns, 0x34, RT_BYTE1(u32));
+ pcbiosCmosWrite(pDevIns, 0x35, RT_BYTE2(u32));
/* Bochs/VBox BIOS specific way of specifying memory above 4GB in 64KB units.
Bochs got these in a different location which we've already used for SATA,
it also lacks the last two. */
- uint64_t c64KBAbove4GB;
- if (pThis->cbRam <= offRamHole)
- c64KBAbove4GB = 0;
- else
- {
- c64KBAbove4GB = (pThis->cbRam - offRamHole) / _64K;
- /* Make sure it doesn't hit the limits of the current BIOS code. */
- AssertLogRelMsgReturn((c64KBAbove4GB >> (3 * 8)) < 255, ("%#RX64\n", c64KBAbove4GB), VERR_OUT_OF_RANGE);
- }
- pcbiosCmosWrite(pDevIns, 0x61, c64KBAbove4GB & 0xff);
- pcbiosCmosWrite(pDevIns, 0x62, (c64KBAbove4GB >> 8) & 0xff);
- pcbiosCmosWrite(pDevIns, 0x63, (c64KBAbove4GB >> 16) & 0xff);
- pcbiosCmosWrite(pDevIns, 0x64, (c64KBAbove4GB >> 24) & 0xff);
- pcbiosCmosWrite(pDevIns, 0x65, (c64KBAbove4GB >> 32) & 0xff);
+ uint64_t c64KBAbove4GB = cbAbove4GB / _64K;
+ /* Make sure it doesn't hit the limits of the current BIOS code (RAM limit of ~255TB). */
+ AssertLogRelMsgReturn((c64KBAbove4GB >> (3 * 8)) < 255, ("%#RX64\n", c64KBAbove4GB), VERR_OUT_OF_RANGE);
+ pcbiosCmosWrite(pDevIns, 0x61, RT_BYTE1(c64KBAbove4GB));
+ pcbiosCmosWrite(pDevIns, 0x62, RT_BYTE2(c64KBAbove4GB));
+ pcbiosCmosWrite(pDevIns, 0x63, RT_BYTE3(c64KBAbove4GB));
+ pcbiosCmosWrite(pDevIns, 0x64, RT_BYTE4(c64KBAbove4GB));
+ pcbiosCmosWrite(pDevIns, 0x65, RT_BYTE5(c64KBAbove4GB));
/*
* Number of CPUs.
@@ -700,8 +694,8 @@ static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
*/
for (i = 0; i < NET_BOOT_DEVS; ++i)
{
- pcbiosCmosWrite(pDevIns, 0x82 + i * 2, pThis->au16NetBootDev[i] & 0xff);
- pcbiosCmosWrite(pDevIns, 0x83 + i * 2, pThis->au16NetBootDev[i] >> 8);
+ pcbiosCmosWrite(pDevIns, 0x82 + i * 2, RT_BYTE1(pThis->au16NetBootDev[i]));
+ pcbiosCmosWrite(pDevIns, 0x83 + i * 2, RT_BYTE2(pThis->au16NetBootDev[i]));
}
/*
@@ -917,8 +911,8 @@ static DECLCALLBACK(int) pcbiosInitComplete(PPDMDEVINS pDevIns)
uint16_t cksum = 0;
for (i = 0x10; i < 0x2e; ++i)
cksum += pcbiosCmosRead(pDevIns, i);
- pcbiosCmosWrite(pDevIns, 0x2e, cksum >> 8);
- pcbiosCmosWrite(pDevIns, 0x2f, cksum & 0xff);
+ pcbiosCmosWrite(pDevIns, 0x2e, RT_BYTE1(cksum));
+ pcbiosCmosWrite(pDevIns, 0x2f, RT_BYTE2(cksum));
LogFlow(("%s: returns VINF_SUCCESS\n", __FUNCTION__));
return VINF_SUCCESS;
@@ -1095,8 +1089,6 @@ static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCF
"BootDevice1\0"
"BootDevice2\0"
"BootDevice3\0"
- "RamSize\0"
- "RamHoleSize\0"
"HardDiskDevice\0"
"SataHardDiskDevice\0"
"SataLUN1\0"
@@ -1161,16 +1153,6 @@ static DECLCALLBACK(int) pcbiosConstruct(PPDMDEVINS pDevIns, int iInstance, PCF
/*
* Init the data.
*/
- rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbRam);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Querying \"RamSize\" as integer failed"));
-
- rc = CFGMR3QueryU32Def(pCfg, "RamHoleSize", &pThis->cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Querying \"RamHoleSize\" as integer failed"));
-
rc = CFGMR3QueryU16Def(pCfg, "NumCPUs", &pThis->cCpus, 1);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
diff --git a/src/VBox/Devices/PC/vbox.dsl b/src/VBox/Devices/PC/vbox.dsl
index 71b82e0..c558cc7 100644
--- a/src/VBox/Devices/PC/vbox.dsl
+++ b/src/VBox/Devices/PC/vbox.dsl
@@ -13,7 +13,7 @@
// VirtualBox OSE distribution. VirtualBox OSE is distributed in the
// hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
-DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
+DefinitionBlock ("DSDT.aml", "DSDT", 2, "VBOX ", "VBOXBIOS", 2)
{
// Declare debugging ports withing SystemIO
OperationRegion(DBG0, SystemIO, 0x3000, 4)
@@ -134,17 +134,17 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
// Local6 is the length of Str2.
// Local7 is the minimum of Str1 or Str2 length.
//
-
+
Store(Arg0, Local0)
Store(S2BF(Local0), Local0)
-
+
Store(S2BF(Arg1), Local1)
Store(Zero, Local4)
-
+
Store(SLEN(Arg0), Local5)
Store(SLEN(Arg1), Local6)
Store(MIN(Local5, Local6), Local7)
-
+
While (LLess(Local4, Local7))
{
Store(Derefof(Index(Local0, Local4)), Local2)
@@ -160,10 +160,10 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
Return(Ones)
}
}
-
+
Increment(Local4)
}
-
+
If (LLess(Local4, Local5))
{
Return(One)
@@ -241,7 +241,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
DBG("_OSI exists\n")
// OS returns non-zero value in response to _OSI query if it
// supports the interface. Newer Windows releases support older
- // versions of the ACPI interface.
+ // versions of the ACPI interface.
If (_OSI("Windows 2001"))
{
Store(4, MSWV) // XP
@@ -337,16 +337,16 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
IndexField (IDX0, DAT0, DwordAcc, NoLock, Preserve)
{
- MEML, 32,
+ MEML, 32, // low-memory length (64KB units)
UIOA, 32, // if IO APIC enabled
UHPT, 32, // if HPET enabled
USMC, 32, // if SMC enabled
UFDC, 32, // if floppy controller enabled
- SL2B, 32, // Serial2 base IO address
+ SL2B, 32, // Serial2 base IO address
SL2I, 32, // Serial2 IRQ
- SL3B, 32, // Serial3 base IO address
+ SL3B, 32, // Serial3 base IO address
SL3I, 32, // Serial3 IRQ
- MEMH, 32,
+ PMNN, 32, // start of 64-bit prefetch window (64KB units)
URTC, 32, // if RTC shown in tables
CPUL, 32, // flag of CPU lock state
CPUC, 32, // CPU to check lock status
@@ -359,14 +359,15 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
HBCA, 32, // host bus controller address
PCIB, 32, // PCI MCFG base start
PCIL, 32, // PCI MCFG length
- SL0B, 32, // Serial0 base IO address
+ SL0B, 32, // Serial0 base IO address
SL0I, 32, // Serial0 IRQ
- SL1B, 32, // Serial1 base IO address
+ SL1B, 32, // Serial1 base IO address
SL1I, 32, // Serial1 IRQ
- PP0B, 32, // Parallel0 base IO address
+ PP0B, 32, // Parallel0 base IO address
PP0I, 32, // Parallel0 IRQ
- PP1B, 32, // Parallel1 base IO address
+ PP1B, 32, // Parallel1 base IO address
PP1I, 32, // Parallel1 IRQ
+ PMNX, 32, // limit of 64-bit prefetch window (64KB units)
Offset (0x80),
ININ, 32,
Offset (0x200),
@@ -388,8 +389,8 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
HEX4 (USMC)
DBG ("UFDC: ")
HEX4 (UFDC)
- DBG ("MEMH: ")
- HEX4 (MEMH)
+ DBG ("PMNN: ")
+ HEX4 (PMNN)
}
// PCI PIC IRQ Routing table
@@ -729,7 +730,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
// PCI bus 0
Device (PCI0)
{
-
+
Name (_HID, EisaId ("PNP0A03")) // PCI bus PNP id
Method(_ADR, 0, NotSerialized) // PCI address
{
@@ -738,7 +739,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
Name (_BBN, 0x00) // base bus address (bus number)
Name (_UID, 0x00)
- // Method that returns routing table; also opens PCI to I/O APIC
+ // Method that returns routing table; also opens PCI to I/O APIC
// interrupt routing backdoor by writing 0xdead 0xbeef signature
// to ISA bridge config space. See DevPCI.cpp/pciSetIrqInternal().
Method (_PRT, 0, NotSerialized)
@@ -773,7 +774,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
Offset (0xde),
APDE, 8,
}
-
+
// PCI MCFG MMIO ranges
Device (^PCIE)
{
@@ -803,7 +804,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
Return (0x0F)
}
}
- }
+ }
// Keyboard device
Device (PS2K)
@@ -965,7 +966,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
}
Name (CRS, ResourceTemplate ()
{
- IO (Decode16, 0x03F8, 0x03F8, 0x01, 0x08, _Y14)
+ IO (Decode16, 0x03F8, 0x03F8, 0x01, 0x08, _Y14)
IRQNoFlags (_Y15) {4}
})
Method (_CRS, 0, NotSerialized)
@@ -979,7 +980,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
Return (CRS)
}
}
-
+
// Serial port 1
Device (^SRL1)
{
@@ -998,7 +999,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
}
Name (CRS, ResourceTemplate ()
{
- IO (Decode16, 0x02F8, 0x02F8, 0x01, 0x08, _Y16)
+ IO (Decode16, 0x02F8, 0x02F8, 0x01, 0x08, _Y16)
IRQNoFlags (_Y17) {3}
})
Method (_CRS, 0, NotSerialized)
@@ -1031,7 +1032,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
}
Name (CRS, ResourceTemplate ()
{
- IO (Decode16, 0x03E8, 0x03E8, 0x01, 0x08, _Y22)
+ IO (Decode16, 0x03E8, 0x03E8, 0x01, 0x08, _Y22)
IRQNoFlags (_Y23) {3}
})
Method (_CRS, 0, NotSerialized)
@@ -1127,7 +1128,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
// Real Time Clock and CMOS (MC146818)
- Device (RTC)
+ Device (RTC)
{
Name (_HID, EisaId ("PNP0B00"))
Name (_CRS, ResourceTemplate ()
@@ -1146,18 +1147,18 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
}
// High Precision Event Timer
- Device(HPET)
+ Device(HPET)
{
Name (_HID, EISAID("PNP0103"))
Name (_CID, EISAID("PNP0C01"))
Name(_UID, 0)
- Method (_STA, 0, NotSerialized)
+ Method (_STA, 0, NotSerialized)
{
Return(UHPT)
}
- Name(CRS, ResourceTemplate()
+ Name(CRS, ResourceTemplate()
{
IRQNoFlags ()
{0}
@@ -1168,7 +1169,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
0x00000400 // Address Length
)
})
-
+
Method (_CRS, 0, NotSerialized)
{
Return (CRS)
@@ -1191,7 +1192,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
0x0300, // Range Minimum
0x0300, // Range Maximum
0x01, // Alignment
- 0x20) // Length
+ 0x20) // Length
IRQNoFlags ()
{6}
@@ -1200,7 +1201,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
{
Return (CRS)
}
- }
+ }
}
// NIC
@@ -1297,42 +1298,42 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
{
Method(_DSM, 4, NotSerialized)
{
- Store (Package (0x04)
- {
- "layout-id",
- Buffer (0x04)
- {
- /* 04 */ 0x04, 0x00, 0x00, 0x00
- },
-
- "PinConfigurations",
- Buffer (Zero) {}
- }, Local0)
+ Store (Package (0x04)
+ {
+ "layout-id",
+ Buffer (0x04)
+ {
+ /* 04 */ 0x04, 0x00, 0x00, 0x00
+ },
+
+ "PinConfigurations",
+ Buffer (Zero) {}
+ }, Local0)
if (LEqual (Arg0, ToUUID("a0b5b7c6-1318-441c-b0c9-fe695eaf949b")))
{
If (LEqual (Arg1, One))
{
if (LEqual(Arg2, Zero))
{
- Store (Buffer (0x01)
- {
+ Store (Buffer (0x01)
+ {
0x03
}
- , Local0)
- Return (Local0)
+ , Local0)
+ Return (Local0)
}
if (LEqual(Arg2, One))
{
- Return (Local0)
+ Return (Local0)
}
}
}
- Store (Buffer (0x01)
- {
+ Store (Buffer (0x01)
+ {
0x0
}
- , Local0)
- Return (Local0)
+ , Local0)
+ Return (Local0)
}
Method(_ADR, 0, NotSerialized)
@@ -1349,7 +1350,7 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
Return (0x0F)
}
}
- }
+ }
// Control method battery
@@ -1566,60 +1567,52 @@ DefinitionBlock ("DSDT.aml", "DSDT", 1, "VBOX ", "VBOXBIOS", 2)
)
})
-// Name (TOM, ResourceTemplate () // Memory above 4GB (aka high), appended when needed.
-// {
-// QWORDMemory(
-// ResourceProducer, // bit 0 of general flags is 0
-// PosDecode, // positive Decode
-// MinFixed, // Range is fixed
-// MaxFixed, // Range is fixed
-// Cacheable,
-// ReadWrite,
-// 0x0000000000000000, // _GRA: Granularity.
-// 0 /*0x0000000100000000*/, // _MIN: Min address, 4GB.
-// 0 /*0x00000fffffffffff*/, // _MAX: Max possible address, 16TB.
-// 0x0000000000000000, // _TRA: Translation
-// 0x0000000000000000, // _LEN: Range length (calculated dynamically)
-// , // ResourceSourceIndex: Optional field left blank
-// , // ResourceSource: Optional field left blank
-// MEM4 // Name declaration for this descriptor.
-// )
-// })
+ Name (TOM, ResourceTemplate ()
+ {
+ QwordMemory(
+ ResourceProducer, // bit 0 of general flags is 0
+ PosDecode, // positive Decode
+ MinFixed, // Range is fixed
+ MaxFixed, // Range is fixed
+ Prefetchable,
+ ReadWrite,
+ 0x0000000000000000, // _GRA: Granularity.
+ 0x0000000100000000, // _MIN: Min address, def. 4GB, will be overwritten.
+ 0x0000000fffffffff, // _MAX: Max address, def. 64GB-1, will be overwritten.
+ 0x0000000000000000, // _TRA: Translation
+ 0x0000000f00000000, // _LEN: Range length (_MAX-_MIN+1)
+ , // ResourceSourceIndex: Optional field left blank
+ , // ResourceSource: Optional field left blank
+ MEM4 // Name declaration for this descriptor.
+ )
+ })
Method (_CRS, 0, NotSerialized)
{
CreateDwordField (CRS, \_SB.PCI0.MEM3._MIN, RAMT)
CreateDwordField (CRS, \_SB.PCI0.MEM3._LEN, RAMR)
-// CreateQwordField (TOM, \_SB.PCI0.MEM4._LEN, TM4L)
-// CreateQwordField (TOM, \_SB.PCI0.MEM4._LEN, TM4N)
-// CreateQwordField (TOM, \_SB.PCI0.MEM4._LEN, TM4X)
Store (MEML, RAMT)
Subtract (0xffe00000, RAMT, RAMR)
-// If (LNotEqual (MEMH, 0x00000000))
-// {
-// //
-// // Update the TOM resource template and append it to CRS.
-// // This way old < 4GB guest doesn't see anything different.
-// // (MEMH is the memory above 4GB specified in 64KB units.)
-// //
-// // Note: ACPI v2 doesn't do 32-bit integers. IASL may fail on
-// // seeing 64-bit constants and the code probably wont work.
-// //
-// Store (1, TM4N)
-// ShiftLeft (TM4N, 32, TM4N)
-//
-// Store (0x00000fff, TM4X)
-// ShiftLeft (TM4X, 32, TM4X)
-// Or (TM4X, 0xffffffff, TM4X)
-//
-// Store (MEMH, TM4L)
-// ShiftLeft (TM4L, 16, TM4L)
-//
-// ConcatenateResTemplate (CRS, TOM, Local2)
-// Return (Local2)
-// }
+ if (LNotEqual (PMNN, 0x00000000))
+ {
+ // Not for Windows < 7!
+ If (LOr (LLess (MSWN(), 0x01), LGreater (MSWN(), 0x06)))
+ {
+ CreateQwordField (TOM, \_SB.PCI0.MEM4._MIN, TM4N)
+ CreateQwordField (TOM, \_SB.PCI0.MEM4._MAX, TM4X)
+ CreateQwordField (TOM, \_SB.PCI0.MEM4._LEN, TM4L)
+
+ Multiply (PMNN, 0x10000, TM4N) // PMNN in units of 64KB
+ Subtract (Multiply (PMNX, 0x10000), 1, TM4X) // PMNX in units of 64KB
+ Add (Subtract (TM4X, TM4N), 1, TM4L) // determine LEN, MAX is already there
+
+ ConcatenateResTemplate (CRS, TOM, Local2)
+
+ Return (Local2)
+ }
+ }
Return (CRS)
}
diff --git a/src/VBox/Devices/Samples/DevPlayground.cpp b/src/VBox/Devices/Samples/DevPlayground.cpp
index 44e028a..3651224 100644
--- a/src/VBox/Devices/Samples/DevPlayground.cpp
+++ b/src/VBox/Devices/Samples/DevPlayground.cpp
@@ -118,7 +118,8 @@ static DECLCALLBACK(int) devPlaygroundMap(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev
{
case 0:
case 2:
- Assert(enmType == (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64));
+ Assert( enmType == (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64)
+ || enmType == (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR64));
if (GCPhysAddress == NIL_RTGCPHYS)
return VINF_SUCCESS; /* We ignore the unmap notification. */
return PDMDevHlpMMIOExMap(pDevIns, pPciDev, iRegion, GCPhysAddress);
@@ -180,7 +181,8 @@ static DECLCALLBACK(int) devPlaygroundConstruct(PPDMDEVINS pDevIns, int iInstanc
/* First region. */
RTGCPHYS const cbFirst = iPciFun == 0 ? 8*_1G64 : iPciFun * _4K;
rc = PDMDevHlpPCIIORegionRegisterEx(pDevIns, &pFun->PciDev, 0, cbFirst,
- (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64),
+ (PCIADDRESSSPACE)( PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64
+ | (iPciFun == 0 ? PCI_ADDRESS_SPACE_MEM_PREFETCH : 0)),
devPlaygroundMap);
AssertLogRelRCReturn(rc, rc);
rc = PDMDevHlpMMIOExPreRegister(pDevIns, &pFun->PciDev, 0, cbFirst,
@@ -193,7 +195,8 @@ static DECLCALLBACK(int) devPlaygroundConstruct(PPDMDEVINS pDevIns, int iInstanc
/* Second region. */
RTGCPHYS const cbSecond = iPciFun == 0 ? 256*_1G64 : iPciFun * _32K;
rc = PDMDevHlpPCIIORegionRegisterEx(pDevIns, &pFun->PciDev, 2, cbSecond,
- (PCIADDRESSSPACE)(PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64),
+ (PCIADDRESSSPACE)( PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64
+ | (iPciFun == 0 ? PCI_ADDRESS_SPACE_MEM_PREFETCH : 0)),
devPlaygroundMap);
AssertLogRelRCReturn(rc, rc);
rc = PDMDevHlpMMIOExPreRegister(pDevIns, &pFun->PciDev, 2, cbSecond,
diff --git a/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp b/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
index 27d1e10..8149bad 100644
--- a/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
+++ b/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
@@ -1601,7 +1601,8 @@ static int lsilogicRegisterRead(PLSILOGICSCSI pThis, uint32_t offReg, uint32_t *
break;
case LSILOGICDOORBELLSTATE_FN_HANDSHAKE:
/* Return next 16bit value. */
- u32 |= pThis->ReplyBuffer.au16Reply[pThis->uNextReplyEntryRead++];
+ if (pThis->uNextReplyEntryRead < pThis->cReplySize)
+ u32 |= pThis->ReplyBuffer.au16Reply[pThis->uNextReplyEntryRead++];
lsilogicSetInterrupt(pThis, LSILOGIC_REG_HOST_INTR_STATUS_SYSTEM_DOORBELL);
break;
case LSILOGICDOORBELLSTATE_RFR_FRAME_COUNT_LOW:
diff --git a/src/VBox/Devices/USB/VUSBSnifferPcapNg.cpp b/src/VBox/Devices/USB/VUSBSnifferPcapNg.cpp
index f57ff0b..2abe6a4 100644
--- a/src/VBox/Devices/USB/VUSBSnifferPcapNg.cpp
+++ b/src/VBox/Devices/USB/VUSBSnifferPcapNg.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2014-2016 Oracle Corporation
+ * Copyright (C) 2014-2017 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -449,7 +449,7 @@ static int vusbSnifferAddOption(PVUSBSNIFFERFMTINT pThis, uint16_t u16OptionCode
/** @interface_method_impl{VUSBSNIFFERFMT,pfnInit} */
-static DECLCALLBACK(int) vusbSnifferFmtPcanNgInit(PVUSBSNIFFERFMTINT pThis, PVUSBSNIFFERSTRM pStrm)
+static DECLCALLBACK(int) vusbSnifferFmtPcapNgInit(PVUSBSNIFFERFMTINT pThis, PVUSBSNIFFERSTRM pStrm)
{
pThis->pStrm = pStrm;
pThis->cbBlockCur = 0;
@@ -547,7 +547,7 @@ static DECLCALLBACK(int) vusbSnifferFmtPcanNgInit(PVUSBSNIFFERFMTINT pThis, PVUS
/** @interface_method_impl{VUSBSNIFFERFMT,pfnDestroy} */
-static DECLCALLBACK(void) vusbSnifferFmtPcanNgDestroy(PVUSBSNIFFERFMTINT pThis)
+static DECLCALLBACK(void) vusbSnifferFmtPcapNgDestroy(PVUSBSNIFFERFMTINT pThis)
{
if (pThis->pbBlockData)
RTMemFree(pThis->pbBlockData);
@@ -555,7 +555,7 @@ static DECLCALLBACK(void) vusbSnifferFmtPcanNgDestroy(PVUSBSNIFFERFMTINT pThis)
/** @interface_method_impl{VUSBSNIFFERFMT,pfnRecordEvent} */
-static DECLCALLBACK(int) vusbSnifferFmtPcanNgRecordEvent(PVUSBSNIFFERFMTINT pThis, PVUSBURB pUrb, VUSBSNIFFEREVENT enmEvent)
+static DECLCALLBACK(int) vusbSnifferFmtPcapNgRecordEvent(PVUSBSNIFFERFMTINT pThis, PVUSBURB pUrb, VUSBSNIFFEREVENT enmEvent)
{
DumpFileEpb Epb;
DumpFileUsbHeaderLnxMmapped UsbHdr;
@@ -642,7 +642,8 @@ static DECLCALLBACK(int) vusbSnifferFmtPcanNgRecordEvent(PVUSBSNIFFERFMTINT pThi
|| pUrb->enmType == VUSBXFERTYPE_MSG)
cbDataLength = 0;
}
- else if (pUrb->enmDir == VUSBDIRECTION_SETUP)
+ else if ( pUrb->enmDir == VUSBDIRECTION_SETUP
+ && cbDataLength >= sizeof(VUSBSETUP))
cbDataLength -= sizeof(VUSBSETUP);
Epb.u32CapturedLen = cbCapturedLength + cbDataLength;
@@ -720,10 +721,10 @@ const VUSBSNIFFERFMT g_VUsbSnifferFmtPcapNg =
/** cbFmt */
sizeof(VUSBSNIFFERFMTINT),
/** pfnInit */
- vusbSnifferFmtPcanNgInit,
+ vusbSnifferFmtPcapNgInit,
/** pfnDestroy */
- vusbSnifferFmtPcanNgDestroy,
+ vusbSnifferFmtPcapNgDestroy,
/** pfnRecordEvent */
- vusbSnifferFmtPcanNgRecordEvent
+ vusbSnifferFmtPcapNgRecordEvent
};
diff --git a/src/VBox/Devices/VMMDev/VMMDev.cpp b/src/VBox/Devices/VMMDev/VMMDev.cpp
index 3060205..96269ef 100644
--- a/src/VBox/Devices/VMMDev/VMMDev.cpp
+++ b/src/VBox/Devices/VMMDev/VMMDev.cpp
@@ -3920,6 +3920,7 @@ static DECLCALLBACK(int) vmmdevDestruct(PPDMDEVINS pDevIns)
#ifdef VBOX_WITH_HGCM
vmmdevHGCMDestroy(pThis);
+ RTCritSectDelete(&pThis->critsectHGCMCmdList);
#endif
#ifndef VBOX_WITHOUT_TESTING_FEATURES
@@ -4015,7 +4016,6 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
"BackdoorLogDisabled|"
"KeepCredentials|"
"HeapEnabled|"
- "RamSize|"
"RZEnabled|"
"GuestCoreDumpEnabled|"
"GuestCoreDumpDir|"
@@ -4028,11 +4028,6 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
,
"");
- rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbGuestRAM);
- if (RT_FAILURE(rc))
- return PDMDEV_SET_ERROR(pDevIns, rc,
- N_("Configuration error: Failed querying \"RamSize\" as a 64-bit unsigned integer"));
-
rc = CFGMR3QueryBoolDef(pCfg, "GetHostTimeDisabled", &pThis->fGetHostTimeDisabled, false);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
@@ -4113,6 +4108,8 @@ static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFG
/** @todo image-to-load-filename? */
#endif
+ pThis->cbGuestRAM = MMR3PhysGetRamSize(PDMDevHlpGetVM(pDevIns));
+
/*
* We do our own locking entirely. So, install NOP critsect for the device
* and create our own critsect for use where it really matters (++).
diff --git a/src/VBox/Devices/VirtIO/Virtio.cpp b/src/VBox/Devices/VirtIO/Virtio.cpp
index 19a1705..05cdefe 100644
--- a/src/VBox/Devices/VirtIO/Virtio.cpp
+++ b/src/VBox/Devices/VirtIO/Virtio.cpp
@@ -164,7 +164,7 @@ bool vqueueGet(PVPCISTATE pState, PVQUEUE pQueue, PVQUEUEELEM pElem, bool fRemov
}
break;
}
-
+
vringReadDesc(pState, &pQueue->VRing, idx, &desc);
if (desc.u16Flags & VRINGDESC_F_WRITE)
{
diff --git a/src/VBox/Devices/build/VBoxDD.cpp b/src/VBox/Devices/build/VBoxDD.cpp
index 24b7e94..728a6f6 100644
--- a/src/VBox/Devices/build/VBoxDD.cpp
+++ b/src/VBox/Devices/build/VBoxDD.cpp
@@ -126,11 +126,7 @@ extern "C" DECLEXPORT(int) VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t
rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSB16);
if (RT_FAILURE(rc))
return rc;
-#ifdef VBOX_WITH_AUDIO_50
rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceICH6_HDA);
-#else
- rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceHDA);
-#endif
if (RT_FAILURE(rc))
return rc;
#ifdef VBOX_WITH_VUSB
diff --git a/src/VBox/Devices/build/VBoxDD.h b/src/VBox/Devices/build/VBoxDD.h
index 77a61c0..4dc0d17 100644
--- a/src/VBox/Devices/build/VBoxDD.h
+++ b/src/VBox/Devices/build/VBoxDD.h
@@ -59,11 +59,7 @@ extern const PDMDEVREG g_DeviceINIP;
#endif
extern const PDMDEVREG g_DeviceICHAC97;
extern const PDMDEVREG g_DeviceSB16;
-#ifdef VBOX_WITH_AUDIO_50
extern const PDMDEVREG g_DeviceICH6_HDA;
-#else
-extern const PDMDEVREG g_DeviceHDA;
-#endif
extern const PDMDEVREG g_DeviceOHCI;
extern const PDMDEVREG g_DeviceEHCI;
extern const PDMDEVREG g_DeviceXHCI;
diff --git a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
index 42dfb5a..4e0e34b 100644
--- a/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
+++ b/src/VBox/Devices/testcase/tstDeviceStructSizeRC.cpp
@@ -1922,9 +1922,13 @@ int main()
GEN_CHECK_OFF(AC97DRIVER, MicIn);
GEN_CHECK_OFF(AC97DRIVER, Out);
- GEN_CHECK_SIZE(HDAMIXERSTREAM);
- GEN_CHECK_OFF(HDAMIXERSTREAM, DestSource);
- GEN_CHECK_OFF(HDAMIXERSTREAM, pMixStrm);
+ GEN_CHECK_SIZE(HDAINPUTSTREAM);
+ GEN_CHECK_OFF(HDAINPUTSTREAM, pStrmIn);
+ GEN_CHECK_OFF(HDAINPUTSTREAM, phStrmIn);
+
+ GEN_CHECK_SIZE(HDAOUTPUTSTREAM);
+ GEN_CHECK_OFF(HDAOUTPUTSTREAM, pStrmOut);
+ GEN_CHECK_OFF(HDAOUTPUTSTREAM, phStrmOut);
GEN_CHECK_SIZE(HDADRIVER);
GEN_CHECK_OFF(HDADRIVER, Node);
@@ -1937,11 +1941,7 @@ int main()
#ifdef VBOX_WITH_HDA_MIC_IN
GEN_CHECK_OFF(HDADRIVER, MicIn);
#endif
- GEN_CHECK_OFF(HDADRIVER, Front);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- GEN_CHECK_OFF(HDADRIVER, CenterLFE);
- GEN_CHECK_OFF(HDADRIVER, Rear);
-#endif
+ GEN_CHECK_OFF(HDADRIVER, Out);
GEN_CHECK_SIZE(HDABDLESTATE);
GEN_CHECK_OFF(HDABDLESTATE, u32BDLIndex);
@@ -1960,7 +1960,7 @@ int main()
GEN_CHECK_OFF(HDASTREAMSTATE, BDLE);
GEN_CHECK_SIZE(HDASTREAM);
- GEN_CHECK_OFF(HDASTREAM, u8SD);
+ GEN_CHECK_OFF(HDASTREAM, u8Strm);
GEN_CHECK_OFF(HDASTREAM, u64BDLBase);
GEN_CHECK_OFF(HDASTREAM, u16FMT);
GEN_CHECK_OFF(HDASTREAM, u16FIFOS);
@@ -1975,9 +1975,10 @@ int main()
GEN_CHECK_OFF(HDASTATE, IBase);
GEN_CHECK_OFF(HDASTATE, MMIOBaseAddr);
GEN_CHECK_OFF(HDASTATE, au32Regs[0]);
- GEN_CHECK_OFF(HDASTATE, au32Regs[HDA_NUM_REGS]);
- GEN_CHECK_OFF(HDASTATE, aStreams);
- GEN_CHECK_OFF(HDASTATE, aTags);
+ GEN_CHECK_OFF(HDASTATE, au32Regs[HDA_NREGS]);
+ GEN_CHECK_OFF(HDASTATE, StrmStLineIn);
+ GEN_CHECK_OFF(HDASTATE, StrmStOut);
+ GEN_CHECK_OFF(HDASTATE, StrmStMicIn);
GEN_CHECK_OFF(HDASTATE, u64CORBBase);
GEN_CHECK_OFF(HDASTATE, u64RIRBBase);
GEN_CHECK_OFF(HDASTATE, u64DPBase);
@@ -2003,14 +2004,9 @@ int main()
GEN_CHECK_OFF(HDASTATE, pCodec);
GEN_CHECK_OFF(HDASTATE, lstDrv);
GEN_CHECK_OFF(HDASTATE, pMixer);
- GEN_CHECK_OFF(HDASTATE, SinkFront);
-#ifdef VBOX_WITH_HDA_51_SURROUND
- GEN_CHECK_OFF(HDASTATE, SinkCenterLFE);
- GEN_CHECK_OFF(HDASTATE, SinkRear);
-#endif
- GEN_CHECK_OFF(HDASTATE, SinkLineIn);
+ GEN_CHECK_OFF(HDASTATE, pSinkLineIn);
#ifdef VBOX_WITH_HDA_MIC_IN
- GEN_CHECK_OFF(HDASTATE, SinkMicIn);
+ GEN_CHECK_OFF(HDASTATE, pSinkMicIn);
#endif
GEN_CHECK_OFF(HDASTATE, u64BaseTS);
GEN_CHECK_OFF(HDASTATE, u8RespIntCnt);
diff --git a/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp b/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp
index 6eda39e..0f3a2f3 100644
--- a/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp
+++ b/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp
@@ -145,19 +145,62 @@ private:
RTDIRENTRY m_DirEntry;
};
+
+BugReportFilter::BugReportFilter() : m_pvBuffer(0), m_cbBuffer(0)
+{
+}
+
+BugReportFilter::~BugReportFilter()
+{
+ if (m_pvBuffer)
+ RTMemFree(m_pvBuffer);
+}
+
+void *BugReportFilter::allocateBuffer(size_t cbNeeded)
+{
+ if (m_pvBuffer)
+ {
+ if (cbNeeded > m_cbBuffer)
+ RTMemFree(m_pvBuffer);
+ else
+ return m_pvBuffer;
+ }
+ m_pvBuffer = RTMemAlloc(cbNeeded);
+ if (!m_pvBuffer)
+ throw RTCError(com::Utf8StrFmt("Failed to allocate %ld bytes\n", cbNeeded));
+ m_cbBuffer = cbNeeded;
+ return m_pvBuffer;
+}
+
+
/*
* An abstract class serving as the root of the bug report item tree.
*/
BugReportItem::BugReportItem(const char *pszTitle)
{
m_pszTitle = RTStrDup(pszTitle);
+ m_filter = 0;
}
BugReportItem::~BugReportItem()
{
+ if (m_filter)
+ delete m_filter;
RTStrFree(m_pszTitle);
}
+void BugReportItem::addFilter(BugReportFilter *filter)
+{
+ m_filter = filter;
+}
+
+void *BugReportItem::applyFilter(void *pvSource, size_t *pcbInOut)
+{
+ if (m_filter)
+ return m_filter->apply(pvSource, pcbInOut);
+ return pvSource;
+}
+
const char * BugReportItem::getTitle(void)
{
return m_pszTitle;
@@ -183,8 +226,10 @@ int BugReport::getItemCount(void)
return (int)m_Items.size();
}
-void BugReport::addItem(BugReportItem* item)
+void BugReport::addItem(BugReportItem* item, BugReportFilter *filter)
{
+ if (filter)
+ item->addFilter(filter);
if (item)
m_Items.append(item);
}
@@ -200,6 +245,11 @@ void BugReport::process(void)
RTPrintf("100%% - compressing...\n\n");
}
+void *BugReport::applyFilters(BugReportItem* item, void *pvSource, size_t *pcbInOut)
+{
+ return item->applyFilter(pvSource, pcbInOut);
+}
+
BugReportStream::BugReportStream(const char *pszTitle) : BugReportItem(pszTitle)
{
@@ -330,6 +380,84 @@ PRTSTREAM BugReportCommand::getStream(void)
}
+BugReportCommandTemp::BugReportCommandTemp(const char *pszTitle, const char *pszExec, ...)
+ : BugReportItem(pszTitle), m_Strm(NULL)
+{
+ handleRtError(RTPathTemp(m_szFileName, RTPATH_MAX),
+ "Failed to obtain path to temporary folder");
+ handleRtError(RTPathAppend(m_szFileName, RTPATH_MAX, "BugRepXXXXX.tmp"),
+ "Failed to append path");
+ handleRtError(RTFileCreateTemp(m_szFileName, 0600),
+ "Failed to create temporary file '%s'", m_szFileName);
+
+ unsigned cArgs = 0;
+ m_papszArgs[cArgs++] = RTStrDup(pszExec);
+
+ const char *pszArg;
+ va_list va;
+ va_start(va, pszExec);
+ do
+ {
+ if (cArgs >= RT_ELEMENTS(m_papszArgs) - 1)
+ {
+ va_end(va);
+ throw RTCError(com::Utf8StrFmt("Too many arguments (%u > %u)\n", cArgs+1, RT_ELEMENTS(m_papszArgs)));
+ }
+ pszArg = va_arg(va, const char *);
+ m_papszArgs[cArgs++] = RTStrDup(pszArg ? pszArg : m_szFileName);
+ } while (pszArg);
+ va_end(va);
+
+ m_papszArgs[cArgs++] = NULL;
+}
+
+BugReportCommandTemp::~BugReportCommandTemp()
+{
+ if (m_Strm)
+ RTStrmClose(m_Strm);
+ RTFileDelete(m_szErrFileName);
+ RTFileDelete(m_szFileName);
+ for (size_t i = 0; i < RT_ELEMENTS(m_papszArgs) && m_papszArgs[i]; ++i)
+ RTStrFree(m_papszArgs[i]);
+}
+
+PRTSTREAM BugReportCommandTemp::getStream(void)
+{
+ handleRtError(RTPathTemp(m_szErrFileName, RTPATH_MAX),
+ "Failed to obtain path to temporary folder");
+ handleRtError(RTPathAppend(m_szErrFileName, RTPATH_MAX, "BugRepErrXXXXX.tmp"),
+ "Failed to append path");
+ handleRtError(RTFileCreateTemp(m_szErrFileName, 0600),
+ "Failed to create temporary file '%s'", m_szErrFileName);
+
+ RTHANDLE hStdOutErr;
+ hStdOutErr.enmType = RTHANDLETYPE_FILE;
+ handleRtError(RTFileOpen(&hStdOutErr.u.hFile, m_szErrFileName,
+ RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE),
+ "Failed to open temporary file '%s'", m_szErrFileName);
+
+ /* Remove the output file to prevent errors or confirmation prompts */
+ handleRtError(RTFileDelete(m_szFileName),
+ "Failed to delete temporary file '%s'", m_szFileName);
+
+ RTPROCESS hProcess;
+ handleRtError(RTProcCreateEx(m_papszArgs[0], m_papszArgs, RTENV_DEFAULT, 0,
+ NULL, &hStdOutErr, &hStdOutErr,
+ NULL, NULL, &hProcess),
+ "Failed to create process '%s'", m_papszArgs[0]);
+ RTPROCSTATUS status;
+ handleRtError(RTProcWait(hProcess, RTPROCWAIT_FLAGS_BLOCK, &status),
+ "Process wait failed");
+ RTFileClose(hStdOutErr.u.hFile);
+
+ if (status.enmReason == RTPROCEXITREASON_NORMAL && status.iStatus == 0)
+ handleRtError(RTStrmOpen(m_szFileName, "r", &m_Strm), "Failed to open '%s'", m_szFileName);
+ else
+ handleRtError(RTStrmOpen(m_szErrFileName, "r", &m_Strm), "Failed to open '%s'", m_szErrFileName);
+ return m_Strm;
+}
+
+
BugReportText::BugReportText(const char *pszFileName) : BugReport(pszFileName)
{
handleRtError(RTStrmOpen(pszFileName, "w", &m_StrmTxt),
@@ -368,7 +496,7 @@ void BugReportText::processItem(BugReportItem* item)
cbRead = cbWritten = 0;
while (RT_SUCCESS(rc = RTStrmReadEx(strmIn, buf, sizeof(buf), &cbRead)) && cbRead)
{
- rc = RTStrmWriteEx(m_StrmTxt, buf, cbRead, &cbWritten);
+ rc = RTStrmWriteEx(m_StrmTxt, applyFilters(item, buf, &cbRead), cbRead, &cbWritten);
if (RT_FAILURE(rc) || cbRead != cbWritten)
throw RTCError(com::Utf8StrFmt("Write failure (rc=%d, cbRead=%lu, cbWritten=%lu)\n",
rc, cbRead, cbWritten));
@@ -443,7 +571,7 @@ void BugReportTarGzip::processItem(BugReportItem* item)
RT_SUCCESS(rc = RTStrmReadEx(strmIn, buf, sizeof(buf), &cbRead)) && cbRead;
offset += cbRead)
{
- handleRtError(RTTarFileWriteAt(m_hTarFile, offset, buf, cbRead, NULL),
+ handleRtError(RTTarFileWriteAt(m_hTarFile, offset, applyFilters(item, buf, &cbRead), cbRead, NULL),
"Failed to write %u bytes to TAR", cbRead);
}
}
diff --git a/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.h b/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.h
index 2e065bb..073113a 100644
--- a/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.h
+++ b/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.h
@@ -85,6 +85,29 @@ private:
/*
+ * An abstract class serving as the root of the bug report filter tree.
+ * A child provides an implementation of the 'apply' method. A child
+ * should modify the input buffer (provided via pvSource) in place, or
+ * allocate a new buffer via 'allocateBuffer'. Allocated buffers are
+ * released automatically when another buffer is allocated, which means
+ * that NEXT CALL TO 'APPLY' INVALIDATES BUFFERS RETURNED IN PREVIOUS
+ * CALLS!
+ */
+class BugReportFilter
+{
+public:
+ BugReportFilter();
+ virtual ~BugReportFilter();
+ virtual void *apply(void *pvSource, size_t *pcbInOut) = 0;
+protected:
+ void *allocateBuffer(size_t cbNeeded);
+private:
+ void *m_pvBuffer;
+ size_t m_cbBuffer;
+};
+
+
+/*
* An abstract class serving as the root of the bug report item tree.
*/
class BugReportItem
@@ -94,8 +117,11 @@ public:
virtual ~BugReportItem();
virtual const char *getTitle(void);
virtual PRTSTREAM getStream(void) = 0;
+ void addFilter(BugReportFilter *filter);
+ void *applyFilter(void *pvSource, size_t *pcbInOut);
private:
char *m_pszTitle;
+ BugReportFilter *m_filter;
};
/*
@@ -107,9 +133,10 @@ public:
BugReport(const char *pszFileName);
virtual ~BugReport();
- void addItem(BugReportItem* item);
+ void addItem(BugReportItem* item, BugReportFilter *filter = 0);
int getItemCount(void);
void process();
+ void *applyFilters(BugReportItem* item, void *pvSource, size_t *pcbInOut);
virtual void processItem(BugReportItem* item) = 0;
virtual void complete(void) = 0;
@@ -223,6 +250,21 @@ private:
char *m_papszArgs[32];
};
+/*
+ * A base class for item classes that provide temp output file to a command.
+ */
+class BugReportCommandTemp : public BugReportItem
+{
+public:
+ BugReportCommandTemp(const char *pszTitle, const char *pszExec, ...);
+ virtual ~BugReportCommandTemp();
+ virtual PRTSTREAM getStream(void);
+private:
+ PRTSTREAM m_Strm;
+ char m_szFileName[RTPATH_MAX];
+ char m_szErrFileName[RTPATH_MAX];
+ char *m_papszArgs[32];
+};
/* Platform-specific */
diff --git a/src/VBox/Frontends/VBoxBugReport/VBoxBugReportWin.cpp b/src/VBox/Frontends/VBoxBugReport/VBoxBugReportWin.cpp
index cac11f6..f2ac315 100644
--- a/src/VBox/Frontends/VBoxBugReport/VBoxBugReportWin.cpp
+++ b/src/VBox/Frontends/VBoxBugReport/VBoxBugReportWin.cpp
@@ -533,6 +533,11 @@ void BugReportUsbTreeWin::enumerate()
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (int i = 0; SetupDiEnumDeviceInfo(m_hDevInfo, i, &deviceInfoData); ++i)
{
+ if (m_hHostCtrlDev != INVALID_HANDLE_VALUE)
+ CloseHandle(m_hHostCtrlDev);
+ if (m_pDetailData)
+ RTMemFree(m_pDetailData);
+
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiEnumDeviceInterfaces(m_hDevInfo, 0, (LPGUID)&GUID_DEVINTERFACE_USB_HOST_CONTROLLER,
@@ -693,6 +698,41 @@ void BugReportDriversWin::enumerateDrivers()
}
+class BugReportFilterRegistryWin : public BugReportFilter
+{
+public:
+ BugReportFilterRegistryWin() {};
+ virtual ~BugReportFilterRegistryWin() {};
+ virtual void *apply(void *pvSource, size_t *pcbInOut);
+};
+
+void *BugReportFilterRegistryWin::apply(void *pvSource, size_t *pcbInOut)
+{
+ /*
+ * The following implementation is not optimal by any means. It serves to
+ * illustrate and test the case when filter's output is longer than its
+ * input.
+ */
+ RT_NOREF(pcbInOut);
+ /* Registry export files are encoded in UTF-16 (little endian on Intel x86). */
+ void *pvDest = pvSource;
+ uint16_t *pwsSource = (uint16_t *)pvSource;
+ if (*pwsSource++ == 0xFEFF && *pcbInOut > 48)
+ {
+ if (!memcmp(pwsSource, L"Windows Registry Editor", 46))
+ {
+ *pcbInOut += 2;
+ pvDest = allocateBuffer(*pcbInOut);
+ uint16_t *pwsDest = (uint16_t *)pvDest;
+ *pwsDest++ = 0xFEFF;
+ *pwsDest++ = '#';
+ /* Leave space for 0xFEFF and '#' */
+ memcpy(pwsDest, pwsSource, *pcbInOut - 4);
+ }
+ }
+ return pvDest;
+}
+
void createBugReportOsSpecific(BugReport* report, const char *pszHome)
{
@@ -718,6 +758,16 @@ void createBugReportOsSpecific(BugReport* report, const char *pszHome)
"qfe", "list", "brief", NULL));
report->addItem(new BugReportCommand("DriverServices", PathJoin(WinSysDir.c_str(), "sc.exe"),
"query", "type=", "driver", "state=", "all", NULL));
+ report->addItem(new BugReportCommand("DriverStore", PathJoin(WinSysDir.c_str(), "pnputil.exe"), "-e", NULL));
+ report->addItem(new BugReportCommandTemp("RegDevKeys", PathJoin(WinSysDir.c_str(), "reg.exe"), "export",
+ "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\Root\\NET", NULL),
+ new BugReportFilterRegistryWin());
+ report->addItem(new BugReportCommandTemp("RegDrvKeys", PathJoin(WinSysDir.c_str(), "reg.exe"), "export",
+ "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", NULL),
+ new BugReportFilterRegistryWin());
+ report->addItem(new BugReportCommandTemp("RegNetwork", PathJoin(WinSysDir.c_str(), "reg.exe"), "export",
+ "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}", NULL),
+ new BugReportFilterRegistryWin());
report->addItem(new BugReportUsbTreeWin);
report->addItem(new BugReportDriversWin);
}
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
index 3c92614..03a6b21 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
@@ -670,6 +670,8 @@ RTEXITCODE handleModifyMedium(HandlerArg *a)
// new medium size in MB not Byte. If the operation is started and then
// aborted by the user, the result is most likely a medium which doesn't
// work anymore.
+ MediumState_T state;
+ pMedium->RefreshState(&state);
LONG64 logicalSize;
pMedium->COMGETTER(LogicalSize)(&logicalSize);
if (cbResize > (uint64_t)logicalSize * 1000)
@@ -1161,7 +1163,6 @@ HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
/* check for accessibility */
MediumState_T enmState;
CHECK_ERROR_BREAK(pMedium, RefreshState(&enmState));
- pMedium->RefreshState(&enmState);
const char *pszState = "unknown";
switch (enmState)
{
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp
index 4952200..5ed1887 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp
@@ -43,18 +43,35 @@
#ifndef VBOX_ONLY_DOCS
using namespace com;
+static const RTGETOPTDEF g_aHostOnlyCreateOptions[] =
+{
+ { "--machinereadable", 'M', RTGETOPT_REQ_NOTHING },
+};
+
#if defined(VBOX_WITH_NETFLT) && !defined(RT_OS_SOLARIS)
static RTEXITCODE handleCreate(HandlerArg *a)
{
/*
* Parse input.
*/
+ bool fMachineReadable = false;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
- RTGetOptInit(&GetState, a->argc, a->argv, NULL, 0, 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
- int ch = RTGetOpt(&GetState, &ValueUnion);
- if (ch != 0)
- return errorGetOpt(USAGE_HOSTONLYIFS, ch, &ValueUnion);
+ RTGetOptInit(&GetState, a->argc, a->argv, g_aHostOnlyCreateOptions,
+ RT_ELEMENTS(g_aHostOnlyCreateOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
+ int c;
+ while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
+ {
+ switch (c)
+ {
+ case 'M': // --machinereadable
+ fMachineReadable = true;
+ break;
+
+ default:
+ return errorGetOpt(USAGE_HOSTONLYIFS, c, &ValueUnion);
+ }
+ }
/*
* Do the work.
@@ -67,14 +84,23 @@ static RTEXITCODE handleCreate(HandlerArg *a)
CHECK_ERROR2I_RET(host, CreateHostOnlyNetworkInterface(hif.asOutParam(), progress.asOutParam()), RTEXITCODE_FAILURE);
- /*HRESULT hrc =*/ showProgress(progress);
- CHECK_PROGRESS_ERROR_RET(progress, ("Failed to create the host-only adapter"), RTEXITCODE_FAILURE);
+ if (fMachineReadable)
+ {
+ CHECK_PROGRESS_ERROR_RET(progress, (""), RTEXITCODE_FAILURE);
+ }
+ else
+ {
+ /*HRESULT hrc =*/ showProgress(progress);
+ CHECK_PROGRESS_ERROR_RET(progress, ("Failed to create the host-only adapter"), RTEXITCODE_FAILURE);
+ }
Bstr bstrName;
CHECK_ERROR2I(hif, COMGETTER(Name)(bstrName.asOutParam()));
- RTPrintf("Interface '%ls' was successfully created\n", bstrName.raw());
-
+ if (fMachineReadable)
+ RTPrintf("%ls", bstrName.raw());
+ else
+ RTPrintf("Interface '%ls' was successfully created\n", bstrName.raw());
return RTEXITCODE_SUCCESS;
}
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
index 3777ede..1b4cd61 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
@@ -2587,7 +2587,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> pVirtualBox,
if (!description.isEmpty())
{
if (details == VMINFO_MACHINEREADABLE)
- RTPrintf("description=\"%ls\"\n", description.raw());
+ outputMachineReadableString("description", &description);
else
RTPrintf("Description:\n%ls\n", description.raw());
}
diff --git a/src/VBox/Frontends/VirtualBox/VBoxUI.pro b/src/VBox/Frontends/VirtualBox/VBoxUI.pro
index bfa91d0..35b27f1 100644
--- a/src/VBox/Frontends/VirtualBox/VBoxUI.pro
+++ b/src/VBox/Frontends/VirtualBox/VBoxUI.pro
@@ -84,6 +84,7 @@ TRANSLATIONS = \
nls/VirtualBox_sl.ts \
nls/VirtualBox_sr.ts \
nls/VirtualBox_sv.ts \
+ nls/VirtualBox_th.ts \
nls/VirtualBox_tr.ts \
nls/VirtualBox_uk.ts \
nls/VirtualBox_zh_CN.ts \
diff --git a/src/VBox/Frontends/VirtualBox/nls/ApprovedLanguages.kmk b/src/VBox/Frontends/VirtualBox/nls/ApprovedLanguages.kmk
index 7fc2ba2..71a1c71 100644
--- a/src/VBox/Frontends/VirtualBox/nls/ApprovedLanguages.kmk
+++ b/src/VBox/Frontends/VirtualBox/nls/ApprovedLanguages.kmk
@@ -38,6 +38,7 @@ VBOX_APPROVED_GUI_LANGUAGES := \
pt_BR \
ru \
sl \
+ th \
tr \
uk \
zh_CN \
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts
index 5b6312c..ed61acd 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_bg.ts
@@ -2524,6 +2524,10 @@
<source>Downloading %1...</source>
<translation>Изтегляне на %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10734,6 +10738,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -13408,11 +13420,11 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Указва името или пълния път до папката на виртуалната машина, която предстои да създадете.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Указва името или пълния път до папката на виртуалната машина, която предстои да създадете.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Предстои да създадете виртуална машина в следната папка:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Предстои да създадете виртуална машина в следната папка:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts
index 078e601..163dbdd 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca.ts
@@ -1217,6 +1217,10 @@
<source>Downloading %1...</source>
<translation>S'està baixant %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -5303,11 +5307,11 @@
</message>
<message>
<source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p></source>
- <translation><p>No s'ha pogut canviar la pantalla del client a aquest patalla de l'amfitrió perquè no hi ha memòria de vídeo suficient.</p><p>Haureu de configurar la màquina virtual per tal que tingui un mínim de <b>%1</b> de memòria de vídeo.</p></translation>
+ <translation><p>No s'ha pogut canviar la pantalla del client a aquest pantalla de l'amfitrió perquè no hi ha memòria de vídeo suficient.</p><p>Haureu de configurar la màquina virtual per tal que tingui un mínim de <b>%1</b> de memòria de vídeo.</p></translation>
</message>
<message>
<source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p><p>Press <b>Ignore</b> to switch the screen anyway or press <b>Cancel</b> to cancel the operation.</p></source>
- <translation><p>No s'ha pogut canviar la pantalla del client a aquest patalla de l'amfitrió perquè no hi ha memòria de vídeo suficient.</p><p>Haureu de configurar la màquina virtual per tal que tingui almenys <b>%1</b> de memòria de vídeo.</p><p>Premeu <b>Ignora</b> per canviar la pantalla de totes maneres o premeu <b>Cancel·la</b> per cancel·lar l'operació.</p></translation>
+ <translation><p>No s'ha pogut canviar la pantalla del client a aquest pantalla de l'amfitrió perquè no hi ha memòria de vídeo suficient.</p><p>Haureu de configurar la màquina virtual per tal que tingui almenys <b>%1</b> de memòria de vídeo.</p><p>Premeu <b>Ignora</b> per canviar la pantalla de totes maneres o premeu <b>Cancel·la</b> per cancel·lar l'operació.</p></translation>
</message>
<message>
<source>Failed to open virtual machine located in %1.</source>
@@ -5958,6 +5962,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniToolBar</name>
@@ -7397,14 +7409,6 @@
<source>Choose a virtual hard disk file...</source>
<translation>Selecciona un fitxer de disc dur virtual...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts
index 73a82a9..b3d6912 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ca_VA.ts
@@ -2488,6 +2488,10 @@
<source>Downloading %1...</source>
<translation>S'està baixant %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10053,11 +10057,11 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p></source>
- <translation><p>No s'ha pogut canviar la pantalla del client a este patalla de l'amfitrió perquè no hi ha memòria de vídeo suficient.</p><p>Haureu de configurar la màquina virtual per tal que tinga un mínim de <b>%1</b> de memòria de vídeo.</p></translation>
+ <translation><p>No s'ha pogut canviar la pantalla del client a este pantalla de l'amfitrió perquè no hi ha memòria de vídeo suficient.</p><p>Haureu de configurar la màquina virtual per tal que tinga un mínim de <b>%1</b> de memòria de vídeo.</p></translation>
</message>
<message>
<source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p><p>Press <b>Ignore</b> to switch the screen anyway or press <b>Cancel</b> to cancel the operation.</p></source>
- <translation><p>No s'ha pogut canviar la pantalla del client a este patalla de l'amfitrió perquè no hi ha memòria de vídeo suficient.</p><p>Haureu de configurar la màquina virtual per tal que tinga almenys <b>%1</b> de memòria de vídeo.</p><p>Premeu <b>Ignora</b> per canviar la pantalla de totes maneres o premeu <b>Cancel·la</b> per cancel·lar l'operació.</p></translation>
+ <translation><p>No s'ha pogut canviar la pantalla del client a este pantalla de l'amfitrió perquè no hi ha memòria de vídeo suficient.</p><p>Haureu de configurar la màquina virtual per tal que tinga almenys <b>%1</b> de memòria de vídeo.</p><p>Premeu <b>Ignora</b> per canviar la pantalla de totes maneres o premeu <b>Cancel·la</b> per cancel·lar l'operació.</p></translation>
</message>
<message>
<source><p>Can not switch the guest display to fullscreen mode. You have more virtual screens configured than physical screens are attached to your host.</p><p>Please either lower the virtual screens in your VM configuration or attach additional screens to your host.</p></source>
@@ -10919,6 +10923,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -13745,14 +13757,6 @@ pas i connectar discos durs més avant, fent servir el diàleg de configuració
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts
index 9d3731d..a0c2752 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_cs.ts
@@ -2508,6 +2508,10 @@
<source>Downloading %1...</source>
<translation>Stahuji %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10872,6 +10876,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -13730,14 +13742,6 @@ krok a připojit pevné disky později použitím dialogu Nastavení VM.</p&g
<source>Choose a virtual hard disk file...</source>
<translation>Vyberte virtuální obraz disku...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts
index e25b73f..39a86bb 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_da.ts
@@ -2411,6 +2411,10 @@
<source>Downloading %1...</source>
<translation>Henter %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10313,6 +10317,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -12920,14 +12932,6 @@ p, li { white-space: pre-wrap; }
<source>Choose a virtual hard disk file...</source>
<translation>Vælg en virtuel harddisk-fil...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts
index fbf8fb2..3482d18 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_de.ts
@@ -339,7 +339,7 @@
</message>
<message>
<source>&Group</source>
- <translation>&Gruppieren</translation>
+ <translation>&Gruppe</translation>
</message>
<message>
<source>S&tart</source>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts
index 02750c3..5b677bb 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_el.ts
@@ -1218,6 +1218,10 @@
<source>Downloading %1...</source>
<translation>Κατεβάζω το %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -5965,6 +5969,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation>Ο λόγος γι' αυτό το λάθος είναι μάλλον λάθος δικαιώματα της υποδοχής του δαίμονα IPC εξ αιτίας προβλημάτων στην εγκατάσταση. Ελέξτε τα δικαιώματα στα <font color=blue>'/tmp'</font> και <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniToolBar</name>
@@ -7414,11 +7426,11 @@
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Δείχνει την πλήρη διαδρομή του φακέλου της εικονικής μηχανής που θα δημιουργήσετε.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Δείχνει την πλήρη διαδρομή του φακέλου της εικονικής μηχανής που θα δημιουργήσετε.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Πρόκειται να δημιουργήσετε την εικονική μηχανή στον ακόλουθο φάκελο:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Πρόκειται να δημιουργήσετε την εικονική μηχανή στον ακόλουθο φάκελο:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts
index d098023..ad7907c 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_es.ts
@@ -1155,7 +1155,7 @@
</message>
<message>
<source>&Full-screen Mode</source>
- <translation>Modo patalla &completa</translation>
+ <translation>Modo pantalla &completa</translation>
</message>
<message>
<source>Switch between normal and full-screen mode</source>
@@ -2622,6 +2622,10 @@
<source>Downloading %1...</source>
<translation>Descargando %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -11087,6 +11091,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -14040,11 +14052,11 @@ este paso y luego conectar los Discos Duros desde el diálogo de Configuración
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Contiene el nombre o ruta completa a la carpeta de la máquina virtual que está apunto de crear.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Contiene el nombre o ruta completa a la carpeta de la máquina virtual que está apunto de crear.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Está apunto de crear la máquina virtual en la siguiente carpeta:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Está apunto de crear la máquina virtual en la siguiente carpeta:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
index aa0e8c1..21f0f5b 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_eu.ts
@@ -4,7 +4,7 @@
<context>
<name>@@@</name>
<message>
- <location filename="../src/globals/VBoxGlobal.cpp" line="+2065"/>
+ <location filename="../src/globals/VBoxGlobal.cpp" line="+2064"/>
<source>English</source>
<comment>Native language name</comment>
<translation>Euskara</translation>
@@ -468,15 +468,19 @@
<location line="+36"/>
<location line="+31"/>
<location line="+30"/>
+ <location line="+30"/>
+ <location line="+30"/>
<source>&Insert %1</source>
<comment>that means send the %1 key sequence to the virtual machine</comment>
<translation>&Txertatu %1</translation>
</message>
<message>
- <location line="-96"/>
+ <location line="-156"/>
<location line="+36"/>
<location line="+31"/>
<location line="+30"/>
+ <location line="+30"/>
+ <location line="+30"/>
<source>Send the %1 sequence to the virtual machine</source>
<translation>Bidali %1 sekuentzia makina birtualari</translation>
</message>
@@ -558,7 +562,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+780"/>
+ <location line="+782"/>
<source>%1%</source>
<comment>scale-factor</comment>
<translation>%1%</translation>
@@ -588,7 +592,7 @@
<translation type="obsolete">&USB Gailuak</translation>
</message>
<message>
- <location line="-1228"/>
+ <location line="-1230"/>
<source>&Webcams</source>
<translation>&Webkamerak</translation>
</message>
@@ -637,7 +641,7 @@
<translation>&Elkarbanatutako Agiritegi Ezarpenak...</translation>
</message>
<message>
- <location line="-837"/>
+ <location line="-897"/>
<source>R&emote Display</source>
<translation>&Hurruneko Erakuspena</translation>
</message>
@@ -665,7 +669,7 @@
<translation type="obsolete">Itxuratu bideo harpen ezarpenak</translation>
</message>
<message>
- <location line="+931"/>
+ <location line="+991"/>
<source>&Insert Guest Additions CD image...</source>
<translation>&Txertatu Gonbidatu Gehigarrien CD irudia...</translation>
</message>
@@ -761,7 +765,7 @@
<translation type="obsolete">&Aldatu &Irudizko Modura</translation>
</message>
<message>
- <location line="-1379"/>
+ <location line="-1439"/>
<source>Switch between normal and seamless desktop integration mode</source>
<translation>Aldatu modu arruntaren eta irudizko mahaigain baterapen moduaren artean</translation>
</message>
@@ -1498,7 +1502,7 @@
<translation type="obsolete">Antolatu hautaturiko lehen makinaren taldea alfabetikoki</translation>
</message>
<message>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+1173"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+1233"/>
<source>Shared &Clipboard</source>
<translation>&Elkarbanatutako Gakoa</translation>
</message>
@@ -1511,7 +1515,7 @@
<translation type="obsolete">Gorde makina birtualaren egoera</translation>
</message>
<message>
- <location line="-1172"/>
+ <location line="-1232"/>
<source>Power off the virtual machine</source>
<translation>Itzali makina birtuala</translation>
</message>
@@ -1527,7 +1531,7 @@
<translation>Aurreikuspen Monitorea %1</translation>
</message>
<message>
- <location line="+1495"/>
+ <location line="+1533"/>
<source>&Connect Network Adapter</source>
<translation>&Elkarketatu Sare Egokitzailea</translation>
</message>
@@ -2184,7 +2188,7 @@
<context>
<name>UIDownloader</name>
<message>
- <location filename="../src/net/UIDownloader.cpp" line="+73"/>
+ <location filename="../src/net/UIDownloader.cpp" line="+87"/>
<source>Looking for %1...</source>
<translation>Bilatzen %1...</translation>
</message>
@@ -2193,16 +2197,21 @@
<source>Downloading %1...</source>
<translation>Jeisten %1...</translation>
</message>
+ <message>
+ <location line="+1"/>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
<message>
- <location filename="../src/net/UIDownloaderAdditions.cpp" line="+137"/>
+ <location filename="../src/net/UIDownloaderAdditions.cpp" line="+200"/>
<source>Select folder to save Guest Additions image to</source>
<translation>Hautatu Gonbidatu Gehigarri irudia gordetzeko agiritegia</translation>
</message>
<message>
- <location line="-35"/>
+ <location line="-92"/>
<source>VirtualBox Guest Additions</source>
<translation>VirtualBox Gonbidatu Gehigarriak</translation>
</message>
@@ -2210,12 +2219,12 @@
<context>
<name>UIDownloaderExtensionPack</name>
<message>
- <location filename="../src/net/UIDownloaderExtensionPack.cpp" line="+133"/>
+ <location filename="../src/net/UIDownloaderExtensionPack.cpp" line="+183"/>
<source>Select folder to save %1 to</source>
<translation>Hautatu %1 gordetzeko agiritegia</translation>
</message>
<message>
- <location line="-45"/>
+ <location line="-91"/>
<source>VirtualBox Extension Pack</source>
<translation>VirtualBox Hedapen Paketea</translation>
</message>
@@ -3512,7 +3521,7 @@
<translation>Goi Muga</translation>
</message>
<message>
- <location line="+249"/>
+ <location line="+250"/>
<source>The name <b>%1</b> is being used for several NAT networks.</source>
<translation><b>%1</b> izena NAT sare ugarik erabiltzen dute.</translation>
</message>
@@ -3637,8 +3646,8 @@
<translation>Izena</translation>
</message>
<message>
- <location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="+138"/>
- <location line="+52"/>
+ <location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="+139"/>
+ <location line="+53"/>
<source>Networking</source>
<translation>Sareketa</translation>
</message>
@@ -7769,7 +7778,7 @@
<context>
<name>UIMenuBarEditorWidget</name>
<message>
- <location filename="../src/runtime/UIMenuBarEditorWindow.cpp" line="+912"/>
+ <location filename="../src/runtime/UIMenuBarEditorWindow.cpp" line="+926"/>
<source>Virtual Screen Resize</source>
<translation>Ikusleiho Birtual Birneurriratzea</translation>
</message>
@@ -7798,41 +7807,41 @@
<name>UIMessageCenter</name>
<message>
<location filename="../src/globals/UIMessageCenter.cpp" line="-1522"/>
- <location line="+2647"/>
+ <location line="+2669"/>
<source>VirtualBox - Information</source>
<comment>msg box title</comment>
<translation>VirtualBox - Argibideak</translation>
</message>
<message>
- <location line="-2643"/>
- <location line="+2647"/>
+ <location line="-2665"/>
+ <location line="+2669"/>
<source>VirtualBox - Question</source>
<comment>msg box title</comment>
<translation>VirtualBox - Galdera</translation>
</message>
<message>
- <location line="-2643"/>
- <location line="+2647"/>
+ <location line="-2665"/>
+ <location line="+2669"/>
<source>VirtualBox - Warning</source>
<comment>msg box title</comment>
<translation>VirtualBox - Ohartarazpena</translation>
</message>
<message>
- <location line="-2643"/>
- <location line="+2647"/>
+ <location line="-2665"/>
+ <location line="+2669"/>
<source>VirtualBox - Error</source>
<comment>msg box title</comment>
<translation>VirtualBox - Akatsa</translation>
</message>
<message>
- <location line="-2643"/>
- <location line="+2647"/>
+ <location line="-2665"/>
+ <location line="+2669"/>
<source>VirtualBox - Critical Error</source>
<comment>msg box title</comment>
<translation>VirtualBox - Akats Larria</translation>
</message>
<message>
- <location line="-2506"/>
+ <location line="-2528"/>
<source><p>Failed to create the VirtualBoxClient COM object.</p><p>The application will now terminate.</p></source>
<translation><p>Hutsegitea VirtualBox COM objetua sortzerakoan.</p><p>Orain aplikazioak amaitu egingo du.</p></translation>
</message>
@@ -8070,7 +8079,7 @@
<message>
<location line="+3"/>
<location line="+10"/>
- <location line="+40"/>
+ <location line="+51"/>
<location line="+10"/>
<location line="+29"/>
<location line="+10"/>
@@ -8078,7 +8087,7 @@
<translation>Jeitsi</translation>
</message>
<message>
- <location line="-93"/>
+ <location line="-104"/>
<source><p>Are you sure you want to download the <b>VirtualBox Guest Additions</b> disk image file from <nobr><a href="%1">%1</a></nobr> (size %2 bytes)?</p></source>
<translation><p>Zihur zaude VirtualBox Gonbidatu Gehigarriak diska irudia <nobr><a href="%1">%1</a></nobr>-tik (neurria %2 byte) jeistea nahi duzula?</p></translation>
</message>
@@ -8094,7 +8103,7 @@
<translation>Txertatu</translation>
</message>
<message>
- <location line="+6"/>
+ <location line="+17"/>
<source>Failed to update Guest Additions. The Guest Additions disk image file will be inserted for user installation.</source>
<translation>Hutsgitea Gonbidatu Gehigarriak eguneratzerakoan. Gonbidatu Gehigarriak diska irudi agiria txertatuko da erabiltzaileak ezartzeko.</translation>
</message>
@@ -8119,7 +8128,7 @@
<translation><p>VirtualBox Erabiltzaile Eskuliburua ongi jeitsi da hemendik, <nobr><a href="%1">%1</a></nobr> eta tokian bertan gorde da honela <nobr><b>%2</b>.</nobr></p></translation>
</message>
<message>
- <location line="+51"/>
+ <location line="+62"/>
<source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
<translation type="unfinished"></translation>
</message>
@@ -8135,7 +8144,7 @@
<translation>Ez erakutsi mezu hau berriro</translation>
</message>
<message>
- <location line="-2419"/>
+ <location line="-2441"/>
<source>Failed to open <tt>%1</tt>. Make sure your desktop environment can properly handle URLs of this type.</source>
<translation>Hutsegitea <tt>%1</tt> irekitzerakoan. Zihurtatu zure mahaigin inguruak mota honetako URL-ak egoki kudeatu ditzakeela.</translation>
</message>
@@ -8436,7 +8445,17 @@
<translation><p><b>VirtualBox Gonbidatu Gehigarriak</b> diska irudi agiria ongi jeitsi da <nobr><a href="%1">%1</a></nobr>-tik eta tokian bertan gorde da <nobr><b>%2</b> bezala.</nobr></p><p>Nahi duzu diska irudi agiria erregistratzea eta gidagailu optiko birtualean txertatzea?</p></translation>
</message>
<message>
- <location line="+104"/>
+ <location line="+12"/>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+100"/>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
<location line="+9"/>
<source>Delete</source>
<comment>extension pack</comment>
@@ -8499,7 +8518,7 @@
<translation type="obsolete"><p>Ezin da <b><nobr>%1</nobr></b> hizkuntza agiria gertatu. <p>Hizkuntza aldibaterako Ingeleran (barne-eraikita) berrezarriko da. Mesedez joan <b>Hobespenak</b> elkarrizketara VirtualBox leihoko <b>Agiria</b> menutik ireki dezakezuna, eta hautatu <b>Hizkuntza</b> orrialdean dauden hizkuntzetako bat.</p></translation>
</message>
<message>
- <location line="-1627"/>
+ <location line="-1649"/>
<location line="+11"/>
<source><p>Failed to remove the shared folder <b>%1</b> (pointing to <nobr><b>%2</b></nobr>) from the virtual machine <b>%3</b>.</p><p>Please close all programs in the guest OS that may be using this shared folder and try again.</p></source>
<translation><p>Hutsegitea <b>%1</b> elkarbanatutako agiritegia kentzerakoan (hona zuzentzeno <nobr><b>%2</b></nobr>) <b>%3</b> makina birtutaletik.</p><p>Mesedez itxi elkarbanatutako agiritegi hau erabiltzen egon daitezkeen SE gonbidatuko programa guztiak eta saiatu berriro.</p></translation>
@@ -8513,12 +8532,12 @@
<translation type="obsolete">Hutsegitea baimen agiriak aurkitzerakoan, <nobr><b>%1</b></nobr>.</translation>
</message>
<message>
- <location line="+1197"/>
+ <location line="+1219"/>
<source>Failed to open the license file <nobr><b>%1</b></nobr>. Check file permissions.</source>
<translation>Hutsegitea <nobr><b>%1</b></nobr> baimen agiria irekitzerakoan. Egiaztatu agiri baimenak.</translation>
</message>
<message>
- <location line="-1630"/>
+ <location line="-1652"/>
<source>Failed to send the ACPI Power Button press event to the virtual machine <b>%1</b>.</source>
<translation>Hutsegitea ACPI Indar Botoi sakatze gertaera <b>%1</b> makina birtualera bildatzerakoan.</translation>
</message>
@@ -8702,12 +8721,12 @@
<translation><p>Akats larri bat gertatu da makina birtualaren jardunean eta makinaren exekuzioa gelditu egin da.</p><p>Laguntza lortzeko, mesedez ikusi Herkidegoa atala <a href=https://www.virtualbox.org>https://www.virtualbox.org</a> edo zure sostengu itunean. Mesedez hornitu <tt>VBox.log</tt> ohar agiriaren edukiak eta <tt>VBox.png</tt> irudi agiria, hauek <nobr><b>%1</b></nobr> zuzenbidean aurkitu di [...]
</message>
<message>
- <location line="+699"/>
+ <location line="+721"/>
<source>The following files already exist:<br /><br />%1<br /><br />Are you sure you want to replace them? Replacing them will overwrite their contents.</source>
<translation>Jadanik badaude hurrengo agiriak:<br /><br />%1<br /><br />Zihur zaude ordeztea nahi dituzula? Hauek ordezteak beren edukiak gainidaztea eragingo du.</translation>
</message>
<message>
- <location line="-2079"/>
+ <location line="-2101"/>
<source>You are running a prerelease version of VirtualBox. This version is not suitable for production use.</source>
<translation>VirtualBox aurreargitalpen bertsio bat ari zara erabiltzen. Bertsio hau ez da ekoizpen erabilpenerako.</translation>
</message>
@@ -8789,12 +8808,12 @@
<translation><p>Hostalaria-bakarrik sare hau ezabatzeak sare honek ohinarri duen hostalaria-bakarrik interfazea kenduko du. <nobr><b>%1</b> (hostalaria-bakarrik sarea) interfazea kentzea nahi duzu?</nobr></p><p><b>Oharra:</b> egokitzaile birtual bat baino gehiago egon daiteke interfaze hau erabiltzen zure MB-etan. Kendu ondoren, egokitzaile hauek ezingo dira gehiago erabili beren ezarpenak zuzentzen dituzun arte beste interfaz [...]
</message>
<message>
- <location line="+1484"/>
+ <location line="+1506"/>
<source>A file named <b>%1</b> already exists. Are you sure you want to replace it?<br /><br />Replacing it will overwrite its contents.</source>
<translation>Jadanik badago <b>%1</b> izeneko agiri bat. Zihur zaude ordeztea nahi duzula? Ordezteak bere edukiak gainidaztea eragingo du.</translation>
</message>
<message>
- <location line="-618"/>
+ <location line="-640"/>
<source><p>VT-x/AMD-V hardware acceleration has been enabled, but is not operational. Certain guests (e.g. OS/2 and QNX) require this feature.</p><p>Please ensure that you have enabled VT-x/AMD-V properly in the BIOS of your host computer.</p></source>
<translation><p>VT-x/AMD-V hardware bizkorpena gaitu egin da, baina ez dago eraginkor. Zenbait gonbidatuk (adib. OS/2 eta QNX) ezaugarri hau behar dute.</p><p>Mesedez zihurtatu VT-x/AMD-V egoki gaituta duzula zure hostalari ordenagailuaren BIOS-ean.</p></translation>
</message>
@@ -9032,7 +9051,7 @@
<translation>Hutsegitea (<nobr><b>%1</b></nobr>) diska gogorra <b>%3</b> makinaren <i>%2</i> eslotetik deseranstearakoan.</translation>
</message>
<message>
- <location line="+981"/>
+ <location line="+1003"/>
<location line="+8"/>
<source>Failed to install the Extension Pack <b>%1</b>.</source>
<translation>Hutsegitea <b>%1</b> Hedapen Paketea ezartzerakoan.</translation>
@@ -9049,7 +9068,7 @@
<translation>&Kendu</translation>
</message>
<message>
- <location line="-1179"/>
+ <location line="-1201"/>
<source>The current port forwarding rules are not valid. None of the host or guest port values may be set to zero.</source>
<translation>Oraingo berbidalketa ataka arauak ez dira baliozkoak. Hostalari edo gonbidatu ataka balioetako bat ere ezin daiteke hutsean ezarri.</translation>
</message>
@@ -9080,7 +9099,7 @@
<translation type="obsolete">Aldatu</translation>
</message>
<message>
- <location line="+440"/>
+ <location line="+462"/>
<location line="+7"/>
<source>Failed to open the Extension Pack <b>%1</b>.</source>
<translation><b>%1</b> Hedapen Paketea irekitzerakoan.</translation>
@@ -9140,7 +9159,7 @@
<translation><br><nobr><b>%1</b><nobr><br> hedapen paketea ongi ezarri da.</translation>
</message>
<message>
- <location line="-824"/>
+ <location line="-846"/>
<source><p>Cannot create the machine folder <b>%1</b> in the parent folder <nobr><b>%2</b>.</nobr></p><p>Please check that the parent really exists and that you have permissions to create the machine folder.</p></source>
<translation><p>Ezin da makinaren <b>%1</b> agiritegia sortu gaineko <nobr><b>%2</b> agiritegian.</nobr></p><p>Mesedez egiaztatu gainekoa egitan dagoela eta makina agiritegia sortzeko baimena duzula.</p></translation>
</message>
@@ -9185,7 +9204,7 @@
<translation type="obsolete">Barkatu, zenbati akats generiko gertatu dira.</translation>
</message>
<message>
- <location line="+1937"/>
+ <location line="+1959"/>
<source>Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer</source>
<translation>Ezin da Hostalari USB Proxy Zerbitzua gertatu (VERR_FILE_NOT_FOUND). Badaiteke zerbitzua hostalari ordenagailuan ezarrita ez egotea</translation>
</message>
@@ -9210,7 +9229,7 @@
<translation>Ezin da Hostalari USB Proxy zerbitzua gertatu</translation>
</message>
<message>
- <location line="-1123"/>
+ <location line="-1145"/>
<source>Can't find snapshot named <b>%1</b>.</source>
<translation>Ezin da<b>%1</b> izeneko berehalakoa aurkitu.</translation>
</message>
@@ -9219,7 +9238,7 @@
<translation type="obsolete"><p>Hutsegitea jeitsitako agiria gordetzerakoan,<nobr><b>%1</b>.</nobr></p></translation>
</message>
<message>
- <location line="+544"/>
+ <location line="+555"/>
<source><p>You have an old version (%1) of the <b><nobr>%2</nobr></b> installed.</p><p>Do you wish to download latest one from the Internet?</p></source>
<translation><p><b><nobr>%2</nobr></b>-ren bertsio zahar bat (%1) duzu ezarrita.</p><p>Nahi duzu azkenengoa Internetetik jeistea?</p></translation>
</message>
@@ -9240,18 +9259,18 @@
</message>
<message>
<location line="+6"/>
- <location line="+37"/>
+ <location line="+48"/>
<source>Install</source>
<comment>extension pack</comment>
<translation>Ezarri</translation>
</message>
<message>
- <location line="-53"/>
+ <location line="-64"/>
<source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> but can't be saved locally as <nobr><b>%3</b>.</nobr></p><p>Please choose another location for that file.</p></source>
<translation><p><b><nobr>%1</nobr></b> ongi jeitsi da <nobr><a href="%2">%2</a></nobr>-tik baina ezin da tokian gorde <nobr><b>%3</b> bezala.</nobr></p><p>Mesedez hautatu beste kokaleku bat agiriarentzat.</p></translation>
</message>
<message>
- <location line="-116"/>
+ <location line="-127"/>
<source><p>You have version %1 of the <b><nobr>%2</nobr></b> installed.</p><p>You should download and install version %3 of this extension pack from Oracle!</p></source>
<translation><p><b><nobr>%2</nobr></b>-ren %1 bertsioa duzu ezarrita.</p><p> Hedapen pakete honen %3 bertsioa jeitsi eta ezarri behar duzu Oracle-tik!</p></translation>
</message>
@@ -9408,7 +9427,7 @@
<context>
<name>UIMultiScreenLayout</name>
<message>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+2134"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+2196"/>
<location line="+15"/>
<location line="+47"/>
<source>Virtual Screen %1</source>
@@ -9697,7 +9716,7 @@
<translation>Gonbidatu Ataka</translation>
</message>
<message>
- <location line="+395"/>
+ <location line="+394"/>
<source>Contains a list of port forwarding rules.</source>
<translation>Berbidalketa ataka arauen zerrenda bat du.</translation>
</message>
@@ -9770,7 +9789,7 @@
<context>
<name>UISelectorWindow</name>
<message>
- <location filename="../src/selector/UISelectorWindow.cpp" line="+160"/>
+ <location filename="../src/selector/UISelectorWindow.cpp" line="+161"/>
<source>Show Toolbar</source>
<translation>Erakutsi Tresnabarra</translation>
</message>
@@ -9780,7 +9799,7 @@
<translation>Erakutsi Egoerabarra</translation>
</message>
<message>
- <location line="+338"/>
+ <location line="+342"/>
<source>Select a virtual machine file</source>
<translation>Hautatu makina birtual agiria</translation>
</message>
@@ -9790,12 +9809,12 @@
<translation>Makina birtual agiriak (%1)</translation>
</message>
<message>
- <location line="-231"/>
+ <location line="-235"/>
<source><h3>Welcome to VirtualBox!</h3><p>The left part of this window is a list of all virtual machines on your computer. The list is empty now because you haven't created any virtual machines yet.<img src=:/welcome.png align=right/></p><p>In order to create a new virtual machine, press the <b>New</b> button in the main tool bar located at the top of the window.</p><p>You can press the <b>%1</b> key to [...]
<translation><h3>Ongi etorri VirtualBox-era!</h3><p>Leiho honetako ezker aldea zure ordenagailuko makina birtualen zerrenda bat da. Zerrenda orain hutsik dago oraindik ez duzulako makina birtualik sortu.<img src=:/welcome.png align=right/></p><p>Makina birtual berri bat sortzeko, sakatu <b>Berria</b> botoia leihoaren goialdeko tresna barra nagusian.</p><p><b>%1</b> tekla sakatu dezakezu berehalako laguntza lo [...]
</message>
<message>
- <location line="+781"/>
+ <location line="+785"/>
<source>Manager</source>
<comment>Note: main window title which is pretended by the product name.</comment>
<translation>Kudeatzailea</translation>
@@ -9821,7 +9840,7 @@
<translation type="obsolete"><b>%1</b> orrialdean, %2</translation>
</message>
<message>
- <location filename="../src/settings/UISettingsDialog.cpp" line="+348"/>
+ <location filename="../src/settings/UISettingsDialog.cpp" line="+356"/>
<source>Invalid settings detected</source>
<translation>Ezarpen baliogabea atzeman da</translation>
</message>
@@ -9977,7 +9996,7 @@
<context>
<name>UISettingsSerializerProgress</name>
<message>
- <location filename="../src/settings/UISettingsSerializer.cpp" line="+339"/>
+ <location filename="../src/settings/UISettingsSerializer.cpp" line="+340"/>
<source>Loading Settings...</source>
<translation>Ezarpenak Gertatzen...</translation>
</message>
@@ -10094,7 +10113,7 @@
<context>
<name>UIUpdateStepVirtualBox</name>
<message>
- <location filename="../src/net/UIUpdateManager.cpp" line="+173"/>
+ <location filename="../src/net/UIUpdateManager.cpp" line="+176"/>
<source>Checking for a new VirtualBox version...</source>
<translation>VirtualBox bertsio berririk dagoen egiaztatzen...</translation>
</message>
@@ -11397,18 +11416,8 @@
<translation>Sortu</translation>
</message>
<message>
- <location filename="../src/wizards/newvm/UIWizardNewVMPageBasic1.cpp" line="+215"/>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+10"/>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location line="+130"/>
- <location filename="../src/wizards/newvm/UIWizardNewVMPageExpert.cpp" line="+238"/>
+ <location filename="../src/wizards/newvm/UIWizardNewVMPageBasic1.cpp" line="+308"/>
+ <location filename="../src/wizards/newvm/UIWizardNewVMPageExpert.cpp" line="+227"/>
<source>Name and operating system</source>
<translation>Izena eta sistema eragilea</translation>
</message>
@@ -13393,7 +13402,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+662"/>
+ <location line="+666"/>
<location line="+30"/>
<source>General</source>
<comment>DetailsElementType</comment>
@@ -13624,7 +13633,7 @@
<translation>Disketa birtual agiri guztiak (%1)</translation>
</message>
<message>
- <location line="+2056"/>
+ <location line="+2100"/>
<source>VDI (VirtualBox Disk Image)</source>
<translation>VDI (VirtualBox Diska Irudia)</translation>
</message>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts
index 428f664..2e6b36c 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fa_IR.ts
@@ -1867,6 +1867,10 @@
<source>Downloading %1...</source>
<translation>درحال دانلود %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -8149,6 +8153,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniToolBar</name>
@@ -9866,14 +9878,6 @@
<source>Choose a virtual hard disk file...</source>
<translation>یک فایل ديسک سخت مجازی انتخاب کنید...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts
index 57e414c..50690d3 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fi.ts
@@ -1868,6 +1868,10 @@
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -8804,6 +8808,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -10934,14 +10946,6 @@ Kaikki VirtualBoxin komponentit käyttävät sitä koneen tunnistukseen.</p&g
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts
index 06550ea..5895af3 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_fr.ts
@@ -2411,6 +2411,10 @@
<source>Downloading %1...</source>
<translation>Téléchargement de %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9675,6 +9679,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -12006,14 +12018,6 @@ And the size is not necessarily "in megabytes", the slider chooses the
<source>Choose a virtual hard disk file...</source>
<translation>Choisissez un fichier de disque dur virtuel...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts
index 257d843..aaab468 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_gl_ES.ts
@@ -1865,6 +1865,10 @@
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -8692,6 +8696,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -10737,14 +10749,6 @@ p, li { white-space: pre-wrap; }
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts
index 68edf50..87002ab 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_he.ts
@@ -1372,6 +1372,10 @@
<source>Downloading %1...</source>
<translation>כעת מוריד את %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -6289,6 +6293,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniToolBar</name>
@@ -7817,14 +7829,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Hard disk</source>
<translation type="unfinished"></translation>
</message>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts
index 3d38c2a..6a3ed73 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_hu.ts
@@ -2530,6 +2530,10 @@
<source>Downloading %1...</source>
<translation>%1 letöltése...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10718,6 +10722,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -13508,14 +13520,6 @@ esetleg a <b>Létező</b> gombbal a Virtuális lemezkezelőből.<
<source>Choose a virtual hard disk file...</source>
<translation>Virtuális merevlemez választása...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
index 52bf820..af657ce 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_id.ts
@@ -2339,6 +2339,10 @@
<source>Downloading %1...</source>
<translation>Mengunduh %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9256,7 +9260,7 @@
</message>
<message>
<source><p>You are about to install a VirtualBox extension pack. Extension packs complement the functionality of VirtualBox and can contain system level software that could be potentially harmful to your system. Please review the description below and only proceed if you have obtained the extension pack from a trusted source.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name: </b></td><td>%1< [...]
- <translation><p>Anda akan menginstal sebuah extension pack VirtualBox. Extension pack melengkapi fungsionalitas VirtualBox dan dapat memuat software level sistem yang berpotensi meruksa sistem Anda. Silakan tinjau deskripsi di bawah dan hanya melanjutkan bila Anda memperoleh extension pack dari suatu sumber yang terpercaya.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Nama: </b></td><td>%1</t [...]
+ <translation><p>Anda akan menginstal sebuah extension pack VirtualBox. Extension pack melengkapi fungsionalitas VirtualBox dan dapat memuat software level sistem yang berpotensi merusak sistem Anda. Silakan tinjau deskripsi di bawah dan hanya melanjutkan bila Anda memperoleh extension pack dari suatu sumber yang terpercaya.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Nama: </b></td><td>%1</t [...]
</message>
<message>
<source>&Install</source>
@@ -9264,7 +9268,7 @@
</message>
<message>
<source>Extension packs complement the functionality of VirtualBox and can contain system level software that could be potentially harmful to your system. Please review the description below and only proceed if you have obtained the extension pack from a trusted source.</source>
- <translation>Extension pack melengkapi fungsionalitas VirtualBox dan dapat memuat software level sistem yang berpotensi meruksa sistem Anda. Silakan tinjau deskripsi di bawah dan hanya melanjutkan bila Anda memperoleh extension pack dari suatu sumber yang terpercaya.</translation>
+ <translation>Extension pack melengkapi fungsionalitas VirtualBox dan dapat memuat software level sistem yang berpotensi merusak sistem Anda. Silakan tinjau deskripsi di bawah dan hanya melanjutkan bila Anda memperoleh extension pack dari suatu sumber yang terpercaya.</translation>
</message>
<message>
<source><p>An older version of the extension pack is already installed, would you like to upgrade? <p>%1</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name: </b></td><td>%2</td></tr><tr><td><b>New Version: </b></td><td>%3</td></tr><tr><td><b>Current Version: </b></td& [...]
@@ -9906,18 +9910,26 @@
<message>
<source>Delete</source>
<comment>extension pack</comment>
- <translation type="unfinished">Hapus</translation>
+ <translation>Hapus</translation>
</message>
<message>
<source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
- <translation type="unfinished"></translation>
+ <translation>Apakah Anda hendak menghapus berkas <nobr><b>%1</b></nobr> yang diunduh?</translation>
</message>
<message>
<source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
- <translation type="unfinished"></translation>
+ <translation>Apakah Anda hendak menghapus daftar berkas berikut <nobr><b>%1</b></nobr>?</translation>
</message>
<message>
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+ <translation><p>Alasan kesalahan ini paling mungkin karena hak yang salah pada soket daemon IPC karena masalah instalasi. Harap periksa hak dari <font color=blue>'/tmp'</font> dan <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
+ </message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -12426,11 +12438,11 @@ langkah ini dan memasang hard disk pada waktu lain menggunakan dialog Setting Me
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Menyimpan nama atau path lengkap ke folder mesin virtual yang akan Anda buat.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Menyimpan nama atau path lengkap ke folder mesin virtual yang akan Anda buat.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Anda akan membuat mesin virtual dalam folder berikut:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Anda akan membuat mesin virtual dalam folder berikut:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts
index 8a47920..df00f86 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_it.ts
@@ -2769,6 +2769,10 @@
<source>Downloading %1...</source>
<translation>Scaricamento di %1 in corso...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -11611,6 +11615,14 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+ <translation><p>Questo errore è causato nella maggior parte dei casi da permessi errati sul socket del demone IPC, derivanti da un problema di installazione. Controlla i permessi di <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
+ </message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
<translation type="unfinished"></translation>
</message>
</context>
@@ -14513,11 +14525,11 @@ questo passo e collegare hard disk più tardi tramite Impostazioni della MV.<
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Mostra il nome o il percorso della cartella della macchina virtuale che stai per creare.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Mostra il nome o il percorso della cartella della macchina virtuale che stai per creare.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Stai per creare la macchina virtuale nella cartella seguente:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Stai per creare la macchina virtuale nella cartella seguente:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts
index e03ac0d..567f3b9 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ja.ts
@@ -2465,6 +2465,10 @@
<source>Downloading %1...</source>
<translation>%1 をダウンロードしています...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -11034,6 +11038,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -13757,11 +13769,11 @@ step and attach hard disks later using the VM Settings dialog.</p></source
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>作成しようとしている名前もしくは仮想マシンのフォルダーのフルパスを指定してください。</nobr></p></translation>
+ <translation type="vanished"><p><nobr>作成しようとしている名前もしくは仮想マシンのフォルダーのフルパスを指定してください。</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>次のフォルダーに仮想マシンを作成しようとしています:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>次のフォルダーに仮想マシンを作成しようとしています:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_km_KH.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_km_KH.ts
index b19cc92..2f08a2b 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_km_KH.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_km_KH.ts
@@ -1732,6 +1732,10 @@
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -8740,6 +8744,14 @@ medium</comment>
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -10797,14 +10809,6 @@ You may wish to translate this more like "Time remaining: %1"</comment
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts
index 0bc0de3..0f5dc3c 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ko.ts
@@ -2491,6 +2491,10 @@
<source>Downloading %1...</source>
<translation>%1 다운로드 중...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10865,6 +10869,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -13476,11 +13488,11 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>생성할 가상 머신 폴더의 이름이나 전체 경로입니다.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>생성할 가상 머신 폴더의 이름이나 전체 경로입니다.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>다음 폴더에 가상 머신을 생성하려고 합니다:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>다음 폴더에 가상 머신을 생성하려고 합니다:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts
index ace2a31..1c8f4eb 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_lt.ts
@@ -2289,6 +2289,10 @@
<source>Downloading %1...</source>
<translation type="unfinished">Parsiunčiama %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9600,6 +9604,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -11805,14 +11817,6 @@
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished">Pasirinkti virtualaus standžiojo disko rinkmeną...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts
index 2e7db9c..fbb62e6 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_nl.ts
@@ -2369,6 +2369,10 @@
<source>Downloading %1...</source>
<translation>Downloaden %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9396,6 +9400,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation><p>De oorzaak van deze fout is vaak verkeerde permissies op de IPC-daemon-socket als gevold van een installatiefout. Controleer de permissies van <font color=blue>'/tmp'</font> en <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetUserManual</name>
@@ -11543,11 +11555,11 @@
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>De naam of volledig pad naar de virtuelemachinemap die u op het punt staat aan te maken.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>De naam of volledig pad naar de virtuelemachinemap die u op het punt staat aan te maken.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>U staat op het punt de virtuele machine aan te maken in de volgende map:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>U staat op het punt de virtuele machine aan te maken in de volgende map:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts
index 0d046df..9d68dda 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pl.ts
@@ -2054,6 +2054,10 @@
<source>Downloading %1...</source>
<translation>Pobieranie %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9754,6 +9758,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -12100,11 +12112,11 @@ Będzie ona używana przez wszystkie moduły VirtualBox, aby móc rozróżnić t
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Przechowuje nazwę lub pełną ścieżkę do folderu wirtualnej maszyny, który zamierzasz stworzyć.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Przechowuje nazwę lub pełną ścieżkę do folderu wirtualnej maszyny, który zamierzasz stworzyć.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Zamierzasz stworzyć wirtualną maszynę w następującym folderze:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Zamierzasz stworzyć wirtualną maszynę w następującym folderze:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts
index 9b5980c..bbb05e8 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt.ts
@@ -2105,6 +2105,10 @@
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9215,6 +9219,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -11538,14 +11550,6 @@ diálogo de Configurações da MV.</p></translation>
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts
index d0b569a..73cff08 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_pt_BR.ts
@@ -2704,6 +2704,10 @@
<source>Downloading %1...</source>
<translation>Baixando %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -11466,6 +11470,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation><p>A provável razão para este erro são permissões incorretas para o socket do daemon de IPC devido a um problema durante a instalação. Verifique as permissões de <font color=blue>'/tmp'</font> e <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -14538,11 +14550,11 @@ utilizando o diálogo de Configurações da MV.</p></translation>
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Contém o nome ou caminho completo da pasta para a máquina virtual que você está prestes a criar</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Contém o nome ou caminho completo da pasta para a máquina virtual que você está prestes a criar</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Você está prestes a criar uma máquina virtual na seguinte pasta:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Você está prestes a criar uma máquina virtual na seguinte pasta:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts
index 4c29755..6c5ba1a 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ro.ts
@@ -1900,6 +1900,10 @@
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9010,6 +9014,14 @@ Acest director este folosit, dacă nu este explicit specificat altfel, atunci c
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -11397,14 +11409,6 @@ din listă apăsând butonul <b>Existent</b> (pentru a invoca dialog
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts
index 49ce747..5bce5f4 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_ru.ts
@@ -2513,6 +2513,10 @@
<source>Downloading %1...</source>
<translation>Загружаю %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10761,6 +10765,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -13396,11 +13408,11 @@ p, li { white-space: pre-wrap; }
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Содержит имя или полный путь к папке машины, которую вы собираетесь создать.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Содержит имя или полный путь к папке машины, которую вы собираетесь создать.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Вы собираетесь создать виртуальную машину в следующей папке:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Вы собираетесь создать виртуальную машину в следующей папке:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts
index 83319d6..294a3b0 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sk.ts
@@ -2147,6 +2147,10 @@
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -8976,6 +8980,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -11292,14 +11304,6 @@ preskočiť a pripojiť pevné disky neskôr pomocou dialógu Nastavenia virtuá
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
index 2eb3085..2b70f09 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sl.ts
@@ -4,7 +4,7 @@
<context>
<name>@@@</name>
<message>
- <location filename="../src/globals/VBoxGlobal.cpp" line="+2065"/>
+ <location filename="../src/globals/VBoxGlobal.cpp" line="+2064"/>
<source>English</source>
<comment>Native language name</comment>
<translation>Slovenščina</translation>
@@ -280,7 +280,7 @@
<translation>&Pogled</translation>
</message>
<message>
- <location line="+875"/>
+ <location line="+935"/>
<source>&Devices</source>
<translation>&Naprave</translation>
</message>
@@ -322,7 +322,7 @@
<translation>Prikaži ikono programa</translation>
</message>
<message>
- <location line="-1379"/>
+ <location line="-1439"/>
<source>Switch between normal and seamless desktop integration mode</source>
<translation>Preklopi med običajnim in tekočim načinom vključitve namizja</translation>
</message>
@@ -536,17 +536,17 @@
<translation>&Skupina</translation>
</message>
<message>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+1173"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+1233"/>
<source>Shared &Clipboard</source>
<translation>&Souporaba odložišča</translation>
</message>
<message>
- <location line="-1172"/>
+ <location line="-1232"/>
<source>Power off the virtual machine</source>
<translation>Izklopi navidezni računalnik</translation>
</message>
<message>
- <location line="+1063"/>
+ <location line="+1123"/>
<source>&Network Settings...</source>
<translation>&Omrežne nastavitve …</translation>
</message>
@@ -556,7 +556,7 @@
<translation>&Nastavitve souporabe map …</translation>
</message>
<message>
- <location line="-837"/>
+ <location line="-897"/>
<source>R&emote Display</source>
<translation>&Oddaljeni zaslon</translation>
</message>
@@ -578,7 +578,7 @@
<translation>Pojavni meni</translation>
</message>
<message>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+800"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+860"/>
<source>&Webcams</source>
<translation>&Spletne kamere</translation>
</message>
@@ -593,7 +593,7 @@
<translation>&VirtualBox</translation>
</message>
<message>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-842"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-902"/>
<source>&Menu Bar</source>
<translation>&Menijska vrstica</translation>
</message>
@@ -638,7 +638,7 @@
<translation>&Nastavitve tipkovice …</translation>
</message>
<message>
- <location line="+157"/>
+ <location line="+217"/>
<source>&Mouse</source>
<translation>&Miška</translation>
</message>
@@ -684,7 +684,7 @@
<translation>&Skrči</translation>
</message>
<message>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-1340"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-1400"/>
<source>&Full-screen Mode</source>
<translation>&Celozaslonski način</translation>
</message>
@@ -713,6 +713,8 @@
<location line="+36"/>
<location line="+31"/>
<location line="+30"/>
+ <location line="+30"/>
+ <location line="+30"/>
<source>Send the %1 sequence to the virtual machine</source>
<translation>Pošlji zaporedje %1 v navidezni računalnik</translation>
</message>
@@ -764,7 +766,7 @@
</message>
<message>
<location filename="../src/globals/UIActionPool.cpp" line="+1"/>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-1200"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-1260"/>
<source>Minimize active window</source>
<translation>Skrči dejavno okno</translation>
</message>
@@ -876,6 +878,8 @@
<location line="+36"/>
<location line="+31"/>
<location line="+30"/>
+ <location line="+30"/>
+ <location line="+30"/>
<source>&Insert %1</source>
<comment>that means send the %1 key sequence to the virtual machine</comment>
<translation>&Pošlji %1</translation>
@@ -926,7 +930,7 @@
<translation>Vstavi datoteko diska Dodatkov za gosta v navidezni optični pogon</translation>
</message>
<message>
- <location line="+1020"/>
+ <location line="+1022"/>
<source>%1%</source>
<comment>scale-factor</comment>
<translation>%1%</translation>
@@ -949,7 +953,7 @@
<translation>Predogled zaslona %1</translation>
</message>
<message>
- <location line="+1495"/>
+ <location line="+1533"/>
<source>&Connect Network Adapter</source>
<translation>&Poveži omrežni vmesnik</translation>
</message>
@@ -1188,7 +1192,7 @@
<translation>Odpri brskalnik in pojdi na spletno mesto Oracle</translation>
</message>
<message>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-2476"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="-2538"/>
<location filename="../src/selector/UIActionPoolSelector.cpp" line="-85"/>
<source>&Detach GUI</source>
<translation>&Odpni GUI</translation>
@@ -1200,7 +1204,7 @@
<translation>Odpni GUI z brezglavnega navideznega računalnka</translation>
</message>
<message>
- <location line="+1619"/>
+ <location line="+1679"/>
<source>Disable Dock Icon Overlay</source>
<translation>Onemogoči prekrivnost ikone Docka</translation>
</message>
@@ -1521,7 +1525,7 @@
<context>
<name>UIDownloader</name>
<message>
- <location filename="../src/net/UIDownloader.cpp" line="+73"/>
+ <location filename="../src/net/UIDownloader.cpp" line="+87"/>
<source>Looking for %1...</source>
<translation>Iskanje %1 …</translation>
</message>
@@ -1530,16 +1534,21 @@
<source>Downloading %1...</source>
<translation>Prejemanje %1 …</translation>
</message>
+ <message>
+ <location line="+1"/>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
<message>
- <location filename="../src/net/UIDownloaderAdditions.cpp" line="+137"/>
+ <location filename="../src/net/UIDownloaderAdditions.cpp" line="+200"/>
<source>Select folder to save Guest Additions image to</source>
<translation>Izberite mapo za shranjevanje Dodatkov za gosta</translation>
</message>
<message>
- <location line="-35"/>
+ <location line="-92"/>
<source>VirtualBox Guest Additions</source>
<translation>Dodatki za gosta VirtualBox</translation>
</message>
@@ -1547,12 +1556,12 @@
<context>
<name>UIDownloaderExtensionPack</name>
<message>
- <location filename="../src/net/UIDownloaderExtensionPack.cpp" line="+133"/>
+ <location filename="../src/net/UIDownloaderExtensionPack.cpp" line="+183"/>
<source>Select folder to save %1 to</source>
<translation>Izberite mapo za shranjevanje %1</translation>
</message>
<message>
- <location line="-45"/>
+ <location line="-91"/>
<source>VirtualBox Extension Pack</source>
<translation>Paket razširitev za VirtualBox</translation>
</message>
@@ -2604,13 +2613,13 @@
</message>
<message>
<location line="+7"/>
- <location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="+300"/>
+ <location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="+301"/>
<source>Name</source>
<translation>Ime</translation>
</message>
<message>
- <location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="+138"/>
- <location line="+52"/>
+ <location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="+139"/>
+ <location line="+53"/>
<source>Networking</source>
<translation>Omreženje</translation>
</message>
@@ -2630,7 +2639,7 @@
<translation>Omrežja &samo za gostitelja</translation>
</message>
<message>
- <location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="-723"/>
+ <location filename="../src/settings/global/UIGlobalSettingsNetwork.cpp" line="-726"/>
<source>No new name specified for the NAT network previously called <b>%1</b>.</source>
<translation>Za omrežje NAT s prejšnjim imenom <b>%1</b> ni navedenega novega imena.</translation>
</message>
@@ -2748,7 +2757,7 @@
<translation>Vmesnik gostitelja <b>%1</b> trenutno nima veljavne zgornje omejitve naslovov strežnika DHCP.</translation>
</message>
<message>
- <location line="+313"/>
+ <location line="+314"/>
<source>The name <b>%1</b> is being used for several NAT networks.</source>
<translation>Ime <b>%1</b> se uporablja za več omrežij NAT.</translation>
</message>
@@ -2819,7 +2828,7 @@
<translation>Uredi izbrano omrežje samo za gostitelja.</translation>
</message>
<message>
- <location line="-419"/>
+ <location line="-420"/>
<source>Host interface <b>%1</b> does not currently have a valid IPv6 network mask prefix length.</source>
<translation>Vmesnik gostitelja <b>%1</b> trenutno nima veljavne dolžine predpone maske omrežja IPv6.</translation>
</message>
@@ -6075,7 +6084,7 @@
<context>
<name>UIMenuBarEditorWidget</name>
<message>
- <location filename="../src/runtime/UIMenuBarEditorWindow.cpp" line="+912"/>
+ <location filename="../src/runtime/UIMenuBarEditorWindow.cpp" line="+926"/>
<source>Virtual Screen Resize</source>
<translation>Sprememba velikosti navideznega zaslona</translation>
</message>
@@ -6104,35 +6113,35 @@
<name>UIMessageCenter</name>
<message>
<location filename="../src/globals/UIMessageCenter.cpp" line="-1522"/>
- <location line="+2647"/>
+ <location line="+2669"/>
<source>VirtualBox - Information</source>
<comment>msg box title</comment>
<translation>VirtualBox - podatki</translation>
</message>
<message>
- <location line="-2643"/>
- <location line="+2647"/>
+ <location line="-2665"/>
+ <location line="+2669"/>
<source>VirtualBox - Question</source>
<comment>msg box title</comment>
<translation>VirtualBox - vprašanje</translation>
</message>
<message>
- <location line="-2643"/>
- <location line="+2647"/>
+ <location line="-2665"/>
+ <location line="+2669"/>
<source>VirtualBox - Warning</source>
<comment>msg box title</comment>
<translation>VirtualBox - opozorilo</translation>
</message>
<message>
- <location line="-2643"/>
- <location line="+2647"/>
+ <location line="-2665"/>
+ <location line="+2669"/>
<source>VirtualBox - Error</source>
<comment>msg box title</comment>
<translation>VirtualBox - napaka</translation>
</message>
<message>
- <location line="-2643"/>
- <location line="+2647"/>
+ <location line="-2665"/>
+ <location line="+2669"/>
<source>VirtualBox - Critical Error</source>
<comment>msg box title</comment>
<translation>VirtualBox - kritična napaka</translation>
@@ -6144,7 +6153,7 @@
<translation>Tega sporočila ne prikazuj več</translation>
</message>
<message>
- <location line="-2419"/>
+ <location line="-2441"/>
<source>Failed to open <tt>%1</tt>. Make sure your desktop environment can properly handle URLs of this type.</source>
<translation>Odpiranje <tt>%1</tt> je spodeltelo. Prepričajte se, da lahko vaše namizno okolje pravilno obvlada URL te vrste.</translation>
</message>
@@ -6309,7 +6318,17 @@
<translation><p>Izvajanje navideznega računalnka lahko naleti na stanje napake opisano spodaj. Predlagamo, da se ustrezno odzovete, da preprečite napako.</p></translation>
</message>
<message>
- <location line="+499"/>
+ <location line="+407"/>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+100"/>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+14"/>
<location line="+9"/>
<source>Delete</source>
<comment>extension pack</comment>
@@ -6347,18 +6366,18 @@
<translation>Klicalec RC: </translation>
</message>
<message>
- <location line="-1627"/>
+ <location line="-1649"/>
<location line="+11"/>
<source><p>Failed to remove the shared folder <b>%1</b> (pointing to <nobr><b>%2</b></nobr>) from the virtual machine <b>%3</b>.</p><p>Please close all programs in the guest OS that may be using this shared folder and try again.</p></source>
<translation><p>Odstranjevanje souporabe mape <b>%1</b> (ki kaže na <nobr><b>%2</b></nobr>) iz navideznega računalnika <b>%3</b> je spodletelo. </p><p>Zaprite vse programe v gostujočem OS-u, ki morda uporabljajo to mapo in poizkusite znova.</p></translation>
</message>
<message>
- <location line="+1197"/>
+ <location line="+1219"/>
<source>Failed to open the license file <nobr><b>%1</b></nobr>. Check file permissions.</source>
<translation>Odpiranje datoteke z dovoljenjem <nobr><b>%1</b></nobr> je spodletelo. Preverite dovoljenja datoteke.</translation>
</message>
<message>
- <location line="-1630"/>
+ <location line="-1652"/>
<source>Failed to send the ACPI Power Button press event to the virtual machine <b>%1</b>.</source>
<translation>Pošiljanje pritiska gumba za izklop ACPI v navidezni računalnik <b>%1</b> je spodletelo.</translation>
</message>
@@ -6493,12 +6512,12 @@
<translation>Dostop do datoteke odtisa diska <b>%1</b> je spodletel</nobr>.</translation>
</message>
<message>
- <location line="+1947"/>
+ <location line="+1969"/>
<source>The following files already exist:<br /><br />%1<br /><br />Are you sure you want to replace them? Replacing them will overwrite their contents.</source>
<translation>Naslednje datoteke že obstajajo:<br /><br />%1.<br /><br />Ali jih res želite nadomestiti? Njihova nadomestitev bo prepisala njihovo vsebino.</translation>
</message>
<message>
- <location line="-2079"/>
+ <location line="-2101"/>
<source>You are running a prerelease version of VirtualBox. This version is not suitable for production use.</source>
<translation>Izvajajte predizdajno različico VirtualBoxa. Ta različica ni primerna za proizvodno uporabo.</translation>
</message>
@@ -6564,12 +6583,12 @@
<translation><p>Izbris tega omrežja samo za gostitelja bo odstranil vmesnik samo za gostitelja, na katerem je osnovano to omrežje. Ali želite odstraniti vmesnik (omrežja samo za gostitelja) <nobr><b>%1</b>?</nobr></p><p><b>Opomba:</b> ta vmesnik lahko uporablja enega ali več navideznih omrežnih vmesnikov, ki pripadajo enemu od vaših navideznih računalnikov. Ko bo odstranjen, ti vmesniki ne bodo več uporabni, dokler ne popravit [...]
</message>
<message>
- <location line="+1484"/>
+ <location line="+1506"/>
<source>A file named <b>%1</b> already exists. Are you sure you want to replace it?<br /><br />Replacing it will overwrite its contents.</source>
<translation>Datoteka z imenom <b>%1</b> že obstaja. Ali jo res želite nadomestiti?<br /><br />Njena nadomestitev bo prepisala njeno vsebino.</translation>
</message>
<message>
- <location line="-618"/>
+ <location line="-640"/>
<source><p>VT-x/AMD-V hardware acceleration has been enabled, but is not operational. Certain guests (e.g. OS/2 and QNX) require this feature.</p><p>Please ensure that you have enabled VT-x/AMD-V properly in the BIOS of your host computer.</p></source>
<translation><p>Strojno pospeševanje VT-x/AMD-V je bilo omogočeno, vendar ne deluje. Določeni gosti (npr. OS/2 in QNX) zahtevajo to značilnost.</p><p>Prepričajte se, da ste pravilno omogočili VT-x/AMD-V v BIOS-u svojega gostiteljskega računalnika.</p></translation>
</message>
@@ -6692,12 +6711,12 @@
<translation>Odklop trdega diska (<nobr><b>%1</b></nobr>) z mesta <i>%2</i> računalnika <b>%3</b>.je spodletel.</translation>
</message>
<message>
- <location line="+771"/>
+ <location line="+782"/>
<source>Failed to update Guest Additions. The Guest Additions disk image file will be inserted for user installation.</source>
<translation>Posodobitev Dodatkov za gosta je spodletela. Datoteka odtisa diska Dodatkov za gosta bo vstavljena za uporabniško namestitev.</translation>
</message>
<message>
- <location line="+210"/>
+ <location line="+221"/>
<location line="+8"/>
<source>Failed to install the Extension Pack <b>%1</b>.</source>
<translation>Namestitev paketa razširitev <b>%1</b> je spodletela.</translation>
@@ -6714,7 +6733,7 @@
<translation>&Odstrani</translation>
</message>
<message>
- <location line="-1179"/>
+ <location line="-1201"/>
<source>The current port forwarding rules are not valid. None of the host or guest port values may be set to zero.</source>
<translation>Trenutna pravila posredovanja vrat niso veljavna. Nobena vrednost vrat gostitelja ali gosta ne sme biti nastavljena na nič.</translation>
</message>
@@ -6745,7 +6764,7 @@
<translation><p>Okno navideznega računalnika bo sedaj preklopljeno na <b>umerjeni</b> način. S pritiskom na <b>%1</b> se lahko kadarkoli vrnete na okenski način.</p><p>Upoštevajte, da je <i>gostiteljska</i> tipka trenutno določena kot <b>%2</b>.</p><p>Upoštevajte, da je v umerjenem načinu glavna menijska vrstica skrita . Do nje lahko dostopate s pritiskom na <b>gostiteljsko tipko+Home</b>.&l [...]
</message>
<message>
- <location line="+427"/>
+ <location line="+449"/>
<location line="+7"/>
<source>Failed to open the Extension Pack <b>%1</b>.</source>
<translation>Odpiranje paketa razširitev <b>%1</b> je spodletelo.</translation>
@@ -6811,7 +6830,7 @@
<translation>Paket razširitev <br><nobr><b>%1</b><nobr><br> je bil uspešno nameščen.</translation>
</message>
<message>
- <location line="-824"/>
+ <location line="-846"/>
<source><p>Cannot create the machine folder <b>%1</b> in the parent folder <nobr><b>%2</b>.</nobr></p><p>Please check that the parent really exists and that you have permissions to create the machine folder.</p></source>
<translation><p>Mape računalnika <b>%1</b> v nadrejeni mapi <nobr><b>%2</b> ni mogoče ustvariti.</nobr></p><p>Preverite, ali nadrejena mapa res obstaja in da imate dovoljenja za ustvarjanje mape računalnika.</p></translation>
</message>
@@ -6857,7 +6876,7 @@
<translation><p>Napaka pri spreminjanju odtisa diska iz <b>%1</b> v <b>%2</b>.</p></translation>
</message>
<message>
- <location line="+1514"/>
+ <location line="+1536"/>
<source>Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer</source>
<translation>Storitve posredniškega strežnika USB gostitelja ni bilo mogoče naložiti (VERR_FILE_NOT_FOUND. Storitev morda ni nameščena na gostiteljskem računalniku.</translation>
</message>
@@ -6882,12 +6901,12 @@
<translation>Storitve posredniškega strežnika USB gostitelja ni bilo mogoče naložiti.</translation>
</message>
<message>
- <location line="-1123"/>
+ <location line="-1145"/>
<source>Can't find snapshot named <b>%1</b>.</source>
<translation>Posnetka stanja z imenom <b>%1</b> ni bilo mogoče najti.</translation>
</message>
<message>
- <location line="+544"/>
+ <location line="+555"/>
<source><p>You have an old version (%1) of the <b><nobr>%2</nobr></b> installed.</p><p>Do you wish to download latest one from the Internet?</p></source>
<translation><p>Nameščeno imate staro različico (%1) <b><nobr>%2</nobr></b>.</p><p>Ali želite z interneta prejeti najnovejšo?</p></translation>
</message>
@@ -6903,18 +6922,18 @@
</message>
<message>
<location line="+6"/>
- <location line="+37"/>
+ <location line="+48"/>
<source>Install</source>
<comment>extension pack</comment>
<translation>Namesti</translation>
</message>
<message>
- <location line="-53"/>
+ <location line="-64"/>
<source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> but can't be saved locally as <nobr><b>%3</b>.</nobr></p><p>Please choose another location for that file.</p></source>
<translation><p><b><nobr>%1</nobr></b> je bil uspešno prejet iz <nobr><a href="%2">%2</a></nobr>, vendar ga ni mogoče krajevno shraniti kot <nobr><b>%3</b>.</nobr></p><p>Izberite drugo mesto za to datoteko.</p></translation>
</message>
<message>
- <location line="-116"/>
+ <location line="-127"/>
<source><p>You have version %1 of the <b><nobr>%2</nobr></b> installed.</p><p>You should download and install version %3 of this extension pack from Oracle!</p></source>
<translation><p>Nameščeno imate različico %1 <b><nobr>%2</nobr></b>.</p><p>Prejmite in namestite različico %3 tega paketa razširitev od Oracla!</p></translation>
</message>
@@ -7209,7 +7228,7 @@
<message>
<location line="+3"/>
<location line="+10"/>
- <location line="+40"/>
+ <location line="+51"/>
<location line="+10"/>
<location line="+29"/>
<location line="+10"/>
@@ -7217,7 +7236,7 @@
<translation>Prejmi</translation>
</message>
<message>
- <location line="-93"/>
+ <location line="-104"/>
<source><p>Are you sure you want to download the <b>VirtualBox Guest Additions</b> disk image file from <nobr><a href="%1">%1</a></nobr> (size %2 bytes)?</p></source>
<translation><p>Ali res želite prejeti datoteko odtisa diska <b>Dodatkov za gosta VirtualBox</b> iz <nobr><a href="%1">%1</a></nobr> (velikost %2 bajtov)?</p></translation>
</message>
@@ -7227,7 +7246,7 @@
<translation><p>Datoteka odtisa diska <b>Dodatkov za gosta VirtualBox</b> je bila uspešno prejeta iz <nobr><a href="%1">%1</a></nobr>, vendar je ni mogoče krajevno shraniti kot <nobr><b>%2</b>.</nobr></p><p>Izberite drugo mesto za to datoteko.</p></translation>
</message>
<message>
- <location line="+30"/>
+ <location line="+41"/>
<source><p>Could not find the <b>VirtualBox User Manual</b> <nobr><b>%1</b>.</nobr></p><p>Do you wish to download this file from the Internet?</p></source>
<translation><p><b>Uporabniškega priročnika za VirtualBox</b> <nobr><b>%1</b> ni bilo mogoče najti.</nobr></p><p>Ali želite prejeti to datoteko iz interneta?</p></translation>
</message>
@@ -7262,7 +7281,7 @@
<translation>Tega sporočila ne prikazuj več</translation>
</message>
<message>
- <location filename="../src/globals/UIMessageCenter.cpp" line="-1245"/>
+ <location filename="../src/globals/UIMessageCenter.cpp" line="-1256"/>
<source><p>Do you want to remove the NAT network <nobr><b>%1</b>?</nobr></p><p>If this network is in use by one or more virtual machine network adapters these adapters will no longer be usable until you correct their settings by either choosing a different network name or a different adapter attachment type.</p></source>
<translation><p>Ali želite odstraniti omrežje NAT <nobr><b>%1</b>?</nobr></p><p>Če to omrežje uporablja en ali več omrežnih vmesnikov navideznega računalnika, ti ne bodo več uporabni, dokler ne popravite njihove nastavitve z izbiro drugega imena omrežja ali druge vrste priklopa vmesnika.</p></translation>
</message>
@@ -7384,7 +7403,7 @@
<translation><p>Izdana je bila nova rezličica VirtualBoxa! Različica <b>%1</b> je na voljo na <a href="https://www.virtualbox.org/">virtualbox.org</a>.</p><p>To različico lahko prejmete z uporabo povezave:</p><p><a href=%2>%3</a></p></translation>
</message>
<message>
- <location line="+315"/>
+ <location line="+337"/>
<location line="+7"/>
<source>Drag and drop operation from host to guest failed.</source>
<translation>Opravilo vlečenja in spuščanja iz gostitelja v gosta je spodletelo.</translation>
@@ -7401,7 +7420,7 @@
<translation>Opravilo vlečenja in spuščanja iz gosta v gostitelja je spodletelo.</translation>
</message>
<message>
- <location line="-385"/>
+ <location line="-407"/>
<source>Failed to connect the network adapter cable of the virtual machine <b>%1</b>.</source>
<translation>Priklop kabla omrežnega vmesnika navideznega računalnika <b>%1</b> je spodletela.</translation>
</message>
@@ -7507,7 +7526,7 @@
<context>
<name>UIMultiScreenLayout</name>
<message>
- <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+614"/>
+ <location filename="../src/runtime/UIActionPoolRuntime.cpp" line="+616"/>
<location line="+15"/>
<location line="+47"/>
<source>Virtual Screen %1</source>
@@ -7749,7 +7768,7 @@
<translation>Vrata gosta</translation>
</message>
<message>
- <location line="+395"/>
+ <location line="+394"/>
<source>Contains a list of port forwarding rules.</source>
<translation>Vsebuje seznam pravil posredovanja vrat.</translation>
</message>
@@ -7822,7 +7841,7 @@
<context>
<name>UISelectorWindow</name>
<message>
- <location filename="../src/selector/UISelectorWindow.cpp" line="+160"/>
+ <location filename="../src/selector/UISelectorWindow.cpp" line="+161"/>
<source>Show Toolbar</source>
<translation>Prikaži orodno vrstico</translation>
</message>
@@ -7832,7 +7851,7 @@
<translation>Prikaži vrstico stanja</translation>
</message>
<message>
- <location line="+338"/>
+ <location line="+342"/>
<source>Select a virtual machine file</source>
<translation>Izberite datoteko navideznega računalnika</translation>
</message>
@@ -7848,7 +7867,7 @@
<translation>Upravljalnik</translation>
</message>
<message>
- <location line="-781"/>
+ <location line="-785"/>
<source><h3>Welcome to VirtualBox!</h3><p>The left part of this window is a list of all virtual machines on your computer. The list is empty now because you haven't created any virtual machines yet.<img src=:/welcome.png align=right/></p><p>In order to create a new virtual machine, press the <b>New</b> button in the main tool bar located at the top of the window.</p><p>You can press the <b>%1</b> key to [...]
<translation><h3>Dobrodošli v VirtulBox!</h3><p>Levi del tega okna je seznam vseh navideznih računalnikov na vašem računalniku. Seznam je sedaj prazen, ker še niste ustvarili nobenega navideznega računalnika.<img src=:/welcome.png align=right/></p><p>Da ustvarite nov navidezni računalnik, pritisnite gumb <b>Nov</b> v glavni orodni vrstici na vrhu okna.</p><p>Lahko pritisnete tipko <b>%1</b> za takojšnjo pomoč [...]
</message>
@@ -7869,7 +7888,7 @@
<translation><i>Izberite kategorijo nastavitev s seznama na levi in premaknite miško nad predmet nastavitev, da dobite več podatkov.</i></translation>
</message>
<message>
- <location filename="../src/settings/UISettingsDialog.cpp" line="+348"/>
+ <location filename="../src/settings/UISettingsDialog.cpp" line="+356"/>
<source>Invalid settings detected</source>
<translation>Zaznane neveljavne nastavitve</translation>
</message>
@@ -8013,7 +8032,7 @@
<context>
<name>UISettingsSerializerProgress</name>
<message>
- <location filename="../src/settings/UISettingsSerializer.cpp" line="+339"/>
+ <location filename="../src/settings/UISettingsSerializer.cpp" line="+340"/>
<source>Loading Settings...</source>
<translation>Nalaganje nastavitev …</translation>
</message>
@@ -8130,7 +8149,7 @@
<context>
<name>UIUpdateStepVirtualBox</name>
<message>
- <location filename="../src/net/UIUpdateManager.cpp" line="+173"/>
+ <location filename="../src/net/UIUpdateManager.cpp" line="+176"/>
<source>Checking for a new VirtualBox version...</source>
<translation>Preverjanje za novo različico VirtualBoxa …</translation>
</message>
@@ -9258,8 +9277,8 @@
<translation>Ustvari</translation>
</message>
<message>
- <location filename="../src/wizards/newvm/UIWizardNewVMPageBasic1.cpp" line="+355"/>
- <location filename="../src/wizards/newvm/UIWizardNewVMPageExpert.cpp" line="+238"/>
+ <location filename="../src/wizards/newvm/UIWizardNewVMPageBasic1.cpp" line="+308"/>
+ <location filename="../src/wizards/newvm/UIWizardNewVMPageExpert.cpp" line="+227"/>
<source>Name and operating system</source>
<translation>Ime in operacijski sistem</translation>
</message>
@@ -9319,14 +9338,12 @@
<translation>Izberi datoteko navideznega trdega diska …</translation>
</message>
<message>
- <location filename="../src/wizards/newvm/UIWizardNewVMPageBasic1.cpp" line="-143"/>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Vsebuje ime ali polno pot do navideznega računalnika, ki ga boste ustvarli.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Vsebuje ime ali polno pot do navideznega računalnika, ki ga boste ustvarli.</nobr></p></translation>
</message>
<message>
- <location line="+10"/>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Navidezni računalnik boste ustvarili v naslednji mapi:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Navidezni računalnik boste ustvarili v naslednji mapi:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
@@ -10863,7 +10880,7 @@
<translation>Disketna naprava %1</translation>
</message>
<message>
- <location line="+639"/>
+ <location line="+643"/>
<location line="+30"/>
<source>General</source>
<comment>DetailsElementType</comment>
@@ -10967,7 +10984,7 @@
<translation>Vse datoteke navidezne diskete (%1)</translation>
</message>
<message>
- <location line="+2056"/>
+ <location line="+2100"/>
<source>VDI (VirtualBox Disk Image)</source>
<translation>VDI (Odtis diska VirtualBox - angl. VirtualBox Disk Image)</translation>
</message>
@@ -11044,7 +11061,7 @@
<translation>Omrežje NAT</translation>
</message>
<message>
- <location filename="../src/globals/VBoxGlobal.cpp" line="-2363"/>
+ <location filename="../src/globals/VBoxGlobal.cpp" line="-2407"/>
<source>NAT network, '%1'</source>
<comment>details report (network)</comment>
<translation>Omrežje NAT, '%1'</translation>
@@ -11062,7 +11079,7 @@
<translation>USB</translation>
</message>
<message>
- <location filename="../src/converter/UIConverterBackendGlobal.cpp" line="-722"/>
+ <location filename="../src/converter/UIConverterBackendGlobal.cpp" line="-726"/>
<location line="+40"/>
<source>USB Port %1</source>
<comment>StorageSlot</comment>
@@ -11217,7 +11234,7 @@
<translation>xHCI</translation>
</message>
<message>
- <location filename="../src/converter/UIConverterBackendGlobal.cpp" line="+651"/>
+ <location filename="../src/converter/UIConverterBackendGlobal.cpp" line="+655"/>
<location line="+30"/>
<source>User interface</source>
<comment>DetailsElementType</comment>
@@ -11287,13 +11304,13 @@
<translation>NVMe</translation>
</message>
<message>
- <location filename="../src/converter/UIConverterBackendGlobal.cpp" line="-705"/>
+ <location filename="../src/converter/UIConverterBackendGlobal.cpp" line="-709"/>
<source>NVMe Port %1</source>
<comment>StorageSlot</comment>
<translation>Vrata NVMe %1</translation>
</message>
<message>
- <location line="+1358"/>
+ <location line="+1362"/>
<location line="+33"/>
<source>General</source>
<comment>InformationElementType</comment>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts
index 31a38f9..dbd3253 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sr.ts
@@ -2200,6 +2200,10 @@
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9947,6 +9951,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -12355,14 +12367,6 @@ p, li { white-space: pre-wrap; }
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts
index dba2892..1ea14fe 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_sv.ts
@@ -2505,6 +2505,10 @@
<source>Downloading %1...</source>
<translation>Hämtar %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10986,6 +10990,14 @@ serial ports</comment>
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -13775,14 +13787,6 @@ serial ports</comment>
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished">Välj en virtuell hårddiskfil...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_th.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_th.ts
new file mode 100644
index 0000000..c7b0d82
--- /dev/null
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_th.ts
@@ -0,0 +1,9213 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="th_TH">
+<context>
+ <name>@@@</name>
+ <message>
+ <source>English</source>
+ <comment>Native language name</comment>
+ <translation>ไทย</translation>
+ </message>
+ <message>
+ <source>--</source>
+ <comment>Native language country name (empty if this language is for all countries)</comment>
+ <translation>--</translation>
+ </message>
+ <message>
+ <source>English</source>
+ <comment>Language name, in English</comment>
+ <translation>Thai</translation>
+ </message>
+ <message>
+ <source>--</source>
+ <comment>Language country name, in English (empty if native country name is empty)</comment>
+ <translation>--</translation>
+ </message>
+ <message>
+ <source>Oracle Corporation</source>
+ <comment>Comma-separated list of translators</comment>
+ <translation>Surasak Srisawan</translation>
+ </message>
+</context>
+<context>
+ <name>QApplication</name>
+ <message>
+ <source>Executable <b>%1</b> requires Qt %2.x, found Qt %3.</source>
+ <translation>โปรแกรม <b>%1</b> ต้องการ Qt %2.x แต่พบ Qt %3</translation>
+ </message>
+ <message>
+ <source>Incompatible Qt Library Error</source>
+ <translation>เกิดความผิดพลาด ไลบรารี Qt เข้ากันไม่ได้</translation>
+ </message>
+ <message>
+ <source>VirtualBox - Error In %1</source>
+ <translation>เวอร์ชวลบอกซ์ - เกิดความผิดพลาดใน %1</translation>
+ </message>
+ <message>
+ <source><html><b>%1 (rc=%2)</b><br/><br/></source>
+ <translation><html><b>%1 (rc=%2)</b><br/><br/></translation>
+ </message>
+ <message>
+ <source>Please try reinstalling VirtualBox.</source>
+ <translation>โปรดลองติดตั้งเวอร์ชวลบอกซ์อีกครั้ง</translation>
+ </message>
+ <message>
+ <source>Make sure the kernel module has been loaded successfully.</source>
+ <translation>โปรดตรวจสอบว่าสามารถโหลดเคอร์แนลโมดูลได้สำเร็จ</translation>
+ </message>
+ <message>
+ <source>VirtualBox - Runtime Error</source>
+ <translation>เวอร์ชวลบอกซ์ - เกิดความผิดพลาดขณะทำงาน</translation>
+ </message>
+ <message>
+ <source><b>Cannot access the kernel driver!</b><br/><br/></source>
+ <translation><b>ไม่สามารถเข้าถึงไดร์เวอร์เคอร์แนลได้!</b><br/><br/></translation>
+ </message>
+ <message>
+ <source>Unknown error %2 during initialization of the Runtime</source>
+ <translation>เกิดข้อผิดพลาดที่ไม่รู้จัก %2 ขณะเริ่มการทำงานของโปรแกรม</translation>
+ </message>
+ <message>
+ <source>Kernel driver not accessible</source>
+ <translation>ไม่สามารถเข้าถึงไดร์เวอร์เคอร์แนลได้</translation>
+ </message>
+ <message>
+ <source>The VirtualBox kernel modules do not match this version of VirtualBox. The installation of VirtualBox was apparently not successful. Please try completely uninstalling and reinstalling VirtualBox.</source>
+ <translation>โมดูลเคอร์แนลของเวอร์ชวลบอกซ์ไม่ตรงกับเวอร์ชวลบอกซ์รุ่นที่ใช้งานอยู่ อาจเกิดจากการติดตั้งเวอร์ชวลบอกซ์ไม่สมบูรณ์ กรุณาลองติดตั้งเวอร์ชวลบอกซ์ใหม่อีกครั้ง</translation>
+ </message>
+ <message>
+ <source>This error means that the kernel driver was either not able to allocate enough memory or that some mapping operation failed.</source>
+ <translation>ข้อผิดพลาดนี้แสดงว่าอาจมีหน่วยความจำไม่พอสำหรับไดร์เวอร์เคอร์แนล หรือเกิดความล้มเหลวบางประการขณะดำเนินการแมปปิ้ง</translation>
+ </message>
+ <message>
+ <source>The VirtualBox Linux kernel driver (vboxdrv) is either not loaded or there is a permission problem with /dev/vboxdrv. Please reinstall the kernel module by executing<br/><br/> <font color=blue>'/sbin/vboxconfig'</font><br/><br/>as root.</source>
+ <translation>ไดร์เวอร์ลินุกซ์เคอร์แนลของเวอร์ชวลบอกซ์ (vboxdrv) อาจไม่ได้ถูกโหลดไว้หรืออาจมีปัญหาสิทธิในการเข้าถึง /dev/vboxdrv โปรดติดตั้งโมดูลเคอร์แนลอีกครั้งด้วยคำสั่ง <br/><br/> <font color=blue>'/sbin/vboxconfig'</font><br/><br/> ด้วยสิทธิ root</translation>
+ </message>
+ <message>
+ <source>The VirtualBox kernel modules do not match this version of VirtualBox. The installation of VirtualBox was apparently not successful. Executing<br/><br/> <font color=blue>'/sbin/vboxconfig'</font><br/><br/>may correct this. Make sure that you do not mix the OSE version and the PUEL version of VirtualBox.</source>
+ <translation>โมดูลเคอร์แนลของเวอร์ชวลบอกซ์ไม่ตรงกับเวอร์ชวลบอกซ์รุ่นที่ใช้งานอยู่ อาจเกิดจากการติดตั้งเวอร์ชวลบอกซ์ไม่สมบูรณ์ การใช้คำสั่ง<br/><br/> <font color=blue>'/sbin/vboxconfig'</font><br/><br/>อาจแก้ปัญหานี้ได้ โปรดตรวจสอบให้แน่ใจว่าคุณไม่ได้ใช้เวอร์ชวลบอกซ์รุ่น OSE ร่วมกันกับ PUEL</translation>
+ </message>
+</context>
+<context>
+ <name>QIArrowButtonPress</name>
+ <message>
+ <source>&Back</source>
+ <translation>&ย้อนกลับ</translation>
+ </message>
+ <message>
+ <source>&Next</source>
+ <translation>&ถัดไป</translation>
+ </message>
+</context>
+<context>
+ <name>QIArrowSplitter</name>
+ <message>
+ <source>&Details</source>
+ <translation>&รายละเอียด</translation>
+ </message>
+ <message>
+ <source>&Details (%1 of %2)</source>
+ <translation>&รายละเอียด (%1 จาก %2)</translation>
+ </message>
+</context>
+<context>
+ <name>QIFileDialog</name>
+ <message>
+ <source>Select a directory</source>
+ <translation>เลือกไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Select a file</source>
+ <translation>เลือกไฟล์</translation>
+ </message>
+</context>
+<context>
+ <name>QILabel</name>
+ <message>
+ <source>&Copy</source>
+ <translation>&คัดลอก</translation>
+ </message>
+</context>
+<context>
+ <name>QIMessageBox</name>
+ <message>
+ <source>OK</source>
+ <translation>ตกลง</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>ใช่</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>ไม่ใช่</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+ <message>
+ <source>Copy all errors to the clipboard</source>
+ <translation>คัดลอกข้อผิดพลาดทั้งหมดไปยังคลิปบอร์ด</translation>
+ </message>
+ <message>
+ <source>Copy</source>
+ <translation>คัดลอก</translation>
+ </message>
+</context>
+<context>
+ <name>UIActionPool</name>
+ <message>
+ <source>&Machine</source>
+ <translation>เ&ครื่อง</translation>
+ </message>
+ <message>
+ <source>&Adjust Window Size</source>
+ <translation>&ปรับขนาดหน้าต่าง</translation>
+ </message>
+ <message>
+ <source>Adjust window size and position to best fit the guest display</source>
+ <translation>ปรับขนาดและตำแหน่งของหน้าต่างให้เหมาะสมที่สุดสำหรับการแสดงผลของเกสต์</translation>
+ </message>
+ <message>
+ <source>Take a snapshot of the virtual machine</source>
+ <translation>เก็บสแนปช็อตของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Pause</source>
+ <translation>หยุด&ชั่วคราว</translation>
+ </message>
+ <message>
+ <source>Suspend the execution of the virtual machine</source>
+ <translation>พักการทำงานของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Reset</source>
+ <translation>&รีเซ็ต</translation>
+ </message>
+ <message>
+ <source>Reset the virtual machine</source>
+ <translation>รีเซ็ตเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>ACPI Sh&utdown</source>
+ <translation>&ชัตดาวน์ด้วย ACPI</translation>
+ </message>
+ <message>
+ <source>&Close...</source>
+ <translation>&ปิด...</translation>
+ </message>
+ <message>
+ <source>Close the virtual machine</source>
+ <translation>ปิดเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&View</source>
+ <translation>&มุมมอง</translation>
+ </message>
+ <message>
+ <source>&Devices</source>
+ <translation>&อุปกรณ์</translation>
+ </message>
+ <message>
+ <source>De&bug</source>
+ <translation>ดี&บั๊ก</translation>
+ </message>
+ <message>
+ <source>&Statistics...</source>
+ <comment>debug action</comment>
+ <translation>&สถิติ...</translation>
+ </message>
+ <message>
+ <source>&Command Line...</source>
+ <comment>debug action</comment>
+ <translation>&บรรทัดคำสั่ง...</translation>
+ </message>
+ <message>
+ <source>&Help</source>
+ <translation>&ช่วยเหลือ</translation>
+ </message>
+ <message>
+ <source>Dock Icon</source>
+ <translation>ด็อคไอคอน</translation>
+ </message>
+ <message>
+ <source>Show Monitor Preview</source>
+ <translation>แสดงตัวอย่างจอภาพ</translation>
+ </message>
+ <message>
+ <source>Show Application Icon</source>
+ <translation>แสดงไอคอนของโปรแกรม</translation>
+ </message>
+ <message>
+ <source>Switch between normal and seamless desktop integration mode</source>
+ <translation>สลับการทำงานระหว่างโหมดปกติกับโหมดรวมเดสก์ทอปแบบไร้ขอบ</translation>
+ </message>
+ <message>
+ <source>Switch between normal and scaled mode</source>
+ <translation>สลับการทำงานระหว่างโหมดปกติกับโหมดสเกล</translation>
+ </message>
+ <message>
+ <source>Auto-resize &Guest Display</source>
+ <translation>ปรับขนาดหน้าจอของเ&กสต์โดยอัตโนมัติ</translation>
+ </message>
+ <message>
+ <source>&Settings...</source>
+ <translation>การ&ตั้งค่า...</translation>
+ </message>
+ <message>
+ <source>Session I&nformation...</source>
+ <translation>รายละเอียดของเ&ซสชัน...</translation>
+ </message>
+ <message>
+ <source>&Contents...</source>
+ <translation>เ&นื้อหา...</translation>
+ </message>
+ <message>
+ <source>Show help contents</source>
+ <translation>แสดงเนื้อหาของข้อมูลช่วยเหลือ</translation>
+ </message>
+ <message>
+ <source>Open the browser and go to the VirtualBox product web site</source>
+ <translation>เปิดเบราว์เซอร์แล้วไปเว็บไซต์ของเวอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>Go back to showing all suppressed warnings and messages</source>
+ <translation>ย้อนกลับไปแสดงข้อความเตือนและข้อผิดพลาดที่ถูกซ่อนไว้</translation>
+ </message>
+ <message>
+ <source>&Network Operations Manager...</source>
+ <translation>ส่วนจัดการการทำงานของเ&ครือข่าย...</translation>
+ </message>
+ <message>
+ <source>Check for a new VirtualBox version</source>
+ <translation>ตรวจสอบเวอร์ชวลบอกซ์รุ่นใหม่</translation>
+ </message>
+ <message>
+ <source>&About VirtualBox...</source>
+ <translation>เ&กี่ยวกับเวอร์ชวลบอกซ์...</translation>
+ </message>
+ <message>
+ <source>Take Sn&apshot...</source>
+ <translation>เก็บ&สแนปช็อต...</translation>
+ </message>
+ <message>
+ <source>Take Screensh&ot...</source>
+ <translation>เก็บ&ภาพหน้าจอ...</translation>
+ </message>
+ <message>
+ <source>&File</source>
+ <comment>Mac OS X version</comment>
+ <translation>ไ&ฟล์</translation>
+ </message>
+ <message>
+ <source>&File</source>
+ <comment>Non Mac OS X version</comment>
+ <translation>ไ&ฟล์</translation>
+ </message>
+ <message>
+ <source>&Virtual Media Manager...</source>
+ <translation>ส่วนจัดการมีเดียเ&สมือน...</translation>
+ </message>
+ <message>
+ <source>Display the Virtual Media Manager window</source>
+ <translation>แสดงหน้าต่างส่วนจัดการมีเดียเสมือน</translation>
+ </message>
+ <message>
+ <source>&Import Appliance...</source>
+ <translation>&นำเข้าแอพพลายแอนซ์...</translation>
+ </message>
+ <message>
+ <source>Import an appliance into VirtualBox</source>
+ <translation>นำเข้าแอพพลายแอนซ์มาในเวอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>&Export Appliance...</source>
+ <translation>&ส่งออกแอพพลายแอนซ์...</translation>
+ </message>
+ <message>
+ <source>Export one or more VirtualBox virtual machines as an appliance</source>
+ <translation>ส่งออกเวอร์ชวลแมชชีนของเวอร์ชวลบอกซ์ไปเป็นแอพพลายแอนซ์</translation>
+ </message>
+ <message>
+ <source>E&xit</source>
+ <translation>&ออก</translation>
+ </message>
+ <message>
+ <source>Close application</source>
+ <translation>ปิดโปรแกรม</translation>
+ </message>
+ <message>
+ <source>&Group</source>
+ <translation>&กลุ่ม</translation>
+ </message>
+ <message>
+ <source>S&tart</source>
+ <translation>เ&ริ่ม</translation>
+ </message>
+ <message>
+ <source>S&how</source>
+ <translation>แ&สดง</translation>
+ </message>
+ <message>
+ <source>&New...</source>
+ <translation>&สร้าง...</translation>
+ </message>
+ <message>
+ <source>&Add...</source>
+ <translation>เ&พิ่ม...</translation>
+ </message>
+ <message>
+ <source>Cl&one...</source>
+ <translation>โ&คลน...</translation>
+ </message>
+ <message>
+ <source>&Remove...</source>
+ <translation>&ลบ...</translation>
+ </message>
+ <message>
+ <source>Discard</source>
+ <translation>ทิ้ง</translation>
+ </message>
+ <message>
+ <source>&Close</source>
+ <translation>&ปิด</translation>
+ </message>
+ <message>
+ <source>Show &Log...</source>
+ <translation>แสดง&ล็อก...</translation>
+ </message>
+ <message>
+ <source>&VirtualBox Web Site...</source>
+ <translation>เว็บไซต์เ&วอร์ชวลบอกซ์...</translation>
+ </message>
+ <message>
+ <source>&Reset All Warnings</source>
+ <translation>&รีเซ็ตการเตือนทั้งหมด</translation>
+ </message>
+ <message>
+ <source>C&heck for Updates...</source>
+ <translation>&ตรวจสอบการอัพเดต...</translation>
+ </message>
+ <message>
+ <source>Rena&me Group...</source>
+ <translation>เปลี่ยน&ชื่อกลุ่ม...</translation>
+ </message>
+ <message>
+ <source>Po&wer Off</source>
+ <translation>&ปิดสวิตซ์</translation>
+ </message>
+ <message>
+ <source>&New Machine...</source>
+ <translation>&สร้างเครื่องใหม่...</translation>
+ </message>
+ <message>
+ <source>&Add Machine...</source>
+ <translation>เ&พิ่มเครื่อง...</translation>
+ </message>
+ <message>
+ <source>Gro&up</source>
+ <translation>จัด&กลุ่ม</translation>
+ </message>
+ <message>
+ <source>Shared &Clipboard</source>
+ <translation>&คลิปบอร์ดที่ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>Power off the virtual machine</source>
+ <translation>ปิดเครื่องเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Network Settings...</source>
+ <translation>การตั้งค่าเ&ครือข่าย...</translation>
+ </message>
+ <message>
+ <source>&Shared Folders Settings...</source>
+ <translation>ตั้งค่าโ&ฟลเดอร์ที่ใช้ร่วมกัน...</translation>
+ </message>
+ <message>
+ <source>R&emote Display</source>
+ <translation>หน่วยแสดงผลจาก&ระยะไกล</translation>
+ </message>
+ <message>
+ <source>&Video Capture</source>
+ <translation>จับภาพ&วิดีโอ</translation>
+ </message>
+ <message>
+ <source>&Video Capture Settings...</source>
+ <translation>ตั้งค่าการจับภาพ&วิดีโอ...</translation>
+ </message>
+ <message>
+ <source>Popup Menu</source>
+ <translation>เมนูป๊อปอัพ...</translation>
+ </message>
+ <message>
+ <source>&Webcams</source>
+ <translation>เ&ว็บแคม</translation>
+ </message>
+ <message>
+ <source>&Insert Guest Additions CD image...</source>
+ <translation>ใ&ส่ซีดีอิมเมจโปรแกรมเสริมสำหรับเกสต์...</translation>
+ </message>
+ <message>
+ <source>&VirtualBox</source>
+ <translation>เ&วอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>&Menu Bar</source>
+ <translation>แถบเ&มนู</translation>
+ </message>
+ <message>
+ <source>&Menu Bar Settings...</source>
+ <translation>ตั้งค่าแถบเ&มนู...</translation>
+ </message>
+ <message>
+ <source>Show Menu &Bar</source>
+ <translation>แสดงแ&ถบเมนู</translation>
+ </message>
+ <message>
+ <source>&Status Bar</source>
+ <translation>แถบ&สถานะ</translation>
+ </message>
+ <message>
+ <source>&Status Bar Settings...</source>
+ <translation>ตั้งค่าแถบ&สถานะ...</translation>
+ </message>
+ <message>
+ <source>Show Status &Bar</source>
+ <translation>แสดงแ&ถบสถานะ</translation>
+ </message>
+ <message>
+ <source>&Input</source>
+ <translation>&อินพุต</translation>
+ </message>
+ <message>
+ <source>&Keyboard</source>
+ <translation>&คีย์บอร์ด</translation>
+ </message>
+ <message>
+ <source>&Keyboard Settings...</source>
+ <translation>ตั้งค่า&คีย์บอร์ด...</translation>
+ </message>
+ <message>
+ <source>&Mouse</source>
+ <translation>เ&มาส์</translation>
+ </message>
+ <message>
+ <source>&USB Settings...</source>
+ <translation>ตั้งค่า &USB...</translation>
+ </message>
+ <message>
+ <source>&Shared Folders</source>
+ <translation>โ&ฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>Show &Log...</source>
+ <comment>debug action</comment>
+ <translation>แสดง&ล็อก...</translation>
+ </message>
+ <message>
+ <source>E&xtra Data Manager...</source>
+ <translation>ส่วนจัดการข้อมูลเ&พิ่มเติม...</translation>
+ </message>
+ <message>
+ <source>Display the Extra Data Manager window</source>
+ <translation>แสดงหน้าต่างส่วนจัดการข้อมูลเพิ่มเติม</translation>
+ </message>
+ <message>
+ <source>&File</source>
+ <translation>ไ&ฟล์</translation>
+ </message>
+ <message>
+ <source>&Window</source>
+ <translation>&หน้าต่าง</translation>
+ </message>
+ <message>
+ <source>&Minimize</source>
+ <translation>&ย่อหน้าต่าง</translation>
+ </message>
+ <message>
+ <source>&Full-screen Mode</source>
+ <translation>โหมดเ&ต็มจอ</translation>
+ </message>
+ <message>
+ <source>Switch between normal and full-screen mode</source>
+ <translation>สลับระหว่างโหมดปกติกับโหมดเต็มจอ</translation>
+ </message>
+ <message>
+ <source>Seam&less Mode</source>
+ <translation>โหมดไ&ร้ขอบ</translation>
+ </message>
+ <message>
+ <source>S&caled Mode</source>
+ <translation>โหมด&สเกล</translation>
+ </message>
+ <message>
+ <source>S&cale Factor</source>
+ <translation>ค่าสเ&กล</translation>
+ </message>
+ <message>
+ <source>Send the %1 sequence to the virtual machine</source>
+ <translation>ส่งลำดับ %1 ไปยังเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Mouse Integration</source>
+ <translation>การควบรวมเ&มาส์</translation>
+ </message>
+ <message>
+ <source>Enable host mouse pointer integration</source>
+ <translation>เปิดใช้การควบรวมตัวชี้เมาส์ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>&Optical Drives</source>
+ <translation>&ออปติคัลไดรฟ์</translation>
+ </message>
+ <message>
+ <source>&Floppy Drives</source>
+ <translation>ไดรฟ์&ฟลอปปี้</translation>
+ </message>
+ <message>
+ <source>&USB</source>
+ <translation>&USB</translation>
+ </message>
+ <message>
+ <source>&Logging</source>
+ <comment>debug action</comment>
+ <translation>การเก็บ&ล็อก</translation>
+ </message>
+ <message>
+ <source>&Normal Start</source>
+ <translation>เริ่มแบบ&ปกติ</translation>
+ </message>
+ <message>
+ <source>&Headless Start</source>
+ <translation>เริ่มแบบไ&ร้จอแสดงผล</translation>
+ </message>
+ <message>
+ <source>&Detachable Start</source>
+ <translation>เริ่มแบบแ&ยกส่วนได้</translation>
+ </message>
+ <message>
+ <source>Minimize active window</source>
+ <translation>ย่อหน้าต่างที่ใช้งานอยู่</translation>
+ </message>
+ <message>
+ <source>Display the Network Operations Manager window</source>
+ <translation>แสดงหน้าต่างส่วนจัดการกระบวนการทางเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Display a window with product information</source>
+ <translation>แสดงหน้าต่างข้อมูลผลิตภัณฑ์</translation>
+ </message>
+ <message>
+ <source>&Preferences...</source>
+ <comment>global preferences window</comment>
+ <translation>&ค่าตั้งพึงใจ...</translation>
+ </message>
+ <message>
+ <source>Display the global preferences window</source>
+ <translation>แสดงหน้าต่างค่าตั้งพึงใจส่วนกลาง</translation>
+ </message>
+ <message>
+ <source>Display the virtual machine settings window</source>
+ <translation>แสดงหน้าต่างการตั้งค่าเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Display the virtual machine session information window</source>
+ <translation>แสดงหน้าต่างข้อมูลเซสชั่นของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Save State</source>
+ <translation>บันทึก&สถานะ</translation>
+ </message>
+ <message>
+ <source>Save the state of the virtual machine</source>
+ <translation>บันทึกสถานะของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Send the ACPI Shutdown signal to the virtual machine</source>
+ <translation>ส่งสัญญาณปิดเครื่องแบบ ACPI ไปยังเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Minimize Window</source>
+ <translation>&ย่อหน้าต่าง</translation>
+ </message>
+ <message>
+ <source>Automatically resize the guest display when the window is resized</source>
+ <translation>ปรับขนาดการแสดงผลเกสต์โดยอัตโนมัติเมื่อหน้าต่างถูกเปลี่ยนขนาด</translation>
+ </message>
+ <message>
+ <source>Take guest display screenshot</source>
+ <translation>เก็บภาพหน้าจอของเกสต์</translation>
+ </message>
+ <message>
+ <source>Display virtual machine settings window to configure video capture</source>
+ <translation>แสดงหน้าต่างการตั้งค่าเวอร์ชวลแมชชีนเพื่อกำหนดการจับภาพวิดีโอ</translation>
+ </message>
+ <message>
+ <source>Enable guest display video capture</source>
+ <translation>เปิดใช้การจับภาพวิดีโอหน้าจอของเกสต์</translation>
+ </message>
+ <message>
+ <source>Allow remote desktop (RDP) connections to this machine</source>
+ <translation>อนุญาตให้เชื่อมต่อการแสดงผลระยะไกล (RDP) มายังเครื่องนี้</translation>
+ </message>
+ <message>
+ <source>Display window to configure menu-bar</source>
+ <translation>แสดงหน้าต่างเพื่อกำหนดค่าแถบเมนู</translation>
+ </message>
+ <message>
+ <source>Enable menu-bar</source>
+ <translation>เปิดใช้แถบเมนู</translation>
+ </message>
+ <message>
+ <source>Display window to configure status-bar</source>
+ <translation>แสดงหน้าต่างเพื่อกำหนดค่าแถบสถานะ</translation>
+ </message>
+ <message>
+ <source>Enable status-bar</source>
+ <translation>เปิดใช้แถบสถานะ</translation>
+ </message>
+ <message>
+ <source>Display global preferences window to configure keyboard shortcuts</source>
+ <translation>แสดงหน้าต่างค่าตั้งพึงใจส่วนกลางเพื่อกำหนดทางลัดแป้นพิมพ์</translation>
+ </message>
+ <message>
+ <source>&Insert %1</source>
+ <comment>that means send the %1 key sequence to the virtual machine</comment>
+ <translation>&กดปุ่ม %1</translation>
+ </message>
+ <message>
+ <source>&Hard Disks</source>
+ <translation>&ฮาร์ดดิสก์</translation>
+ </message>
+ <message>
+ <source>&Hard Disk Settings...</source>
+ <translation>ตั้งค่า&ฮาร์ดดิสก์...</translation>
+ </message>
+ <message>
+ <source>Display virtual machine settings window to configure hard disks</source>
+ <translation>แสดงหน้าต่างการตั้งค่าเวอร์ชวลแมชชีนเพื่อกำหนดค่าฮาร์ดดิสก์</translation>
+ </message>
+ <message>
+ <source>&Network</source>
+ <translation>เ&ครือข่าย</translation>
+ </message>
+ <message>
+ <source>Display virtual machine settings window to configure network adapters</source>
+ <translation>แสดงหน้าต่างการตั้งค่าเวอร์ชวลแมชชีนเพื่อกำหนดค่าแผงวงจรเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Display virtual machine settings window to configure USB devices</source>
+ <translation>แสดงหน้าต่างการตั้งค่าเวอร์ชวลแมชชีนเพื่อกำหนดค่าอุปกรณ์ USB</translation>
+ </message>
+ <message>
+ <source>&Drag and Drop</source>
+ <translation>&ลากแล้วปล่อย</translation>
+ </message>
+ <message>
+ <source>Display virtual machine settings window to configure shared folders</source>
+ <translation>แสดงหน้าต่างการตั้งค่าเวอร์ชวลแมชชีนเพื่อกำหนดค่าโฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>Insert the Guest Additions disk file into the virtual optical drive</source>
+ <translation>ใส่ไฟล์แผ่นส่วนขยายสำหรับเกสต์ลงในไดรฟ์ออปติคัลเสมือน</translation>
+ </message>
+ <message>
+ <source>%1%</source>
+ <comment>scale-factor</comment>
+ <translation>%1%</translation>
+ </message>
+ <message>
+ <source>Enable</source>
+ <comment>Virtual Screen</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Resize to %1x%2</source>
+ <comment>Virtual Screen</comment>
+ <translation>เปลี่ยนขนาดเป็น %1x%2</translation>
+ </message>
+ <message>
+ <source>Preview Monitor %1</source>
+ <translation>หน้าจอแสดงตัวอย่าง %1</translation>
+ </message>
+ <message>
+ <source>&Connect Network Adapter</source>
+ <translation>เ&ชื่อมต่อแผงวงจรเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Connect Network Adapter &%1</source>
+ <translation>เชื่อมต่อแผงวงจรเครือข่าย &%1</translation>
+ </message>
+ <message>
+ <source>No USB Devices Connected</source>
+ <translation>ไม่ได้เชื่อมต่ออุปกรณ์ USB</translation>
+ </message>
+ <message>
+ <source>No supported devices connected to the host PC</source>
+ <translation>ไม่มีอุปกรณ์ที่รองรับเชื่อมต่ออยู่กับพีซีโฮสต์</translation>
+ </message>
+ <message>
+ <source>No Webcams Connected</source>
+ <translation>ไม่ได้เชื่อมต่อเว็บแคม</translation>
+ </message>
+ <message>
+ <source>No supported webcams connected to the host PC</source>
+ <translation>ไม่มีเว็บแคมที่รองรับเชื่อมต่ออยู่กับพีซีโฮสต์</translation>
+ </message>
+ <message>
+ <source>Create new virtual machine</source>
+ <translation>สร้างเวอร์ชวลแมชชีนใหม่</translation>
+ </message>
+ <message>
+ <source>Add existing virtual machine</source>
+ <translation>เพิ่มเวอร์ชวลแมชชีนที่มีอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>Rename selected virtual machine group</source>
+ <translation>เปลี่ยนชื่อกลุ่มเวอร์ชวลแมชชีนที่เลือกไว้</translation>
+ </message>
+ <message>
+ <source>&Ungroup</source>
+ <translation>เ&ลิกจัดกลุ่ม</translation>
+ </message>
+ <message>
+ <source>Ungroup items of selected virtual machine group</source>
+ <translation>เลิกการจัดกลุ่มของเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>&Sort</source>
+ <translation>&จัดเรียง</translation>
+ </message>
+ <message>
+ <source>Sort items of selected virtual machine group alphabetically</source>
+ <translation>จัดเรียงรายการกลุ่มเวอร์ชวลแมชชีนที่เลือกตามลำดับตัวอักษร</translation>
+ </message>
+ <message>
+ <source>Add new group based on selected virtual machines</source>
+ <translation>เพิ่มกลุ่มใหม่ด้วยเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>Clone selected virtual machine</source>
+ <translation>โคลนเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>Remove selected virtual machines</source>
+ <translation>นำเวอร์ชวลแมชชีนที่เลือกไว้ออก</translation>
+ </message>
+ <message>
+ <source>Start selected virtual machines</source>
+ <translation>เริ่มเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>Switch to the windows of selected virtual machines</source>
+ <translation>สลับไปยังหน้าต่างของเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>Start selected virtual machines in the background</source>
+ <translation>เริ่มเวอร์ชวลแมชชีนที่เลือกโดยให้ทำงานอยู่เบื้องหลัง</translation>
+ </message>
+ <message>
+ <source>Start selected virtual machines with option of continuing in background</source>
+ <translation>เริ่มเวอร์ชวลแมชชีนที่เลือกโดยมีตัวเลือกให้สามาถทำงานต่อไปอยู่เบื้องหลัง</translation>
+ </message>
+ <message>
+ <source>Suspend execution of selected virtual machines</source>
+ <translation>หยุดการประมวลผลเวอร์ชวลแมชชีนที่เลือกชั่วคราว</translation>
+ </message>
+ <message>
+ <source>Reset selected virtual machines</source>
+ <translation>รีเซ็ตเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>D&iscard Saved State...</source>
+ <translation>&ทิ้งสถานะที่บันทึกไว้...</translation>
+ </message>
+ <message>
+ <source>Discard saved state of selected virtual machines</source>
+ <translation>ทิ้งสถานะที่บันทึกไว้ของเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>Show log files of selected virtual machines</source>
+ <translation>แสดงล็อกไฟล์ของเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>Re&fresh</source>
+ <translation>เรียก&ซ้ำ</translation>
+ </message>
+ <message>
+ <source>Refresh accessibility state of selected virtual machines</source>
+ <translation>เรียกซ้ำสถานะการเข้าถึงของเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>S&how in Finder</source>
+ <translation>แ&สดงในไฟน์เดอร์</translation>
+ </message>
+ <message>
+ <source>Show the VirtualBox Machine Definition files in Finder</source>
+ <translation>แสดงไฟล์คำอธิบายเวอร์ชวลแมชชีนในไฟน์เดอร์</translation>
+ </message>
+ <message>
+ <source>S&how in Explorer</source>
+ <translation>แ&สดงในเอ็กซ์พลอเรอร์</translation>
+ </message>
+ <message>
+ <source>Show the VirtualBox Machine Definition files in Explorer</source>
+ <translation>แสดงไฟล์คำอธิบายเวอร์ชวลแมชชีนในเอ็กซ์พลอเรอร์</translation>
+ </message>
+ <message>
+ <source>S&how in File Manager</source>
+ <translation>แ&สดงในไฟล์แมเนเจอร์</translation>
+ </message>
+ <message>
+ <source>Show the VirtualBox Machine Definition files in the File Manager</source>
+ <translation>แสดงไฟล์คำอธิบายเวอร์ชวลแมชชีนในไฟล์แมเนเจอร์</translation>
+ </message>
+ <message>
+ <source>Cr&eate Alias on Desktop</source>
+ <translation>สร้าง&ทางลัดไว้บนเดสก์ทอป</translation>
+ </message>
+ <message>
+ <source>Create alias files to the VirtualBox Machine Definition files on your desktop</source>
+ <translation>สร้างไฟล์ทางลัดไปยังไฟล์คำอธิบายเวอร์ชวลแมชชีนไว้บนเดสก์ทอปของคุณ</translation>
+ </message>
+ <message>
+ <source>Cr&eate Shortcut on Desktop</source>
+ <translation>ส&ร้างทางลัดไว้บนเดสก์ทอป</translation>
+ </message>
+ <message>
+ <source>Create shortcut files to the VirtualBox Machine Definition files on your desktop</source>
+ <translation>สร้างไฟล์ทางลัดไปยังไฟล์คำอธิบายเวอร์ชวลแมชชีนไว้บนเดสก์ทอปของคุณ</translation>
+ </message>
+ <message>
+ <source>Sort group of first selected virtual machine alphabetically</source>
+ <translation>จัดเรียงรายการกลุ่มเวอร์ชวลแมชชีนที่เลือกตามลำดับตัวอักษร</translation>
+ </message>
+ <message>
+ <source>Save state of selected virtual machines</source>
+ <translation>บันทึกสถานะของเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+ <message>
+ <source>Send ACPI Shutdown signal to selected virtual machines</source>
+ <translation>ส่งสัญญาณปิดเครื่องแบบ ACPI ไปยังเวอร์ชวลแมชชีนที่เลือกไว้</translation>
+ </message>
+ <message>
+ <source>Power off selected virtual machines</source>
+ <translation>ปิดสวิทช์เวอร์ชวลแมชชีนที่เลือกไว้</translation>
+ </message>
+ <message>
+ <source>&VirtualBox Bug Tracker...</source>
+ <translation>ติดตามบั๊กเ&วอร์ชวลบอกซ์...</translation>
+ </message>
+ <message>
+ <source>Open the browser and go to the VirtualBox product bug tracker</source>
+ <translation>เปิดเบราว์เซอร์แล้วไปยังระบบติดตามบั๊กของเวอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>&VirtualBox Forums...</source>
+ <translation>ฟอรัมเ&วอร์ชวลบอกซ์...</translation>
+ </message>
+ <message>
+ <source>Open the browser and go to the VirtualBox product forums</source>
+ <translation>เปิดเบราว์เซอร์แล้วไปยังฟอรัมเวอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>&Oracle Web Site...</source>
+ <translation>เว็บไซต์&ออราเคิล...</translation>
+ </message>
+ <message>
+ <source>Open the browser and go to the Oracle web site</source>
+ <translation>เปิดเบราว์เซอร์แล้วไปเว็บไซต์ของออราเคิล</translation>
+ </message>
+ <message>
+ <source>&Detach GUI</source>
+ <translation>แ&ยกจาก GUI</translation>
+ </message>
+ <message>
+ <source>Detach the GUI from headless VM</source>
+ <translation>แยกส่วนของ GUI ออกจาก VM ไร้จอแสดงผล</translation>
+ </message>
+ <message>
+ <source>Disable Dock Icon Overlay</source>
+ <translation>ปิดการซ้อนทับด็อคไอคอน</translation>
+ </message>
+</context>
+<context>
+ <name>UIAddDiskEncryptionPasswordDialog</name>
+ <message>
+ <source>%1 - Disk Encryption</source>
+ <translation>การเข้ารหัสลับดิสก์ - %1</translation>
+ </message>
+ <message numerus="yes">
+ <source>This virtual machine is password protected. Please enter the %n encryption password(s) below.</source>
+ <comment>This text is never used with n == 0. Feel free to drop the %n where possible, we only included it because of problems with Qt Linguist (but the user can see how many passwords are in the list and doesn't need to be told).</comment>
+ <translation>
+ <numerusform>เวอร์ชวลแมชชีนเครื่องนี้ได้รับการปกป้องด้วยรหัสผ่าน โปรดป้อนรหัสผ่านการเข้ารหัสลับ %n ด้านล่าง</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>ID</source>
+ <comment>password table field</comment>
+ <translation>ไอดี</translation>
+ </message>
+ <message>
+ <source>Password</source>
+ <comment>password table field</comment>
+ <translation>รหัสผ่าน</translation>
+ </message>
+ <message numerus="yes">
+ <source><nobr>Used by the following %n hard disk(s):</nobr><br>%1</source>
+ <comment>This text is never used with n == 0. Feel free to drop the %n where possible, we only included it because of problems with Qt Linguist (but the user can see how many hard drives are in the tool-tip and doesn't need to be told).</comment>
+ <translation>
+ <numerusform><nobr>ถูกใช้โดย %n ฮาร์ดดิสก์ต่อไปนี้:</nobr><br>%1</numerusform>
+ </translation>
+ </message>
+</context>
+<context>
+ <name>UIApplianceEditorWidget</name>
+ <message>
+ <source>Virtual System %1</source>
+ <translation>ระบบเสมือน %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Product</source>
+ <translation>ผลิตภัณฑ์</translation>
+ </message>
+ <message>
+ <source>Product-URL</source>
+ <translation>URL ของผลิตภัณฑ์</translation>
+ </message>
+ <message>
+ <source>Vendor</source>
+ <translation>ผู้ผลิต</translation>
+ </message>
+ <message>
+ <source>Vendor-URL</source>
+ <translation>URL ของผู้ผลิต</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>รุ่น</translation>
+ </message>
+ <message>
+ <source>Description</source>
+ <translation>คำอธิบาย</translation>
+ </message>
+ <message>
+ <source>License</source>
+ <translation>ไลเซนส์</translation>
+ </message>
+ <message>
+ <source>Guest OS Type</source>
+ <translation>ชนิดของเกสต์โอเอส</translation>
+ </message>
+ <message>
+ <source>CPU</source>
+ <translation>ซีพียู</translation>
+ </message>
+ <message>
+ <source>RAM</source>
+ <translation>แรม</translation>
+ </message>
+ <message>
+ <source>DVD</source>
+ <translation>ดีวีดี</translation>
+ </message>
+ <message>
+ <source>Floppy</source>
+ <translation>ฟลอปปี้</translation>
+ </message>
+ <message>
+ <source>Network Adapter</source>
+ <translation>แผงวงจรเครือข่าย</translation>
+ </message>
+ <message>
+ <source>USB Controller</source>
+ <translation>ตัวควบคุม USB</translation>
+ </message>
+ <message>
+ <source>Sound Card</source>
+ <translation>การ์ดเสียง</translation>
+ </message>
+ <message>
+ <source>Virtual Disk Image</source>
+ <translation>ดิสก์อิมเมจเสมือน</translation>
+ </message>
+ <message>
+ <source>Unknown Hardware Item</source>
+ <translation>ฮาร์ดแวร์ที่ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source><b>Original Value:</b> %1</source>
+ <translation><b>ค่าดั้งเดิม:</b> %1</translation>
+ </message>
+ <message>
+ <source>Configuration</source>
+ <translation>การตั้งค่า</translation>
+ </message>
+ <message>
+ <source>Warnings:</source>
+ <translation>คำเตือน:</translation>
+ </message>
+ <message>
+ <source>When checked a new unique MAC address will assigned to all configured network cards.</source>
+ <translation>เลือกที่นี่หากต้องการกำหนดค่าแมคแอดเดรสใหม่ที่ไม่ซ้ำกันให้กับแผงวงจรเครือข่ายทั้งหมด</translation>
+ </message>
+ <message>
+ <source>&Reinitialize the MAC address of all network cards</source>
+ <translation>&กำหนดค่าแมคแอดเดรสใหม่ให้แผงวงจรเครือข่ายทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Storage Controller (IDE)</source>
+ <translation>ตัวควบคุมหน่วยเก็บข้อมูล (IDE)</translation>
+ </message>
+ <message>
+ <source>Storage Controller (SATA)</source>
+ <translation>ตัวควบคุมหน่วยเก็บข้อมูล (SATA)</translation>
+ </message>
+ <message>
+ <source>Storage Controller (SCSI)</source>
+ <translation>ตัวควบคุมหน่วยเก็บข้อมูล (SCSI)</translation>
+ </message>
+ <message>
+ <source>Storage Controller (SAS)</source>
+ <translation>ตัวควบคุมหน่วยเก็บข้อมูล (SAS)</translation>
+ </message>
+</context>
+<context>
+ <name>UIApplianceImportEditorWidget</name>
+ <message>
+ <source>Importing Appliance ...</source>
+ <translation>กำลังนำเข้าแอพพลายแอนซ์ ...</translation>
+ </message>
+ <message>
+ <source>Reading Appliance ...</source>
+ <translation>กำลังอ่านแอพพลายแอนซ์ ...</translation>
+ </message>
+</context>
+<context>
+ <name>UIApplianceUnverifiedCertificateViewer</name>
+ <message>
+ <source>Unverifiable Certificate! Continue?</source>
+ <translation>ไม่สามารถยืนยันใบรับรองได้! ทำต่อไป?</translation>
+ </message>
+ <message>
+ <source><b>The appliance is signed by an unverified self signed certificate issued by '%1'. We recommend to only proceed with the importing if you are sure you should trust this entity.</b></source>
+ <translation><b>แอพพลายแอนซ์นี้ถูกเซ็นและรับรองโดยใบรับรองแบบเซ็นด้วยตนเองที่ไม่ได้รับการยืนยัน ออกโดย '%1' เราขอแนะนำให้คุณดำเนินการนำเข้าต่อไปก็ต่อเมื่อคุณมั่นใจว่าคุณเชื่อถือผู้รับรองรายนี้</b></translation>
+ </message>
+ <message>
+ <source><b>The appliance is signed by an unverified certificate issued to '%1'. We recommend to only proceed with the importing if you are sure you should trust this entity.</b></source>
+ <translation><b>แอพพลายแอนซ์นี้ถูกเซ็นและรับรองโดยใบรับรองที่ไม่ได้รับการยืนยัน ออกโดย '%1' เราขอแนะนำให้คุณดำเนินการนำเข้าต่อไปก็ต่อเมื่อคุณมั่นใจว่าคุณเชื่อถือผู้รับรองรายนี้</b></translation>
+ </message>
+ <message>
+ <source>True</source>
+ <translation>จริง</translation>
+ </message>
+ <message>
+ <source>False</source>
+ <translation>เท็จ</translation>
+ </message>
+ <message>
+ <source><tr><td>%1:</td><td>%2</td></tr></source>
+ <comment>key: value</comment>
+ <translation><tr><td>%1:</td><td>%2</td></tr></translation>
+ </message>
+ <message>
+ <source>Issuer</source>
+ <translation>ผู้ออก</translation>
+ </message>
+ <message>
+ <source>Subject</source>
+ <translation>เรื่อง</translation>
+ </message>
+ <message>
+ <source>Not Valid Before</source>
+ <translation>ไม่มีผลก่อน</translation>
+ </message>
+ <message>
+ <source>Not Valid After</source>
+ <translation>ไม่มีผลหลังจาก</translation>
+ </message>
+ <message>
+ <source>Serial Number</source>
+ <translation>ลำดับที่</translation>
+ </message>
+ <message>
+ <source>Self-Signed</source>
+ <translation>เซ็นด้วยตนเอง</translation>
+ </message>
+ <message>
+ <source>Authority (CA)</source>
+ <translation>ผู้มีอำนาจรับรอง (CA)</translation>
+ </message>
+ <message>
+ <source>Public Algorithm</source>
+ <translation>อัลกอริธึมสาธารณะ</translation>
+ </message>
+ <message>
+ <source>%1 (%2)</source>
+ <comment>value (clarification)</comment>
+ <translation></translation>
+ </message>
+ <message>
+ <source>Signature Algorithm</source>
+ <translation>อัลกอริธึมลายเซ็น</translation>
+ </message>
+ <message>
+ <source>X.509 Version Number</source>
+ <translation>หมายเลขรุ่น X.509</translation>
+ </message>
+</context>
+<context>
+ <name>UIDetailsPagePrivate</name>
+ <message>
+ <source>The selected virtual machine is <i>inaccessible</i>. Please inspect the error message shown below and press the <b>Refresh</b> button if you want to repeat the accessibility check:</source>
+ <translation>เวอร์ชวลแมชชีนที่เลือก<i>ไม่สามารถเข้าถึงได้</i> กรุณาตรวจสอบข้อผิดพลาดที่แสดงด้านล่าง และกดปุ่ม<b>เรียกซ้ำ</b>หากต้องการตรวจสอบการเข้าถึงอีกครั้ง:</translation>
+ </message>
+</context>
+<context>
+ <name>UIDnDHandler</name>
+ <message>
+ <source>Dropping data ...</source>
+ <translation>กำลังทิ้งข้อมูล ...</translation>
+ </message>
+ <message>
+ <source>Retrieving data ...</source>
+ <translation>กำลังรับข้อมูล ...</translation>
+ </message>
+</context>
+<context>
+ <name>UIDownloader</name>
+ <message>
+ <source>Looking for %1...</source>
+ <translation>กำลังมองหา %1...</translation>
+ </message>
+ <message>
+ <source>Downloading %1...</source>
+ <translation>กำลังดาวน์โหลด %1...</translation>
+ </message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>UIDownloaderAdditions</name>
+ <message>
+ <source>Select folder to save Guest Additions image to</source>
+ <translation>เลือกโฟลเดอร์เพื่อบันทึกอิมเมจโปรแกรมเสริมสำหรับเกสต์</translation>
+ </message>
+ <message>
+ <source>VirtualBox Guest Additions</source>
+ <translation>โปรแกรมเสริมสำหรับเกสต์เวอร์ชวลบอกซ์</translation>
+ </message>
+</context>
+<context>
+ <name>UIDownloaderExtensionPack</name>
+ <message>
+ <source>Select folder to save %1 to</source>
+ <translation>เลือกโฟลเดอร์เพื่อบันทึก %1</translation>
+ </message>
+ <message>
+ <source>VirtualBox Extension Pack</source>
+ <translation>แพคขยายสำหรับเวอร์ชวลบอกซ์</translation>
+ </message>
+</context>
+<context>
+ <name>UIDownloaderUserManual</name>
+ <message>
+ <source>Select folder to save User Manual to</source>
+ <translation>เลือกโฟลเดอร์เพื่อบันทึกคู่มือ</translation>
+ </message>
+ <message>
+ <source>VirtualBox User Manual</source>
+ <translation>คู่มือใช้งานเวอร์ชวลบอกซ์</translation>
+ </message>
+</context>
+<context>
+ <name>UIEmptyFilePathSelector</name>
+ <message>
+ <source>Choose...</source>
+ <translation>เลือก...</translation>
+ </message>
+</context>
+<context>
+ <name>UIFilePathSelector</name>
+ <message>
+ <source>&Copy</source>
+ <translation>&คัดลอก</translation>
+ </message>
+ <message>
+ <source>Other...</source>
+ <translation>อื่น ๅ ...</translation>
+ </message>
+ <message>
+ <source>Reset</source>
+ <translation>รีเซ็ต</translation>
+ </message>
+ <message>
+ <source>Displays a window to select a different folder.</source>
+ <translation>แสดงหน้าต่างเพื่อเลือกโฟลเดอร์อื่น</translation>
+ </message>
+ <message>
+ <source>Resets the folder path to the default value.</source>
+ <translation>รีเซ็ตเส้นทางโฟลเดอร์ไปเป็นค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source>Displays a window to select a different file.</source>
+ <translation>แสดงหน้าต่างเพื่อเลือกไฟล์อื่น</translation>
+ </message>
+ <message>
+ <source>Resets the file path to the default value.</source>
+ <translation>รีเซ็ตเส้นทางของไฟล์ไปเป็นค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source><reset to default></source>
+ <translation><รีเซ็ตเป็นค่าตั้งต้น></translation>
+ </message>
+ <message>
+ <source>The actual default path value will be displayed after accepting the changes and opening this window again.</source>
+ <translation>ค่าเส้นทางตั้งต้นจะถูกแสดงหลังจากยอมรับการเปลี่ยนแปลงและทำการเปิดหน้าต่างนี้อีกครั้ง</translation>
+ </message>
+ <message>
+ <source><not selected></source>
+ <translation><ไม่ได้เลือก></translation>
+ </message>
+ <message>
+ <source>Please use the <b>Other...</b> item from the drop-down list to select a path.</source>
+ <translation>กรุณาเลือก <b>อื่น ๆ ...</b> จากดรอปดาวน์ลิสต์เพื่อเลือกเส้นทางที่ต้องการ</translation>
+ </message>
+ <message>
+ <source>Holds the folder path.</source>
+ <translation>เก็บเส้นทางโฟลเดอร์</translation>
+ </message>
+ <message>
+ <source>Holds the file path.</source>
+ <translation>เก็บเส้นทางของไฟล์</translation>
+ </message>
+</context>
+<context>
+ <name>UIGChooserItemGroup</name>
+ <message>
+ <source><b>%1</b></source>
+ <comment>Group item tool-tip / Group name</comment>
+ <translation><b>%1</b></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n group(s)</source>
+ <comment>Group item tool-tip / Group info</comment>
+ <translation>
+ <numerusform>%n กลุ่ม</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source><nobr>%1</nobr></source>
+ <comment>Group item tool-tip / Group info wrapper</comment>
+ <translation><nobr>%1</nobr></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n machine(s)</source>
+ <comment>Group item tool-tip / Machine info</comment>
+ <translation>
+ <numerusform>%n เครื่อง</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>(%n running)</source>
+ <comment>Group item tool-tip / Running machine info</comment>
+ <translation>
+ <numerusform>(%n ทำงานอยู่)</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source><nobr>%1</nobr></source>
+ <comment>Group item tool-tip / Machine info wrapper</comment>
+ <translation><nobr>%1</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>%1 %2</nobr></source>
+ <comment>Group item tool-tip / Machine info wrapper, including running</comment>
+ <translation><nobr>%1 %2</nobr></translation>
+ </message>
+ <message>
+ <source>Collapse group</source>
+ <translation>ยุบกลุ่ม</translation>
+ </message>
+ <message>
+ <source>Expand group</source>
+ <translation>ขยายกลุ่ม</translation>
+ </message>
+ <message>
+ <source>Enter group</source>
+ <translation>เข้ากลุ่ม</translation>
+ </message>
+ <message>
+ <source>Exit group</source>
+ <translation>ออกจากกลุ่ม</translation>
+ </message>
+</context>
+<context>
+ <name>UIGChooserModel</name>
+ <message>
+ <source>New group</source>
+ <translation>กลุ่มใหม่</translation>
+ </message>
+</context>
+<context>
+ <name>UIGDetails</name>
+ <message>
+ <source>Name</source>
+ <comment>details (general)</comment>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Groups</source>
+ <comment>details (general)</comment>
+ <translation>กลุ่ม</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <comment>details</comment>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>Processors</source>
+ <comment>details (system)</comment>
+ <translation>โปรเซสเซอร์</translation>
+ </message>
+ <message>
+ <source>%1%</source>
+ <comment>details</comment>
+ <translation>%1%</translation>
+ </message>
+ <message>
+ <source>VT-x/AMD-V</source>
+ <comment>details (system)</comment>
+ <translation>VT-x/AMD-V</translation>
+ </message>
+ <message>
+ <source>PAE/NX</source>
+ <comment>details (system)</comment>
+ <translation>PAE/NX</translation>
+ </message>
+ <message>
+ <source>Acceleration</source>
+ <comment>details (system)</comment>
+ <translation>ตัวเร่งความเร็ว</translation>
+ </message>
+ <message>
+ <source>Screens</source>
+ <comment>details (display)</comment>
+ <translation>หน้าจอ</translation>
+ </message>
+ <message>
+ <source>3D</source>
+ <comment>details (display)</comment>
+ <translation>3D</translation>
+ </message>
+ <message>
+ <source>Acceleration</source>
+ <comment>details (display)</comment>
+ <translation>ตัวเร่งความเร็ว</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (display/vrde/VRDE server)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Controller</source>
+ <comment>details (audio)</comment>
+ <translation>ตัวควบคุม</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (audio)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Adapter %1</source>
+ <comment>details (network)</comment>
+ <translation>แผงวงจร %1</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (network/adapter)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Port %1</source>
+ <comment>details (serial)</comment>
+ <translation>พอร์ต %1</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (serial)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Port %1</source>
+ <comment>details (parallel)</comment>
+ <translation>พอร์ต %1</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (parallel)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>%1 (%2 active)</source>
+ <comment>details (usb)</comment>
+ <translation>%1 (%2 ใช้งานอยู่)</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (usb)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <comment>details (shared folders)</comment>
+ <translation>ไม่มี</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <comment>details (description)</comment>
+ <translation>ไม่มี</translation>
+ </message>
+ <message>
+ <source>Operating System</source>
+ <comment>details (general)</comment>
+ <translation>ระบบปฏิบัติการ</translation>
+ </message>
+ <message>
+ <source>Information Inaccessible</source>
+ <comment>details</comment>
+ <translation>ไม่สามารถเข้าถึงข้อมูลได้</translation>
+ </message>
+ <message>
+ <source>Base Memory</source>
+ <comment>details (system)</comment>
+ <translation>หน่วยความจำพื้นฐาน</translation>
+ </message>
+ <message>
+ <source>Execution Cap</source>
+ <comment>details (system)</comment>
+ <translation>จำกัดการประมวลผล</translation>
+ </message>
+ <message>
+ <source>Boot Order</source>
+ <comment>details (system)</comment>
+ <translation>ลำดับการบูต</translation>
+ </message>
+ <message>
+ <source>Nested Paging</source>
+ <comment>details (system)</comment>
+ <translation>การแบ่งหน้าซ้อนกัน</translation>
+ </message>
+ <message>
+ <source>Video Memory</source>
+ <comment>details (display)</comment>
+ <translation>หน่วยความจำแสดงผล</translation>
+ </message>
+ <message>
+ <source>2D Video</source>
+ <comment>details (display)</comment>
+ <translation>การแสดงผล 2D</translation>
+ </message>
+ <message>
+ <source>Remote Desktop Server Port</source>
+ <comment>details (display/vrde)</comment>
+ <translation>พอร์ตเซอร์ฟเวอร์รีโมตเดสก์ทอป</translation>
+ </message>
+ <message>
+ <source>Remote Desktop Server</source>
+ <comment>details (display/vrde)</comment>
+ <translation>เซอร์ฟเวอร์รีโมตเดสก์ทอป</translation>
+ </message>
+ <message>
+ <source>Not Attached</source>
+ <comment>details (storage)</comment>
+ <translation>ไม่ได้เชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>Host Driver</source>
+ <comment>details (audio)</comment>
+ <translation>ไดร์เวอร์ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Bridged Adapter, %1</source>
+ <comment>details (network)</comment>
+ <translation>แผงวงจรแบบบริดจ์, %1</translation>
+ </message>
+ <message>
+ <source>Internal Network, '%1'</source>
+ <comment>details (network)</comment>
+ <translation>เครือข่ายภายใน, '%1'</translation>
+ </message>
+ <message>
+ <source>Host-only Adapter, '%1'</source>
+ <comment>details (network)</comment>
+ <translation>แผงวงจรเฉพาะโฮสต์, '%1'</translation>
+ </message>
+ <message>
+ <source>Generic Driver, '%1'</source>
+ <comment>details (network)</comment>
+ <translation>ไดร์เวอร์ทั่วไป, '%1'</translation>
+ </message>
+ <message>
+ <source>Device Filters</source>
+ <comment>details (usb)</comment>
+ <translation>ตัวกรองอุปกรณ์</translation>
+ </message>
+ <message>
+ <source>USB Controller Inaccessible</source>
+ <comment>details (usb)</comment>
+ <translation>ไม่สามารถเข้าถึงตัวควบคุม USB</translation>
+ </message>
+ <message>
+ <source>Shared Folders</source>
+ <comment>details (shared folders)</comment>
+ <translation>โฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>Video Capture File</source>
+ <comment>details (display/video capture)</comment>
+ <translation>ไฟล์สำหรับการจับภาพวิดีโอ</translation>
+ </message>
+ <message>
+ <source>Video Capture Attributes</source>
+ <comment>details (display/video capture)</comment>
+ <translation>ลักษณะเฉพาะของการจับภาพวิดีโอ</translation>
+ </message>
+ <message>
+ <source>Video Capture</source>
+ <comment>details (display/video capture)</comment>
+ <translation>การจับภาพวิดีโอ</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (display/video capture)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>NAT Network, '%1'</source>
+ <comment>details (network)</comment>
+ <translation>เครือข่าย NAT '%1'</translation>
+ </message>
+ <message>
+ <source>Frame Size: %1x%2, Frame Rate: %3fps, Bit Rate: %4kbps</source>
+ <translation>ขนาดของเฟรม: %1x%2 อัตราเฟรม: %3fps อัตราบิต: %4kbps</translation>
+ </message>
+ <message>
+ <source>Minimal Paravirtualization</source>
+ <comment>details (system)</comment>
+ <translation>พาราเวอร์ชวลไลเซชันขั้นต่ำ</translation>
+ </message>
+ <message>
+ <source>Hyper-V Paravirtualization</source>
+ <comment>details (system)</comment>
+ <translation>พาราเวอร์ชวลไลเซชัน Hyper-V</translation>
+ </message>
+ <message>
+ <source>KVM Paravirtualization</source>
+ <comment>details (system)</comment>
+ <translation>พาราเวอร์ชวลไลเซชัน KVM</translation>
+ </message>
+ <message>
+ <source>[Optical Drive]</source>
+ <comment>details (storage)</comment>
+ <translation>[ไดรฟ์ออปติคัล]</translation>
+ </message>
+ <message>
+ <source>USB Controller</source>
+ <comment>details (usb)</comment>
+ <translation>ตัวควบคุม USB</translation>
+ </message>
+ <message>
+ <source>Mini-toolbar Position</source>
+ <comment>details (user interface)</comment>
+ <translation>ตำแหน่งแถบเครื่องมือขนาดเล็ก</translation>
+ </message>
+ <message>
+ <source>Top</source>
+ <comment>details (user interface/mini-toolbar position)</comment>
+ <translation>ด้านบน</translation>
+ </message>
+ <message>
+ <source>Bottom</source>
+ <comment>details (user interface/mini-toolbar position)</comment>
+ <translation>ด้านล่าง</translation>
+ </message>
+ <message>
+ <source>Mini-toolbar</source>
+ <comment>details (user interface)</comment>
+ <translation>แถบเครื่องมือขนาดเล็ก</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (user interface/mini-toolbar)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Scale-factor</source>
+ <comment>details (display)</comment>
+ <translation>ค่าสเกล</translation>
+ </message>
+ <message>
+ <source>Unscaled HiDPI Video Output</source>
+ <comment>details (display)</comment>
+ <translation>การแสดงผล HiDPI แบบไม่สเกล</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details (display/Unscaled HiDPI Video Output)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Menu-bar</source>
+ <comment>details (user interface)</comment>
+ <translation>แถบเมนู</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details (user interface/menu-bar)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (user interface/menu-bar)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Status-bar</source>
+ <comment>details (user interface)</comment>
+ <translation>แถบสถานะ</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details (user interface/status-bar)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details (user interface/status-bar)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Generic Driver, '%1' { %2 }</source>
+ <comment>details (network)</comment>
+ <translation>ไดร์เวอร์ทั่วไป, '%1' { %2 }</translation>
+ </message>
+</context>
+<context>
+ <name>UIGMachinePreview</name>
+ <message>
+ <source>Every 0.5 s</source>
+ <translation>ทุก 0.5 วินาที</translation>
+ </message>
+ <message>
+ <source>Every 1 s</source>
+ <translation>ทุก 1 วินาที</translation>
+ </message>
+ <message>
+ <source>Every 2 s</source>
+ <translation>ทุก 2 วินาที</translation>
+ </message>
+ <message>
+ <source>Every 5 s</source>
+ <translation>ทุก 5 วินาที</translation>
+ </message>
+ <message>
+ <source>Every 10 s</source>
+ <translation>ทุก 10 วินาที</translation>
+ </message>
+ <message>
+ <source>Update disabled</source>
+ <translation>ปิดการอัพเดต</translation>
+ </message>
+ <message>
+ <source>No preview</source>
+ <translation>ไม่แสดงตัวอย่าง</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsDisplay</name>
+ <message>
+ <source>Maximum Guest Screen &Size:</source>
+ <translation>&ขนาดหน้าจอสูงสุดของเกสต์:</translation>
+ </message>
+ <message>
+ <source>&Width:</source>
+ <translation>ความ&กว้าง:</translation>
+ </message>
+ <message>
+ <source>&Height:</source>
+ <translation>ความสู&ง:</translation>
+ </message>
+ <message>
+ <source>Automatic</source>
+ <comment>Maximum Guest Screen Size</comment>
+ <translation>อัตโนมัติ</translation>
+ </message>
+ <message>
+ <source>Suggest a reasonable maximum screen size to the guest. The guest will only see this suggestion when guest additions are installed.</source>
+ <translation>แนะนำขนาดหน้าจอสูงสุดที่เหมาะสมให้กับเกสต์ ค่าที่แนะนำนี้จะแสดงให้เกสต์เห็นก็ต่อเมื่อส่วนขยายสำหรับเกสต์ถูกติดตั้งไว้แล้วเท่านั้น</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <comment>Maximum Guest Screen Size</comment>
+ <translation>ไม่กำหนด</translation>
+ </message>
+ <message>
+ <source>Do not attempt to limit the size of the guest screen.</source>
+ <translation>ไม่ต้องจำกัดขนาดหน้าจอของเกสต์</translation>
+ </message>
+ <message>
+ <source>Hint</source>
+ <comment>Maximum Guest Screen Size</comment>
+ <translation>คำแนะนำ</translation>
+ </message>
+ <message>
+ <source>Suggest a maximum screen size to the guest. The guest will only see this suggestion when guest additions are installed.</source>
+ <translation>แนะนำขนาดหน้าจอสูงสุดให้กับเกสต์ ค่าที่แนะนำนี้จะแสดงให้เกสต์เห็นก็ต่อเมื่อส่วนขยายสำหรับเกสต์ถูกติดตั้งไว้แล้วเท่านั้น</translation>
+ </message>
+ <message>
+ <source>Machine Windows:</source>
+ <translation>หน้าต่างของเครื่อง:</translation>
+ </message>
+ <message>
+ <source>&Raise Window Under Mouse</source>
+ <translation>นำหน้าต่างใต้เมาส์ขึ้นแสดงด้าน&บน</translation>
+ </message>
+ <message>
+ <source>Holds the maximum width which we would like the guest to use.</source>
+ <translation>เก็บความกว้างมากที่สุดที่ต้องการให้เกสต์ใช้งานได้</translation>
+ </message>
+ <message>
+ <source>Holds the maximum height which we would like the guest to use.</source>
+ <translation>เก็บความสูงมากที่สุดที่ต้องการให้เกสต์ใช้งานได้</translation>
+ </message>
+ <message>
+ <source>When checked, machine windows will be raised when the mouse pointer moves over them.</source>
+ <translation>หากเลือกไว้ หน้าต่างของเครื่องจะถูกนำขึ้นมาแสดงด้านบนเมื่อตัวชี้เมาส์เลื่อนมาอยู่เหนือหน้าต่าง</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsExtension</name>
+ <message>
+ <source>Lists all installed packages.</source>
+ <translation>แสดงแพคเกจที่ติดตั้งไว้ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Active</source>
+ <translation>ใช้งานอยู่</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Version</source>
+ <translation>รุ่น</translation>
+ </message>
+ <message>
+ <source>Select an extension package file</source>
+ <translation>เลือกไฟล์แพคเกจส่วนขยาย</translation>
+ </message>
+ <message>
+ <source>Extension package files (%1)</source>
+ <translation>ไฟล์แพคเกจส่วนขยาย (%1)</translation>
+ </message>
+ <message>
+ <source>Extensions</source>
+ <translation>ส่วนขยาย</translation>
+ </message>
+ <message>
+ <source>&Extension Packages</source>
+ <translation>แพคเกจส่วน&ขยาย</translation>
+ </message>
+ <message>
+ <source>Add Package</source>
+ <translation>เพิ่มแพคเกจ</translation>
+ </message>
+ <message>
+ <source>Remove Package</source>
+ <translation>นำแพคเกจออก</translation>
+ </message>
+ <message>
+ <source>Adds new package.</source>
+ <translation>เพิ่มแพคเกจใหม่</translation>
+ </message>
+ <message>
+ <source>Removes selected package.</source>
+ <translation>นำแพคเกจที่เลือกออก</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsGeneral</name>
+ <message>
+ <source>Holds the path to the default virtual machine folder. This folder is used, if not explicitly specified otherwise, when creating new virtual machines.</source>
+ <translation>เก็บค่าเส้นทางไปยังโฟลเดอร์ตั้งต้นของเวอร์ชวลแมชชีน หากไม่ได้กำหนดไว้ที่อื่น โฟลเดอร์นี้จะถูกใช้ขณะสร้างเวอร์ชวลแมชชีนใหม่</translation>
+ </message>
+ <message>
+ <source>Holds the path to the library that provides authentication for Remote Display (VRDP) clients.</source>
+ <translation>เก็บค่าเส้นทางไปยังไลบรารีที่ให้บริการพิสูจน์ตัวตนสำหรับไคลเอนต์แสดงผลจากระยะไกล (VRDP)</translation>
+ </message>
+ <message>
+ <source>Default &Machine Folder:</source>
+ <translation>โฟลเดอร์ตั้งต้นของเ&ครื่อง:</translation>
+ </message>
+ <message>
+ <source>V&RDP Authentication Library:</source>
+ <translation>ไลบรารียืนยันตัวตน V&RDP:</translation>
+ </message>
+ <message>
+ <source>When checked, the host screensaver will be disabled whenever a virtual machine is running.</source>
+ <translation>เลือกที่นี่หากต้องการปิดโปรแกรมพักหน้าจอของโฮสต์ขณะที่มีเวอร์ชวลแมชชีนทำงานอยู่</translation>
+ </message>
+ <message>
+ <source>Host Screensaver:</source>
+ <translation>ตัวพักหน้าจอโฮสต์:</translation>
+ </message>
+ <message>
+ <source>&Disable When Running Virtual Machines</source>
+ <translation>&ปิดการใช้งานขณะรันเวอร์ชวลแมชชีน</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsInput</name>
+ <message>
+ <source>When checked, the keyboard is automatically captured every time the VM window is activated. When the keyboard is captured, all keystrokes (including system ones like Alt-Tab) are directed to the VM.</source>
+ <translation>เมื่อเลือก แป้นพิมพ์จะถูกจับไว้โดยอัตโนมัติทุกครั้งที่หน้าต่างเวอร์ชวลแมชชีนถูกเรียกใช้ ขณะจับแป้นพิมพ์ การกดปุ่มทั้งหมด (รวมถึงปุ่มระบบ เช่น Alt-Tab) จะถูกส่งต่อไปยังเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Auto Capture Keyboard</source>
+ <translation>จับแป้นพิมพ์&อัตโนมัติ</translation>
+ </message>
+ <message>
+ <source>Host Key Combination</source>
+ <translation>การผนวกแป้นพิมพ์ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Some items have the same shortcuts assigned.</source>
+ <translation>มีบางรายการที่กำหนดทางลัดซ้ำกัน</translation>
+ </message>
+ <message>
+ <source>&VirtualBox Manager</source>
+ <translation>ตัวจัดการเ&วอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>Virtual &Machine</source>
+ <translation>เวอร์ชวลแ&มชชีน</translation>
+ </message>
+ <message>
+ <source>Lists all available shortcuts which can be configured.</source>
+ <translation>แสดงทางลัดทั้งหมดที่สามารถปรับแต่งได้</translation>
+ </message>
+ <message>
+ <source>Holds a sequence to filter the shortcut list.</source>
+ <translation>เก็บลำดับเพื่อกรองรายการทางลัด</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsLanguage</name>
+ <message>
+ <source> (built-in)</source>
+ <comment>Language</comment>
+ <translation>(บิลท์อิน)</translation>
+ </message>
+ <message>
+ <source><unavailable></source>
+ <comment>Language</comment>
+ <translation><ไม่พร้อมใช้งาน></translation>
+ </message>
+ <message>
+ <source><unknown></source>
+ <comment>Author(s)</comment>
+ <translation><ไม่รู้จัก></translation>
+ </message>
+ <message>
+ <source>Default</source>
+ <comment>Language</comment>
+ <translation>ค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source>Language:</source>
+ <translation>ภาษา</translation>
+ </message>
+ <message>
+ <source>Lists all available user interface languages. The effective language is written in <b>bold</b>. Select <i>Default</i> to reset to the system default language.</source>
+ <translation>แสดงรายการภาษาของส่วนติดต่อผุ้ใช้ทั้งหมดที่พร้อมใช้งาน ภาษาที่ใช้อยู่แสดงเป็น<b>ตัวหนา</b> เลือก <i>ค่าตั้งต้น</i> เพื่อกลับไปใช้ภาษาตั้งต้นของระบบ</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Id</source>
+ <translation>ไอดี</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>ภาษา</translation>
+ </message>
+ <message>
+ <source>Author</source>
+ <translation>ผู้จัดทำ</translation>
+ </message>
+ <message>
+ <source>Author(s):</source>
+ <translation>ผู้จัดทำ:</translation>
+ </message>
+ <message>
+ <source>&Interface Languages</source>
+ <translation>ภาษาของ&ส่วนติดต่อผู้ใช้</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsNetwork</name>
+ <message>
+ <source>Adapter</source>
+ <translation>แผงวงจร</translation>
+ </message>
+ <message>
+ <source>Automatically configured</source>
+ <comment>interface</comment>
+ <translation>ตั้งค่าอัตโนมัติ</translation>
+ </message>
+ <message>
+ <source>Manually configured</source>
+ <comment>interface</comment>
+ <translation>ตั้งค่าด้วยตนเอง</translation>
+ </message>
+ <message>
+ <source>IPv4 Address</source>
+ <translation>ที่อยู่ IPv4</translation>
+ </message>
+ <message>
+ <source>Not set</source>
+ <comment>address</comment>
+ <translation>ไม่ได้กำหนด</translation>
+ </message>
+ <message>
+ <source>IPv4 Network Mask</source>
+ <translation>มาสก์เครือข่าย IPv4</translation>
+ </message>
+ <message>
+ <source>Not set</source>
+ <comment>mask</comment>
+ <translation>ไม่ได้กำหนด</translation>
+ </message>
+ <message>
+ <source>IPv6 Address</source>
+ <translation>ที่อยู่ IPv6</translation>
+ </message>
+ <message>
+ <source>IPv6 Network Mask Length</source>
+ <translation>ความยาวมาสก์เครือข่าย IPv6</translation>
+ </message>
+ <message>
+ <source>Not set</source>
+ <comment>length</comment>
+ <translation>ไม่ได้กำหนด</translation>
+ </message>
+ <message>
+ <source>DHCP Server</source>
+ <translation>เซอร์ฟเวอร์ DHCP</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>server</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>server</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Address</source>
+ <translation>ที่อยู่</translation>
+ </message>
+ <message>
+ <source>Network Mask</source>
+ <translation>มาสก์เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Lower Bound</source>
+ <translation>ที่อยู่เริ่มต้น</translation>
+ </message>
+ <message>
+ <source>Not set</source>
+ <comment>bound</comment>
+ <translation>ไม่ได้กำหนด</translation>
+ </message>
+ <message>
+ <source>Upper Bound</source>
+ <translation>ที่อยู่สุดท้าย</translation>
+ </message>
+ <message>
+ <source>Lists all available host-only networks.</source>
+ <translation>แสดงเครือข่ายเฉพาะโฮสต์ที่ใช้ได้ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Networking</source>
+ <translation>เครือข่าย</translation>
+ </message>
+ <message>
+ <source>&NAT Networks</source>
+ <translation>เครือข่าย &NAT</translation>
+ </message>
+ <message>
+ <source>Lists all available NAT networks.</source>
+ <translation>แสดงเครือข่าย NAT ที่ใช้ได้ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>&Host-only Networks</source>
+ <translation>เครือข่ายเฉพาะโ&ฮสต์</translation>
+ </message>
+ <message>
+ <source>No new name specified for the NAT network previously called <b>%1</b>.</source>
+ <translation>ไม่ได้กำหนดชื่อใหม่สำหรับเครือข่าย NAT ที่ถูกเรียกใช้ก่อนหน้านี้ <b>%1</b></translation>
+ </message>
+ <message>
+ <source>No CIDR specified for the NAT network <b>%1</b>.</source>
+ <translation>ไม่ได้กำหนด CIDR สำหรับเครือข่าย NAT <b>%1</b></translation>
+ </message>
+ <message>
+ <source>No CIDR specified for the NAT network previously called <b>%1</b>.</source>
+ <translation>ไม่ได้กำหนด CIDR สำหรับเครือข่าย NAT ที่ถูกเรียกใช้ก่อนหน้านี้ <b>%1</b></translation>
+ </message>
+ <message>
+ <source>Invalid CIDR specified (<i>%1</i>) for the NAT network <b>%2</b>.</source>
+ <translation>กำหนด CIDR ไม่ถูกต้อง (<i>%1</i>) สำหรับเครือข่าย NAT <b>%2</b></translation>
+ </message>
+ <message>
+ <source>Invalid CIDR specified (<i>%1</i>) for the NAT network previously called <b>%2</b>.</source>
+ <translation>กำหนด CIDR ไม่ถูกต้อง (<i>%1</i>) สำหรับเครือข่าย NAT ที่ถูกเรียกใช้ก่อนหน้านี้ <b>%2</b></translation>
+ </message>
+ <message>
+ <source>Network Name</source>
+ <translation>ชื่อเครือข่าย</translation>
+ </message>
+ <message>
+ <source>[empty]</source>
+ <translation>[ว่าง]</translation>
+ </message>
+ <message>
+ <source>%1 (renamed from %2)</source>
+ <translation>%1 (เปลี่ยนชื่อจาก %2)</translation>
+ </message>
+ <message>
+ <source>Old Network Name</source>
+ <translation>ชื่อเครือข่ายเดิม</translation>
+ </message>
+ <message>
+ <source>New Network Name</source>
+ <translation>ชื่อเครือข่ายใหม่</translation>
+ </message>
+ <message>
+ <source>Network CIDR</source>
+ <translation>CIDR ของเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Supports DHCP</source>
+ <translation>รองรับ DHCP</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>ใช่</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>ไม่ใช่</translation>
+ </message>
+ <message>
+ <source>Supports IPv6</source>
+ <translation>รองรับ IPv6</translation>
+ </message>
+ <message>
+ <source>Default IPv6 route</source>
+ <translation>เส้นทางตั้งต้น IPv6</translation>
+ </message>
+ <message>
+ <source>Host interface <b>%1</b> does not currently have a valid IPv4 address.</source>
+ <translation>แผงวงจรเครือข่ายของโฮสต์ <b>%1</b> ไม่ได้กำหนดที่อยู่ IPv4 ที่ถูกต้องไว้</translation>
+ </message>
+ <message>
+ <source>Host interface <b>%1</b> does not currently have a valid IPv4 network mask.</source>
+ <translation>แผงวงจรเครือข่ายของโฮสต์ <b>%1</b> ไม่ได้กำหนดเน็ตมาสก์ IPv4 ที่ถูกต้องไว้</translation>
+ </message>
+ <message>
+ <source>Host interface <b>%1</b> does not currently have a valid IPv6 address.</source>
+ <translation>แผงวงจรเครือข่ายของโฮสต์ <b>%1</b> ไม่ได้กำหนดที่อยู่ IPv6 ที่ถูกต้องไว้</translation>
+ </message>
+ <message>
+ <source>Host interface <b>%1</b> does not currently have a valid DHCP server address.</source>
+ <translation>แผงวงจรเครือข่ายของโฮสต์ <b>%1</b> ไม่ได้กำหนดที่อยู่เซอร์ฟเวอร์ DHCP ที่ถูกต้องไว้</translation>
+ </message>
+ <message>
+ <source>Host interface <b>%1</b> does not currently have a valid DHCP server mask.</source>
+ <translation>แผงวงจรเครือข่ายของโฮสต์ <b>%1</b> ไม่ได้กำหนดเน็ตมาสก์เซอร์ฟเวอร์ DHCP ที่ถูกต้องไว้</translation>
+ </message>
+ <message>
+ <source>Host interface <b>%1</b> does not currently have a valid DHCP server lower address bound.</source>
+ <translation>แผงวงจรเครือข่ายของโฮสต์ <b>%1</b> ไม่ได้กำหนดขอบล่างของเซอร์ฟเวอร์ DHCP ที่ถูกต้องไว้</translation>
+ </message>
+ <message>
+ <source>Host interface <b>%1</b> does not currently have a valid DHCP server upper address bound.</source>
+ <translation>แผงวงจรเครือข่ายของโฮสต์ <b>%1</b> ไม่ได้กำหนดขอบบนของเซอร์ฟเวอร์ DHCP ที่ถูกต้องไว้</translation>
+ </message>
+ <message>
+ <source>The name <b>%1</b> is being used for several NAT networks.</source>
+ <translation>ชื่อ <b>%1</b> ถูกใช้กับเครือข่าย NAT มากกว่าหนึ่งเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Active</source>
+ <comment>NAT network</comment>
+ <translation>ใช้งานอยู่</translation>
+ </message>
+ <message>
+ <source>Add NAT Network</source>
+ <translation>เพิ่มเครือข่าย NAT</translation>
+ </message>
+ <message>
+ <source>Remove NAT Network</source>
+ <translation>นำเครือข่าย NAT ออก</translation>
+ </message>
+ <message>
+ <source>Edit NAT Network</source>
+ <translation>แก้ไขเครือข่าย NAT</translation>
+ </message>
+ <message>
+ <source>Adds new NAT network.</source>
+ <translation>เพิ่มเครือข่าย NAT ใหม่</translation>
+ </message>
+ <message>
+ <source>Removes selected NAT network.</source>
+ <translation>นำเครือข่าย NAT ที่เลือกไว้ออก</translation>
+ </message>
+ <message>
+ <source>Edits selected NAT network.</source>
+ <translation>แก้ไขเครือข่าย NAT ที่เลือกไว้</translation>
+ </message>
+ <message>
+ <source>Add Host-only Network</source>
+ <translation>เพิ่มเครือข่ายเฉพาะโฮสต์</translation>
+ </message>
+ <message>
+ <source>Remove Host-only Network</source>
+ <translation>นำเครือข่ายเฉพาะโฮสต์ออก</translation>
+ </message>
+ <message>
+ <source>Edit Host-only Network</source>
+ <translation>แก้ไขเครือข่ายเฉพาะโฮสต์</translation>
+ </message>
+ <message>
+ <source>Adds new host-only network.</source>
+ <translation>เพิ่มเครือข่ายเฉพาะโฮสต์ใหม่</translation>
+ </message>
+ <message>
+ <source>Removes selected host-only network.</source>
+ <translation>นำเครือข่ายเฉพาะโฮสต์ที่เลือกไว้ออก</translation>
+ </message>
+ <message>
+ <source>Edits selected host-only network.</source>
+ <translation>แก้ไขเครือข่ายเฉพาะโฮสต์ที่เลือกไว้</translation>
+ </message>
+ <message>
+ <source>Host interface <b>%1</b> does not currently have a valid IPv6 network mask prefix length.</source>
+ <translation>แผงวงจรเครือข่ายของโฮสต์ <b>%1</b> ไม่ได้กำหนดความยาวส่วนขยายเน็ตมาสก์ IPv6 ที่ถูกต้องไว้</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsNetworkDetailsHost</name>
+ <message>
+ <source>Host-only Network Details</source>
+ <translation>รายละเอียดเครือข่ายเฉพาะโฮสต์</translation>
+ </message>
+ <message>
+ <source>&Adapter</source>
+ <translation>แ&ผงวงจร</translation>
+ </message>
+ <message>
+ <source>Manual &Configuration</source>
+ <translation>&ตั้งค่าด้วยตนเอง</translation>
+ </message>
+ <message>
+ <source>&IPv4 Address:</source>
+ <translation>ที่อยู่ &IPv4:</translation>
+ </message>
+ <message>
+ <source>Holds the host IPv4 address for this adapter.</source>
+ <translation>เก็บที่อยู่ IPv4 สำหรับแผงวงจรนี้</translation>
+ </message>
+ <message>
+ <source>IPv4 Network &Mask:</source>
+ <translation>&มาสก์เครือข่าย IPv4:</translation>
+ </message>
+ <message>
+ <source>Holds the host IPv4 network mask for this adapter.</source>
+ <translation>เก็บมาสก์เครือข่าย IPv4 สำหรับแผงวงจรนี้</translation>
+ </message>
+ <message>
+ <source>I&Pv6 Address:</source>
+ <translation>ที่อยู่ I&Pv6:</translation>
+ </message>
+ <message>
+ <source>Holds the host IPv6 address for this adapter if IPv6 is supported.</source>
+ <translation>เก็บที่อยู่ IPv6 สำหรับแผงวงจรนี้หากรองรับ IPv6</translation>
+ </message>
+ <message>
+ <source>IPv6 Network Mask &Length:</source>
+ <translation>ความ&ยาวมาสก์เครือข่าย IPv6:</translation>
+ </message>
+ <message>
+ <source>Holds the host IPv6 network mask prefix length for this adapter if IPv6 is supported.</source>
+ <translation>เก็บความยาวส่วนขยายมาสก์ด้านหน้าเครือข่าย IPv6 ของโฮสต์สำหรับแผงวงจรนี้หากรองรับ IPv6</translation>
+ </message>
+ <message>
+ <source>&DHCP Server</source>
+ <translation>เซอร์ฟเวอร์ &DHCP</translation>
+ </message>
+ <message>
+ <source>&Enable Server</source>
+ <translation>เ&ปิดใช้เซอร์ฟเวอร์</translation>
+ </message>
+ <message>
+ <source>Server Add&ress:</source>
+ <translation>&ที่อยู่เซอร์ฟเวอร์:</translation>
+ </message>
+ <message>
+ <source>Holds the address of the DHCP server servicing the network associated with this host-only adapter.</source>
+ <translation>เก็บที่อยู่ของเซอร์ฟเวอร์ DHCP ที่ให้บริการเครือข่ายที่เชื่อมโยงกับแผงวงจรเครือข่ายเฉพาะโฮสต์นี้</translation>
+ </message>
+ <message>
+ <source>Server &Mask:</source>
+ <translation>&มาสก์เครือข่าย:</translation>
+ </message>
+ <message>
+ <source>Holds the network mask of the DHCP server servicing the network associated with this host-only adapter.</source>
+ <translation>เก็บมาสก์เครือข่ายของเซอร์ฟเวอร์ DHCP ที่ให้บริการเครือข่ายที่เชื่อมโยงกับแผงวงจรเครือข่ายเฉพาะโฮสต์นี้</translation>
+ </message>
+ <message>
+ <source>&Lower Address Bound:</source>
+ <translation>ที่อยู่เ&ริ่มต้น:</translation>
+ </message>
+ <message>
+ <source>Holds the lower address bound offered by the DHCP server servicing the network associated with this host-only adapter.</source>
+ <translation>เก็บค่าที่อยู่เริ่มต้นที่จ่ายโดยเซอร์ฟเวอร์ DHCP ที่ให้บริการเครือข่ายที่เชื่อมโยงกับแผงวงจรเครือข่ายเฉพาะโฮสต์นี้</translation>
+ </message>
+ <message>
+ <source>&Upper Address Bound:</source>
+ <translation>ที่อยู่&สุดท้าย:</translation>
+ </message>
+ <message>
+ <source>Holds the upper address bound offered by the DHCP server servicing the network associated with this host-only adapter.</source>
+ <translation>เก็บค่าที่อยู่สุดท้ายที่จ่ายโดยเซอร์ฟเวอร์ DHCP ที่ให้บริการเครือข่ายที่เชื่อมโยงกับแผงวงจรเครือข่ายเฉพาะโฮสต์นี้</translation>
+ </message>
+ <message>
+ <source>When checked, manual configuration will be used for this network adapter.</source>
+ <translation>หากเลือกไว้ การตั้งค่าด้วยตนเองจะถูกใช้กับแผงวงจรเครือข่ายนี้</translation>
+ </message>
+ <message>
+ <source>When checked, the DHCP Server will be enabled for this network on machine start-up.</source>
+ <translation>หากเลือกไว้ เซอร์ฟเวอร์ DHCP จะถูกเปิดใช้งานสำหรับเครือข่ายนี้ขณะเครื่องเริ่มทำงาน</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsNetworkDetailsNAT</name>
+ <message>
+ <source>NAT Network Details</source>
+ <translation>รายละเอียดเครือข่าย NAT</translation>
+ </message>
+ <message>
+ <source>&Enable Network</source>
+ <translation>เ&ปิดใช้เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Network &Name:</source>
+ <translation>&ชื่อเครือข่าย:</translation>
+ </message>
+ <message>
+ <source>Holds the name for this network.</source>
+ <translation>เก็บชื่อของเครือข่ายนี้</translation>
+ </message>
+ <message>
+ <source>Network &CIDR:</source>
+ <translation>&CIDR ของเครือข่าย:</translation>
+ </message>
+ <message>
+ <source>Holds the CIDR for this network.</source>
+ <translation>เก็บค่า CIDR ของเครือข่ายนี้</translation>
+ </message>
+ <message>
+ <source>Network Options:</source>
+ <translation>ตัวเลือกเครือข่าย:</translation>
+ </message>
+ <message>
+ <source>Supports &DHCP</source>
+ <translation>รองรับ &DHCP</translation>
+ </message>
+ <message>
+ <source>Supports &IPv6</source>
+ <translation>รองรับ &IPv6</translation>
+ </message>
+ <message>
+ <source>Advertise Default IPv6 &Route</source>
+ <translation>ประกาศเ&ส้นทางตั้งต้น IPv6</translation>
+ </message>
+ <message>
+ <source>&Port Forwarding</source>
+ <translation>การส่งต่อ&พอร์ต</translation>
+ </message>
+ <message>
+ <source>When checked, this network will be enabled.</source>
+ <translation>หากเลือกไว้ เครือข่ายนี้จะถูกเปิดใช้งาน</translation>
+ </message>
+ <message>
+ <source>When checked, this network will support DHCP.</source>
+ <translation>หากเลือกไว้ เครือข่ายนี้จะรองรับ DHCP</translation>
+ </message>
+ <message>
+ <source>When checked, this network will support IPv6.</source>
+ <translation>หากเลือกไว้ เครือข่ายนี้จะรองรับ IPv6</translation>
+ </message>
+ <message>
+ <source>When checked, this network will be advertised as the default IPv6 route.</source>
+ <translation>หากเลือกไว้ เครือข่ายนี้จะถูกประกาศให้เป็นเส้นทางตั้งต้นของ IPv6</translation>
+ </message>
+ <message>
+ <source>Displays a window to configure port forwarding rules.</source>
+ <translation>แสดงหน้าต่างเพื่อตั้งค่ากฎการส่งต่อพอร์ต</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsPortForwardingDlg</name>
+ <message>
+ <source>Port Forwarding Rules</source>
+ <translation>กฎการส่งต่อพอร์ต</translation>
+ </message>
+ <message>
+ <source>IPv4</source>
+ <translation>IPv4</translation>
+ </message>
+ <message>
+ <source>IPv6</source>
+ <translation>IPv6</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsProxy</name>
+ <message>
+ <source>Ho&st:</source>
+ <translation>โ&ฮสต์:</translation>
+ </message>
+ <message>
+ <source>&Port:</source>
+ <translation>&พอร์ต:</translation>
+ </message>
+ <message>
+ <source>No proxy host is currently specified.</source>
+ <translation>ไม่ได้กำหนดโฮสต์พรอกซีไว้</translation>
+ </message>
+ <message>
+ <source>No proxy port is currently specified.</source>
+ <translation>ไม่ได้กำหนดพอร์ตของพรอกซีไว้</translation>
+ </message>
+ <message>
+ <source>Holds the proxy host.</source>
+ <translation>เก็บโฮสต์พรอกซี</translation>
+ </message>
+ <message>
+ <source>Holds the proxy port.</source>
+ <translation>เก็บพอร์ตพรอกซี</translation>
+ </message>
+ <message>
+ <source>When chosen, VirtualBox will try to auto-detect host proxy settings for tasks like downloading Guest Additions from the network or checking for updates.</source>
+ <translation>หากเลือกไว้ เวอร์ชวลบอกซ์จะพยายามตรวจหาการตั้งค่าพรอกซีของโฮสต์สำหรับการทำงานเช่นการดาวน์โหลดส่วนขยายสำหรับเกสต์ผ่านเครือข่ายหรือการตรวจสอบการอัพเดต</translation>
+ </message>
+ <message>
+ <source>&Auto-detect Host Proxy Settings</source>
+ <translation>ตรวจหาการตั้งค่าพรอกซีของโฮสต์&อัตโนมัติ</translation>
+ </message>
+ <message>
+ <source>When chosen, VirtualBox will use direct Internet connection for tasks like downloading Guest Additions from the network or checking for updates.</source>
+ <translation>หากเลือกไว้ เวอร์ชวลบอกซ์จะเชื่อมต่ออินเทอร์เน็ตโดยตรงสำหรับการทำงานเช่นการดาวน์โหลดส่วนขยายสำหรับเกสต์ผ่านเครือข่ายหรือการตรวจสอบการอัพเดต</translation>
+ </message>
+ <message>
+ <source>&Direct Connection to the Internet</source>
+ <translation>เชื่อมต่ออินเทอร์เน็ตโ&ดยตรง</translation>
+ </message>
+ <message>
+ <source>When chosen, VirtualBox will use the proxy settings supplied for tasks like downloading Guest Additions from the network or checking for updates.</source>
+ <translation>หากเลือกไว้ เวอร์ชวลบอกซ์จะใช้ค่าพรอกซีที่ตั้งไว้สำหรับการทำงานเช่นการดาวน์โหลดส่วนขยายสำหรับเกสต์ผ่านเครือข่ายหรือการตรวจสอบการอัพเดต</translation>
+ </message>
+ <message>
+ <source>&Manual Proxy Configuration</source>
+ <translation>&ตั้งค่าพรอกซีด้วยตนเอง</translation>
+ </message>
+</context>
+<context>
+ <name>UIGlobalSettingsUpdate</name>
+ <message>
+ <source>When checked, the application will periodically connect to the VirtualBox website and check whether a new VirtualBox version is available.</source>
+ <translation>เลือกที่นี่เพื่อให้โปรแกรมเชื่อมต่อไปยังเว็บไซต์เวอร์ชวลบอกซ์เป็นระยะ และตรวจสอบว่ามีเวอร์ชวลบอกซ์รุ่นใหม่ให้ใช้หรือไม่</translation>
+ </message>
+ <message>
+ <source>&Check for Updates</source>
+ <translation>&ตรวจสอบการอัพเดต</translation>
+ </message>
+ <message>
+ <source>&Once per:</source>
+ <translation>&หนึ่งครั้งใน:</translation>
+ </message>
+ <message>
+ <source>Next Check:</source>
+ <translation>ตรวจสอบครั้งต่อไป:</translation>
+ </message>
+ <message>
+ <source>Check for:</source>
+ <translation>ตรวจหา:</translation>
+ </message>
+ <message>
+ <source><p>Choose this if you only wish to be notified about stable updates to VirtualBox.</p></source>
+ <translation><p>เลือกข้อนี้หากคุณต้องการให้แจ้งเกี่ยวกับการอัพเดตเวอร์ชวลบอกซ์รุ่นเสถียรเท่านั้น</p></translation>
+ </message>
+ <message>
+ <source>&Stable Release Versions</source>
+ <translation>เฉพาะรุ่นเ&สถียร</translation>
+ </message>
+ <message>
+ <source><p>Choose this if you wish to be notified about all new VirtualBox releases.</p></source>
+ <translation><p>เลือกข้อนี้หากคุณต้องการให้แจ้งเกี่ยวกับการอัพเดตเวอร์ชวลบอกซ์รุ่นใหม่ทั้งหมด</p></translation>
+ </message>
+ <message>
+ <source>&All New Releases</source>
+ <translation>รุ่นใ&หม่ทั้งหมด</translation>
+ </message>
+ <message>
+ <source><p>Choose this to be notified about all new VirtualBox releases and pre-release versions of VirtualBox.</p></source>
+ <translation><p>เลือกข้อนี้หากคุณต้องการให้แจ้งเกี่ยวกับการอัพเดตเวอร์ชวลบอกซ์รุ่นใหม่ทั้งหมดรวมถึงรุ่นก่อนเผยแพร่ด้วย</p></translation>
+ </message>
+ <message>
+ <source>All New Releases and &Pre-Releases</source>
+ <translation>รุ่นใหม่ทั้งหมดและรุ่นก่อนเ&ผยแพร่</translation>
+ </message>
+ <message>
+ <source>Selects how often the new version check should be performed. Note that if you want to completely disable this check, just clear the above check box.</source>
+ <translation>เลือกความถี่ในการตรวจหารุ่นใหม่ โปรดทราบว่าหากคุณสามารถปิดการตรวจสอบนี้โดยการล้างกล่องตัวเลือกด้านบน</translation>
+ </message>
+</context>
+<context>
+ <name>UIHelpButton</name>
+ <message>
+ <source>&Help</source>
+ <translation>&ช่วยเหลือ</translation>
+ </message>
+</context>
+<context>
+ <name>UIHostComboEditor</name>
+ <message>
+ <source><key_%1></source>
+ <translation><ปุ่ม_%1></translation>
+ </message>
+ <message>
+ <source>Left </source>
+ <translation>ซ้าย </translation>
+ </message>
+ <message>
+ <source>Right </source>
+ <translation>ขวา </translation>
+ </message>
+ <message>
+ <source>Left Shift</source>
+ <translation>Shift ซ้าย</translation>
+ </message>
+ <message>
+ <source>Right Shift</source>
+ <translation>Shift ขวา</translation>
+ </message>
+ <message>
+ <source>Left Ctrl</source>
+ <translation>Ctrl ซ้าย</translation>
+ </message>
+ <message>
+ <source>Right Ctrl</source>
+ <translation>Ctrl ขวา</translation>
+ </message>
+ <message>
+ <source>Left Alt</source>
+ <translation>Alt ซ้าย</translation>
+ </message>
+ <message>
+ <source>Right Alt</source>
+ <translation>Alt ขวา</translation>
+ </message>
+ <message>
+ <source>Left WinKey</source>
+ <translation>WinKey ซ้าย</translation>
+ </message>
+ <message>
+ <source>Right WinKey</source>
+ <translation>WinKey ขวา</translation>
+ </message>
+ <message>
+ <source>Menu key</source>
+ <translation>ปุ่มเมนู</translation>
+ </message>
+ <message>
+ <source>Alt Gr</source>
+ <translation>Alt Gr</translation>
+ </message>
+ <message>
+ <source>Caps Lock</source>
+ <translation>Caps Lock</translation>
+ </message>
+ <message>
+ <source>Scroll Lock</source>
+ <translation>Scroll Lock</translation>
+ </message>
+ <message>
+ <source>Host+</source>
+ <translation>โฮสต์+</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>ไม่กำหนด</translation>
+ </message>
+</context>
+<context>
+ <name>UIHotKeyEditor</name>
+ <message>
+ <source>Reset shortcut to default</source>
+ <translation>กลับไปใช้ค่าทางลัดตั้งต้น</translation>
+ </message>
+ <message>
+ <source>Unset shortcut</source>
+ <translation>ไม่กำหนดทางลัด</translation>
+ </message>
+</context>
+<context>
+ <name>UIHotKeyTableModel</name>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Shortcut</source>
+ <translation>ทางลัด</translation>
+ </message>
+</context>
+<context>
+ <name>UIImportLicenseViewer</name>
+ <message>
+ <source><b>The virtual system "%1" requires that you agree to the terms and conditions of the software license agreement shown below.</b><br /><br />Click <b>Agree</b> to continue or click <b>Disagree</b> to cancel the import.</source>
+ <translation><b>ระบบเสมือน "%1" ต้องการให้คุณยอมรับข้อตกลงและเงื่อนไขในข้อตกลงไลเซนส์ซอฟต์แวร์ดังแสดงด้านล่างนี้ </b><br /><br />คลิก <b>ยอมรับ</b> เพื่อดำเนินการต่อ หรือคลิก <b>ไม่ยอมรับ</b> เพื่อยกเลิกการนำเข้า</translation>
+ </message>
+ <message>
+ <source>Software License Agreement</source>
+ <translation>ข้อตกลงไลเซนส์ซอฟต์แวร์</translation>
+ </message>
+ <message>
+ <source>&Disagree</source>
+ <translation>ไ&ม่ยอมรับ</translation>
+ </message>
+ <message>
+ <source>&Agree</source>
+ <translation>&ยอมรับ</translation>
+ </message>
+ <message>
+ <source>&Print...</source>
+ <translation>&พิมพ์...</translation>
+ </message>
+ <message>
+ <source>&Save...</source>
+ <translation>&บันทึก...</translation>
+ </message>
+ <message>
+ <source>Text (*.txt)</source>
+ <translation>ข้อความ (*.txt)</translation>
+ </message>
+ <message>
+ <source>Save license to file...</source>
+ <translation>บันทึกไลเซนส์ลงไฟล์...</translation>
+ </message>
+</context>
+<context>
+ <name>UIIndicatorsPool</name>
+ <message>
+ <source><p style='white-space:pre'><nobr>Indicates the activity of the network interfaces:</nobr>%1</p></source>
+ <comment>Network adapters tooltip</comment>
+ <translation><p style='white-space:pre'><nobr>แสดงการทำงานของการเชื่อมต่อเครือข่าย:</nobr>%1</p></translation>
+ </message>
+ <message>
+ <source><br><nobr><b>Adapter %1 (%2)</b>: %3 cable %4</nobr></source>
+ <comment>Network adapters tooltip</comment>
+ <translation><br><nobr><b>อแดปเตอร์ %1 (%2)</b>: %3 เคเบิล %4</nobr></translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <comment>Network adapters tooltip</comment>
+ <translation>เชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <comment>Network adapters tooltip</comment>
+ <translation>ไม่ได้เชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source><br><nobr><b>All network adapters are disabled</b></nobr></source>
+ <comment>Network adapters tooltip</comment>
+ <translation><br><nobr><b>อแดปเตอร์เครือข่ายทั้งหมดถูกปิดการใช้งานไว้</b></nobr></translation>
+ </message>
+ <message>
+ <source><p style='white-space:pre'><nobr>Indicates the activity of the attached USB devices:</nobr>%1</p></source>
+ <comment>USB device tooltip</comment>
+ <translation><p style='white-space:pre'><nobr>แสดงการทำงานของอุปกรณ์ USB ที่ติดตั้งไว้:</nobr>%1</p></translation>
+ </message>
+ <message>
+ <source><br><nobr><b>No USB devices attached</b></nobr></source>
+ <comment>USB device tooltip</comment>
+ <translation><br><nobr><b>ไม่ได้ติดตั้งอุปกรณ์ USB ไว้</b></nobr></translation>
+ </message>
+ <message>
+ <source><p style='white-space:pre'><nobr>Indicates the activity of the machine's shared folders:</nobr>%1</p></source>
+ <comment>Shared folders tooltip</comment>
+ <translation><p style='white-space:pre'><nobr>แสดงการทำงานของโฟลเดอร์ใช้ร่วมกัน:</nobr>%1</p></translation>
+ </message>
+ <message>
+ <source><br><nobr><b>No shared folders</b></nobr></source>
+ <comment>Shared folders tooltip</comment>
+ <translation><br><nobr><b>ไม่มีโฟลเดอร์ที่ใช้ร่วมกัน</b></nobr></translation>
+ </message>
+ <message>
+ <source><br><nobr><b>%1:</b> %2</nobr></source>
+ <comment>Virtualization Stuff LED</comment>
+ <translation><br><nobr><b>%1:</b> %2</nobr></translation>
+ </message>
+ <message>
+ <source>Indicates whether the host mouse pointer is captured by the guest OS:<br><nobr><img src=:/mouse_disabled_16px.png/> pointer is not captured</nobr><br><nobr><img src=:/mouse_16px.png/> pointer is captured</nobr><br><nobr><img src=:/mouse_seamless_16px.png/> mouse integration (MI) is On</nobr><br><nobr><img src=:/mouse_can_seamless_ [...]
+ <translation>ระบุว่าเกสต์โอเอสจับเมาส์พอยเตอร์ของโฮสต์ไว้หรือไม่:<br><nobr><img src=:/mouse_disabled_16px.png/> ไม่ได้จับพอยเตอร์</nobr><br><nobr><img src=:/mouse_16px.png/> จับพอยเตอร์</nobr><br><nobr><img src=:/mouse_seamless_16px.png/> เปิดการใช้เมาส์ร่วมกัน</nobr><br><nobr><img src=:/mouse_can_seamless_16px.png/>   [...]
+ </message>
+ <message>
+ <source><nobr>Indicates video capturing activity:</nobr><br>%1</source>
+ <translation><nobr>ระบุกิจกรรมของการจับภาพวิดีโอ:</nobr><br>%1</translation>
+ </message>
+ <message>
+ <source><nobr><b>Video capture disabled</b></nobr></source>
+ <translation><nobr><b>ปิดการจับภาพวิดีโอ</b></nobr></translation>
+ </message>
+ <message>
+ <source><nobr><b>Video capture file:</b> %1</nobr></source>
+ <translation><nobr><b>ไฟล์สำหรับการจับภาพวิดีโอ:</b> %1</nobr></translation>
+ </message>
+ <message>
+ <source>Additional feature status:<br><nobr><b>%1:</b> %2</nobr><br><nobr><b>%3:</b> %4</nobr><br><nobr><b>%5:</b> %6</nobr><br><nobr><b>%7:</b> %8%</nobr></source>
+ <comment>Virtualization Stuff LED</comment>
+ <translation>สถานะของคุณสมบัติเพิ่มเติม:<br><nobr><b>%1:</b> %2</nobr><br><nobr><b>%3:</b> %4</nobr><br><nobr><b>%5:</b> %6</nobr><br><nobr><b>%7:</b> %8%</nobr></translation>
+ </message>
+ <message>
+ <source><p style='white-space:pre'><nobr>Indicates the activity of the display:</nobr>%1</p></source>
+ <translation><p style='white-space:pre'><nobr>แสดงกิจกรรมของหน่วยแสดงผล:</nobr>%1</p></translation>
+ </message>
+ <message>
+ <source><p style='white-space:pre'><nobr>Indicates the activity of the optical drives:</nobr>%1</p></source>
+ <comment>CD tooltip</comment>
+ <translation><p style='white-space:pre'><nobr>แสดงกิจกรรมของไดรฟ์ออปติคัล:</nobr>%1</p></translation>
+ </message>
+ <message>
+ <source><p style='white-space:pre'><nobr>Indicates the activity of the floppy drives:</nobr>%1</p></source>
+ <comment>FD tooltip</comment>
+ <translation><p style='white-space:pre'><nobr>แสดงกิจกรรมของไดรฟ์ฟลอปปี้:</nobr>%1</p></translation>
+ </message>
+ <message>
+ <source><p style='white-space:pre'><nobr>Indicates the activity of the hard disks:</nobr>%1</p></source>
+ <comment>HDD tooltip</comment>
+ <translation><p style='white-space:pre'><nobr>แสดงกิจกรรมของฮาร์ดดิสก์:</nobr>%1</p></translation>
+ </message>
+ <message>
+ <source>Indicates whether the host keyboard is captured by the guest OS:<br><nobr><img src=:/hostkey_16px.png/> keyboard is not captured</nobr><br><nobr><img src=:/hostkey_captured_16px.png/> keyboard is captured</nobr></source>
+ <translation>แสดงว่าขณะนี้แป้นพิมพ์ถูกจับไว้โดยเกสต์โอเอสหรือไม่:<br><nobr><img src=:/hostkey_16px.png/> แป้นพิมพ์ไม่ได้ถูกจับไว้</nobr><br><nobr><img src=:/hostkey_captured_16px.png/> แป้นพิมพ์ถูกจับไว้</nobr></translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataAudio</name>
+ <message>
+ <source>Host Driver</source>
+ <comment>details report (audio)</comment>
+ <translation>ไดร์เวอร์ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Controller</source>
+ <comment>details report (audio)</comment>
+ <translation>ตัวควบคุม</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataDisplay</name>
+ <message>
+ <source>Video Memory</source>
+ <comment>details report</comment>
+ <translation>หน่วยความจำแสดงผล</translation>
+ </message>
+ <message>
+ <source>Screens</source>
+ <comment>details report</comment>
+ <translation>หน้าจอ</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (3D Acceleration)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (3D Acceleration)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>3D Acceleration</source>
+ <comment>details report</comment>
+ <translation>ตัวเร่งความเร็ว 3D</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (2D Video Acceleration)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (2D Video Acceleration)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>2D Video Acceleration</source>
+ <comment>details report</comment>
+ <translation>ตัวเร่งความเร็วในการแสดงผล 2D</translation>
+ </message>
+ <message>
+ <source>Remote Desktop Server Port</source>
+ <comment>details report (VRDE Server)</comment>
+ <translation>พอร์ตเซอร์ฟเวอร์รีโมตเดสก์ทอป</translation>
+ </message>
+ <message>
+ <source>Remote Desktop Server</source>
+ <comment>details report (VRDE Server)</comment>
+ <translation>เซอร์ฟเวอร์รีโมตเดสก์ทอป</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (VRDE Server)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataGeneral</name>
+ <message>
+ <source>Name</source>
+ <comment>details report</comment>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>OS Type</source>
+ <comment>details report</comment>
+ <translation>ชนิดของโอเอส</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataNetwork</name>
+ <message>
+ <source>Bridged adapter, %1</source>
+ <comment>details report (network)</comment>
+ <translation>แผงวงจรแบบบริดจ์, %1</translation>
+ </message>
+ <message>
+ <source>Internal network, '%1'</source>
+ <comment>details report (network)</comment>
+ <translation>เครือข่ายภายใน, '%1'</translation>
+ </message>
+ <message>
+ <source>Host-only adapter, '%1'</source>
+ <comment>details report (network)</comment>
+ <translation>แผงวงจรเฉพาะโฮสต์, '%1'</translation>
+ </message>
+ <message>
+ <source>Generic, '%1'</source>
+ <comment>details report (network)</comment>
+ <translation>ทั่วไป, '%1'</translation>
+ </message>
+ <message>
+ <source>NAT network, '%1'</source>
+ <comment>details report (network)</comment>
+ <translation>เครือข่าย NAT '%1'</translation>
+ </message>
+ <message>
+ <source>Adapter %1</source>
+ <comment>details report (network)</comment>
+ <translation>แผงวงจร %1</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataNetworkStatistics</name>
+ <message>
+ <source>Data Transmitted</source>
+ <translation>ข้อมูลที่ส่งไป</translation>
+ </message>
+ <message>
+ <source>Data Received</source>
+ <translation>ข้อมูลที่ได้รับ</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataParallelPorts</name>
+ <message>
+ <source>Port %1</source>
+ <comment>details report (parallel ports)</comment>
+ <translation>พอร์ต %1</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (parallel ports)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataRuntimeAttributes</name>
+ <message>
+ <source>Not Detected</source>
+ <comment>guest additions</comment>
+ <translation>ไม่พบ</translation>
+ </message>
+ <message>
+ <source>Not Detected</source>
+ <comment>guest os type</comment>
+ <translation>ไม่พบ</translation>
+ </message>
+ <message>
+ <source>Not Available</source>
+ <comment>details report (VRDE server port)</comment>
+ <translation>ไม่พร้อมใช้งาน</translation>
+ </message>
+ <message>
+ <source>Screen Resolution</source>
+ <translation>ความละเอียดจอภาพ</translation>
+ </message>
+ <message>
+ <source>VM Uptime</source>
+ <translation>เวลาตั้งแต่เปิด VM</translation>
+ </message>
+ <message>
+ <source>Clipboard Mode</source>
+ <translation>โหมดของคลิปบอร์ด</translation>
+ </message>
+ <message>
+ <source>Drag and Drop Mode</source>
+ <translation>โหมดลากแล้วปล่อย</translation>
+ </message>
+ <message>
+ <source>VT-x/AMD-V</source>
+ <comment>details report</comment>
+ <translation>VT-x/AMD-V</translation>
+ </message>
+ <message>
+ <source>Nested Paging</source>
+ <comment>details report</comment>
+ <translation>การแบ่งหน้าซ้อนกัน</translation>
+ </message>
+ <message>
+ <source>Unrestricted Execution</source>
+ <comment>details report</comment>
+ <translation>ประมวลผลโดยไม่มีข้อจำกัด</translation>
+ </message>
+ <message>
+ <source>Paravirtualization Interface</source>
+ <comment>details report</comment>
+ <translation>ส่วนเชื่อมต่อพาราเวอร์ชวลไลเซชัน</translation>
+ </message>
+ <message>
+ <source>Guest Additions</source>
+ <translation>โปรแกรมเสริมสำหรับเกสต์</translation>
+ </message>
+ <message>
+ <source>Guest OS Type</source>
+ <comment>details report</comment>
+ <translation>ชนิดของเกสต์โอเอส</translation>
+ </message>
+ <message>
+ <source>Remote Desktop Server Port</source>
+ <comment>details report (VRDE Server)</comment>
+ <translation>พอร์ตเซอร์ฟเวอร์รีโมตเดสก์ทอป</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataSerialPorts</name>
+ <message>
+ <source>Port %1</source>
+ <comment>details report (serial ports)</comment>
+ <translation>พอร์ต %1</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataSharedFolders</name>
+ <message>
+ <source>Shared Folders</source>
+ <comment>details report (shared folders)</comment>
+ <translation>โฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataStorage</name>
+ <message>
+ <source>(Optical Drive)</source>
+ <translation>(ไดรฟ์ออปติคัล)</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataStorageStatistics</name>
+ <message>
+ <source>DMA Transfers</source>
+ <translation>รับส่งแบบ DMA</translation>
+ </message>
+ <message>
+ <source>PIO Transfers</source>
+ <translation>รับส่งแบบ PIO</translation>
+ </message>
+ <message>
+ <source>Data Read</source>
+ <translation>ข้อมูลที่อ่าน</translation>
+ </message>
+ <message>
+ <source>Data Written</source>
+ <translation>ข้อมูลที่เขียน</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataSystem</name>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (ACPI)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (ACPI)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (I/O APIC)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (I/O APIC)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (PAE/NX)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (PAE/NX)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Base Memory</source>
+ <comment>details report</comment>
+ <translation>หน่วยความจำพื้นฐาน</translation>
+ </message>
+ <message>
+ <source>Processor(s)</source>
+ <comment>details report</comment>
+ <translation>โปรเซสเซอร์</translation>
+ </message>
+ <message>
+ <source>Execution Cap</source>
+ <comment>details report</comment>
+ <translation>จำกัดการประมวลผล</translation>
+ </message>
+ <message>
+ <source>Boot Order</source>
+ <comment>details report</comment>
+ <translation>ลำดับการบูต</translation>
+ </message>
+ <message>
+ <source>ACPI</source>
+ <comment>details report</comment>
+ <translation>ACPI</translation>
+ </message>
+ <message>
+ <source>I/O APIC</source>
+ <comment>details report</comment>
+ <translation>I/O APIC</translation>
+ </message>
+ <message>
+ <source>PAE/NX</source>
+ <comment>details report</comment>
+ <translation>PAE/NX</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (VT-x/AMD-V)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (VT-x/AMD-V)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>VT-x/AMD-V</source>
+ <comment>details report</comment>
+ <translation>VT-x/AMD-V</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (Nested Paging)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (Nested Paging)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Nested Paging</source>
+ <comment>details report</comment>
+ <translation>การแบ่งหน้าซ้อนกัน</translation>
+ </message>
+ <message>
+ <source>Paravirtualization Interface</source>
+ <comment>details report</comment>
+ <translation>ส่วนเชื่อมต่อพาราเวอร์ชวลไลเซชัน</translation>
+ </message>
+</context>
+<context>
+ <name>UIInformationDataUSB</name>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (USB)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Device Filters</source>
+ <comment>details report (USB)</comment>
+ <translation>ตัวกรองอุปกรณ์</translation>
+ </message>
+ <message>
+ <source>%1 (%2 active)</source>
+ <comment>details report (USB)</comment>
+ <translation>%1 (%2 ใช้งานอยู่)</translation>
+ </message>
+</context>
+<context>
+ <name>UILineTextEdit</name>
+ <message>
+ <source>&Edit</source>
+ <translation>แ&ก้ไข</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineLogic</name>
+ <message>
+ <source>Select a filename for the screenshot ...</source>
+ <translation>เลือกชื่อไฟล์สำหรับภาพหน้าจอ ...</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsAudio</name>
+ <message>
+ <source>When checked, a virtual PCI audio card will be plugged into the virtual machine and will communicate with the host audio system using the specified driver.</source>
+ <translation>เมื่อเลือก การ์ดเสียง PCI เสมือนจะถูกติดตั้งลงในเวอร์ชวลแมชชีนและจะสื่อสารกับระบบเสียงของโฮสต์โดยใช้ไดร์เวอร์ตามที่กำหนด</translation>
+ </message>
+ <message>
+ <source>Enable &Audio</source>
+ <translation>เปิดใช้ระบบเ&สียง</translation>
+ </message>
+ <message>
+ <source>Host Audio &Driver:</source>
+ <translation>ไ&ดร์เวอร์เสียงของโฮสต์:</translation>
+ </message>
+ <message>
+ <source>Audio &Controller:</source>
+ <translation>&ตัวควบคุมเสียง:</translation>
+ </message>
+ <message>
+ <source>Selects the type of the virtual sound card. Depending on this value, VirtualBox will provide different audio hardware to the virtual machine.</source>
+ <translation>เลือกชนิดของการ์ดเสียงเสมือน เวอร์ชวลบอกซ์จะจัดสรรฮาร์ดแวร์เสียงที่แตกต่างกันไปให้กับเวอร์ชวลแมชชีนโดยใช้ค่านี้</translation>
+ </message>
+ <message>
+ <source>Selects the audio output driver. The <b>Null Audio Driver</b> makes the guest see an audio card, however every access to it will be ignored.</source>
+ <translation>เลือกไดร์เวอร์สำหรับส่งออกข้อมูลเสียง <b>ไดร์เวอร์เสียง Null</b> จะทำให้เกสต์มองเห็นการ์ดเสียง แต่ระบบจะเพิกเฉยต่อการเข้าถึงทั้งหมด</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsDisplay</name>
+ <message>
+ <source>Video &Memory:</source>
+ <translation>&หน่วยความจำวิดีโอ:</translation>
+ </message>
+ <message>
+ <source>Controls the amount of video memory provided to the virtual machine.</source>
+ <translation>ควบคุมขนาดของหน่วยความจำวิดีโอที่จัดสรรให้กับเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>MB</translation>
+ </message>
+ <message>
+ <source>Extended Features:</source>
+ <translation>คุณสมบัติเพิ่มเติม:</translation>
+ </message>
+ <message>
+ <source>When checked, the virtual machine will be given access to the 3D graphics capabilities available on the host.</source>
+ <translation>เลือกที่นี่หากต้องการให้เวอร์ชวลแมชชีนเข้าถึงความสามารถด้านกราฟิก 3D ที่มีให้ใช้บนโฮสต์</translation>
+ </message>
+ <message>
+ <source>Enable &3D Acceleration</source>
+ <translation>ใช้ตัวเร่งความเร็ว &3D</translation>
+ </message>
+ <message>
+ <source>&Remote Display</source>
+ <translation>หน่วยแสดงผลจาก&ระยะไกล</translation>
+ </message>
+ <message>
+ <source>When checked, the VM will act as a Remote Desktop Protocol (RDP) server, allowing remote clients to connect and operate the VM (when it is running) using a standard RDP client.</source>
+ <translation>เมื่อเลือก เวอร์ชวลแมชชีนจะทำหน้าที่เป็นเซอร์ฟเวอร์รีโมตเดสก์ทอปโปรโตคอล (RDP) และยอมให้ไคลเอนต์เชื่อมต่อเข้ามาทำงานกับเวอร์ชวลแมชชีน (เมื่อทำงานอยู่) โดยใช้ไคลเอนต์ RDP มาตรฐาน</translation>
+ </message>
+ <message>
+ <source>&Enable Server</source>
+ <translation>เ&ปิดใช้เซอร์ฟเวอร์</translation>
+ </message>
+ <message>
+ <source>Server &Port:</source>
+ <translation>&พอร์ตของเซอร์ฟเวอร์:</translation>
+ </message>
+ <message>
+ <source>Authentication &Method:</source>
+ <translation>&วิธียืนยันตัวตน:</translation>
+ </message>
+ <message>
+ <source>Authentication &Timeout:</source>
+ <translation>&หมดเวลายืนยันตัวตน:</translation>
+ </message>
+ <message>
+ <source>When checked, the virtual machine will be given access to the Video Acceleration capabilities available on the host.</source>
+ <translation>เลือกที่นี่หากต้องการให้เวอร์ชวลแมชชีนสามารถเข้าถึงคุณสมบัติของตัวเร่งความเร็วในการแสดงผลของโฮสต์ได้</translation>
+ </message>
+ <message>
+ <source>Enable &2D Video Acceleration</source>
+ <translation>ใช้ตัวเร่งความเร็วในการแสดงผล &2D</translation>
+ </message>
+ <message>
+ <source>Mo&nitor Count:</source>
+ <translation>จำนวน&จอภาพ:</translation>
+ </message>
+ <message>
+ <source>Controls the amount of virtual monitors provided to the virtual machine.</source>
+ <translation>ควบคุมจำนวนจอภาพเสมือนที่ติดตั้งให้เวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Allow Multiple Connections</source>
+ <translation>&อนุญาตให้เชื่อมต่อได้พร้อมกัน</translation>
+ </message>
+ <message>
+ <source>Video &Capture</source>
+ <translation>&จับภาพวิดีโอ</translation>
+ </message>
+ <message>
+ <source>When checked, VirtualBox will record the virtual machine session as a video file.</source>
+ <translation>เลือกที่นี่หากต้องการให้เวอร์ชวลบอกซ์บันทึกเซสชันของเวอร์ชวลแมชชีนเป็นไฟล์วิดีโอ</translation>
+ </message>
+ <message>
+ <source>&Enable Video Capture</source>
+ <translation>เ&ปิดใช้การจับภาพวิดีโอ</translation>
+ </message>
+ <message>
+ <source>File &Path:</source>
+ <translation>เ&ส้นทางไฟล์:</translation>
+ </message>
+ <message>
+ <source>Frame &Size:</source>
+ <translation>&ขนาดเฟรม:</translation>
+ </message>
+ <message>
+ <source>&Frame Rate:</source>
+ <translation>อัตราเ&ฟรม:</translation>
+ </message>
+ <message>
+ <source>&Quality:</source>
+ <translation>&คุณภาพ:</translation>
+ </message>
+ <message>
+ <source>&Screens:</source>
+ <translation>&หน้าจอ:</translation>
+ </message>
+ <message>
+ <source>The virtual machine is set up to use hardware graphics acceleration. However the host system does not currently provide this, so you will not be able to start the machine.</source>
+ <translation>เวอร์ชวลแมชชีนถูกกำหนดให้ใช้ตัวเร่งความเร็วกราฟิก แต่โฮสต์ปัจจุบันไม่มีบริการดังกล่าว คุณจึงไม่สามารถเริ่มการทำงานของเครื่องนี้ได้</translation>
+ </message>
+ <message>
+ <source>The virtual machine is currently assigned less than <b>%1</b> of video memory which is the minimum amount required for High Definition Video to be played efficiently.</source>
+ <translation>เวอร์ชวลแมชชีนได้รับการจัดสรรหน่วยความจำวิดีโอไว้น้อยกว่า <b>%1</b> ซึ่งเป็นค่าต่ำสุดที่จำเป็นสำหรับการแสดงผลความคมชัดสูงอย่างมีประสิทธิภาพ</translation>
+ </message>
+ <message>
+ <source>The virtual machine is set up to use Video Stream Acceleration. As this feature only works with Windows guest systems it will be disabled.</source>
+ <translation>เวอร์ชวลแมชชีนถูกกำหนดให้ใช้ตัวเร่งความเร็วกระแสวิดีโอ แต่คุณสมบัตินี้ทำงานได้กับเกสต์ที่เป็นวินโดวส์เท่านั้น ฟังก์ชันนี้จะถูกปิดการใช้งาน</translation>
+ </message>
+ <message>
+ <source>The VRDE server port value is not currently specified.</source>
+ <translation>ไม่ได้กำหนดค่าพอร์ตของเซอร์ฟเวอร์ VRDE ไว้</translation>
+ </message>
+ <message>
+ <source>The VRDE authentication timeout value is not currently specified.</source>
+ <translation>ไม่ได้กำหนดเวลารอสำหรับการพิสูจน์ตัวตน VRDE ไว้</translation>
+ </message>
+ <message>
+ <source>User Defined</source>
+ <translation>กำหนดโดยผู้ใช้</translation>
+ </message>
+ <message>
+ <source>%1 fps</source>
+ <translation>%1 fps</translation>
+ </message>
+ <message>
+ <source>fps</source>
+ <translation>fps</translation>
+ </message>
+ <message>
+ <source>low</source>
+ <comment>quality</comment>
+ <translation>ต่ำ</translation>
+ </message>
+ <message>
+ <source>medium</source>
+ <comment>quality</comment>
+ <translation>ปานกลาง</translation>
+ </message>
+ <message>
+ <source>high</source>
+ <comment>quality</comment>
+ <translation>สูง</translation>
+ </message>
+ <message>
+ <source>kbps</source>
+ <translation>kbps</translation>
+ </message>
+ <message>
+ <source>Screen %1</source>
+ <translation>Screen %1</translation>
+ </message>
+ <message>
+ <source><i>About %1MB per 5 minute video</i></source>
+ <translation><i>ประมาณ %1MB ต่อวิดีโอ 5 นาที</i></translation>
+ </message>
+ <message>
+ <source>Remote Display is currently enabled for this virtual machine. However, this requires the <i>%1</i> to be installed. Please install the Extension Pack from the VirtualBox download site as otherwise your VM will be started with Remote Display disabled.</source>
+ <translation>การแสดงผลระยะไกลถูกเปิดใช้สำหรับเวอร์ชวลแมชชีนนี้ แต่จำเป็นต้องมี <i>%1</i> ติดตั้งไว้ กรุณาติดตั้งแพคขยายจากไซต์ดาวน์โหลดเวอร์ชวลบอกซ์ มิฉะนั้น VM ของคุณจะเริ่มการทำงานแต่การแสดงผลระยะไกลจะถูกปิดไว้</translation>
+ </message>
+ <message>
+ <source>The virtual machine is set up to use hardware graphics acceleration and the operating system hint is set to Windows Vista or later. For best performance you should set the machine's video memory to at least <b>%1</b>.</source>
+ <translation>เวอร์ชวลแมชชีนถูกกำหนดให้ใช้ฮาร์ดแวร์เร่งความเร็วกราฟิกและตัวบ่งชี้ระบบปฏิบัติการถูกกำหนดไว้เป็นวินโดวส์วิสต้าหรือใหม่กว่า เพื่อประสิทธิภาพสูงสุด คุณควรกำหนดหน่วยความจำแสดงผลไว้อย่างน้อย <b>%1</b></translation>
+ </message>
+ <message>
+ <source>&Screen</source>
+ <translation>&หน้าจอ</translation>
+ </message>
+ <message>
+ <source>Scale Factor:</source>
+ <translation>ค่าสเกล:</translation>
+ </message>
+ <message>
+ <source>Controls the guest screen scale factor.</source>
+ <translation>ควบคุมค่าสเกลหน้าจอของเกสต์</translation>
+ </message>
+ <message>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <source>When checked, guest screen contents will not be scaled up to compensate for high host screen resolutions.</source>
+ <translation>หากเลือกไว้ หน้าจอของเกสต์จะไม่ถูกเพิ่มสเกลเพื่อชดเชยหน้าจอความละเอียดสูงของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Use &Unscaled HiDPI Output</source>
+ <translation>ใช้การแสดงผล HiDPI แบบไ&ม่สเกล</translation>
+ </message>
+ <message>
+ <source>Acceleration:</source>
+ <translation>ตัวเร่งความเร็ว:</translation>
+ </message>
+ <message>
+ <source>HiDPI Support:</source>
+ <translation>รองรับ HiDPI:</translation>
+ </message>
+ <message>
+ <source>Holds the VRDP Server port number. You may specify <tt>0</tt> (zero), to select port 3389, the standard port for RDP.</source>
+ <translation>เก็บหมายเลขพอร์ตของเซอร์ฟเวอร์ VRDP คุณสามารถกำหนด <tt>0</tt> (ศูนย์) เพื่อเลือกพอร์ต 3389 ซึ่งเป็นค่ามาตรฐานของ RDP</translation>
+ </message>
+ <message>
+ <source>Selects the VRDP authentication method.</source>
+ <translation>เลือกวิธีพิสูจน์ตัวตน VRDP</translation>
+ </message>
+ <message>
+ <source>Holds the timeout for guest authentication, in milliseconds.</source>
+ <translation>เก็บค่าเวลารอสำหรับการพิสูจน์ตัวตนของเกสต์ หน่วยเป็นมิลลิวินาที</translation>
+ </message>
+ <message>
+ <source>When checked, multiple simultaneous connections to the VM are permitted.</source>
+ <translation>หากเลือกไว้ จะอนุญาตให้เปิดใช้หลายการเชื่อมต่อไปยัง VM พร้อม ๆ กันได้</translation>
+ </message>
+ <message>
+ <source>Holds the filename VirtualBox uses to save the recorded content.</source>
+ <translation>เก็บชื่อไฟล์ที่เวอร์ชวลบอกซ์จะใช้จัดเก็บเนื้อหาที่ถูกบันทึกไว้</translation>
+ </message>
+ <message>
+ <source>Selects the resolution (frame size) of the recorded video.</source>
+ <translation>เลือกความละเอียด (ขนาดของเฟรม) ของวิดีโอที่บันทึก</translation>
+ </message>
+ <message>
+ <source>Holds the <b>horizontal</b> resolution (frame width) of the recorded video.</source>
+ <translation>เก็บค่าความละเอียด<b>แนวนอน</b> (ความกว้างของเฟรม) ของวิดีโอที่บันทึก</translation>
+ </message>
+ <message>
+ <source>Holds the <b>vertical</b> resolution (frame height) of the recorded video.</source>
+ <translation>เก็บค่าความละเอียด<b>แนวตั้ง</b> (ความสูงของเฟรม) ของวิดีโอที่บันทึก</translation>
+ </message>
+ <message>
+ <source>Controls the maximum number of <b>frames per second</b>. Additional frames will be skipped. Reducing this value will increase the number of skipped frames and reduce the file size.</source>
+ <translation>ควบคุมจำนวน<b>เฟรมต่อวินาที</b>สูงสุด เฟรมที่เกินจากนี้จะถูกข้ามไป การลดค่านี้ลงจะเพิ่มจำนวนเฟรมที่ถูกข้ามไปและจะทำให้ไฟล์มีขนาดเล็กลง</translation>
+ </message>
+ <message>
+ <source>Controls the <b>quality</b>. Increasing this value will make the video look better at the cost of an increased file size.</source>
+ <translation>ควบคุม<b>คุณภาพ</b> การเพิ่มค่านี้จะทำให้วิดีโอดูดีขึ้นแต่จะมีขนาดไฟล์ที่ใหญ่ขึ้น</translation>
+ </message>
+ <message>
+ <source>Holds the bitrate in <b>kilobits per second</b>. Increasing this value will make the video look better at the cost of an increased file size.</source>
+ <translation>เก็บอัตราบิตในหน่วย <b>กิโลบิตต่อวินาที</b> การเพิ่มค่านี้จะทำให้วิดีโอดูดีขึ้นแต่จะมีขนาดไฟล์ที่ใหญ่ขึ้น</translation>
+ </message>
+ <message>
+ <source>The virtual machine is currently assigned less than <b>%1</b> of video memory which is the minimum amount required to switch to full-screen or seamless mode.</source>
+ <translation>เวอร์ชวลแมชชีนได้รับการจัดสรรหน่วยความจำแสดงผลน้อยกว่า <b>%1</b> ซึ่งเป็นจำนวนขั้นต่ำที่จำเป็นต่อการสลับไปใช้โหมดเต็มจอหรือโหมดไร้ขอบ</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>%1%</source>
+ <translation>%1%</translation>
+ </message>
+ <message>
+ <source>When checked, enables video recording for screen %1.</source>
+ <translation>เลือกที่นี่หากต้องการเปิดใช้การบันทึกวิดีโอสำหรับหน้าจอ %1</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsGeneral</name>
+ <message>
+ <source>Basi&c</source>
+ <translation>ขั้น&พื้นฐาน</translation>
+ </message>
+ <message>
+ <source>A&dvanced</source>
+ <translation>ขั้น&สูง</translation>
+ </message>
+ <message>
+ <source>&Shared Clipboard:</source>
+ <translation>คลิปบอร์ดที่ใ&ช้ร่วมกัน:</translation>
+ </message>
+ <message>
+ <source>Selects which clipboard data will be copied between the guest and the host OS. This feature requires Guest Additions to be installed in the guest OS.</source>
+ <translation>เลือกว่าข้อมูลใดบ้างจะถูกคัดลอกระหว่างเกสต์และโฮสต์ คุณสมบัตินี้ต้องการการติดตั้งโปรแกรมเสริมสำหรับเกสต์ไว้ในโอเอสของเกสต์ด้วย</translation>
+ </message>
+ <message>
+ <source>S&napshot Folder:</source>
+ <translation>โฟลเดอร์ของ&สแนปช็อต:</translation>
+ </message>
+ <message>
+ <source>D&escription</source>
+ <translation>คำ&อธิบาย</translation>
+ </message>
+ <message>
+ <source>Holds the description of the virtual machine. The description field is useful for commenting on configuration details of the installed guest OS.</source>
+ <translation>เก็บคำอธิบายของเวอร์ชวลแมชชีน ฟิลด์คำอธิบายมีประโยชน์สำหรับการให้ข้อมูลการกำหนดค่าและรายละเอียดของเกสต์โอเอสที่ติดตั้งไว้</translation>
+ </message>
+ <message>
+ <source>D&rag'n'Drop:</source>
+ <translation>&ลากแล้วปล่อย:</translation>
+ </message>
+ <message>
+ <source>Selects which data will be copied between the guest and the host OS by drag'n'drop. This feature requires Guest Additions to be installed in the guest OS.</source>
+ <translation>เลือกว่าข้อมูลใดบ้างจะถูกคัดลอกระหว่างเกสต์และโฮสต์ด้วยการลากและวาง คุณสมบัตินี้ต้องการการติดตั้งโปรแกรมเสริมสำหรับเกสต์ไว้ในโอเอสของเกสต์ด้วย</translation>
+ </message>
+ <message>
+ <source>No name specified for the virtual machine.</source>
+ <translation>ไม่ได้กำหนดชื่อให้กับเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>The virtual machine operating system hint is set to a 64-bit type. 64-bit guest systems require hardware virtualization, so this will be enabled automatically if you confirm the changes.</source>
+ <translation>ระบบปฏิบัติการที่แนะนำของเวอร์ชวลแมชชีนกำหนดเป็นชนิด 64 บิต ระบบเกสต์แบบ 64 บิตต้องการเวอร์ชวลไลเซชันฮาร์ดแวร์ คุณสมบัตินี้จะถูกเปิดใช้โดยอัตโนมัติหากคุณยืนยันการเปลี่ยนแปลงนี้</translation>
+ </message>
+ <message>
+ <source>Enc&ryption</source>
+ <translation>การเ&ข้ารหัสลับ</translation>
+ </message>
+ <message>
+ <source>When checked, enables encryption for this virtual machine.</source>
+ <translation>เลือกที่นี่เพื่อเปิดใช้การเข้ารหัสลับสำหรับเวอร์ชวลแมชชีนนี้</translation>
+ </message>
+ <message>
+ <source>En&able Encryption</source>
+ <translation>เ&ปิดใช้การเข้ารหัสลับ</translation>
+ </message>
+ <message>
+ <source>Encryption C&ipher:</source>
+ <translation>ไ&ซเฟอร์สำหรับการเข้ารหัส:</translation>
+ </message>
+ <message>
+ <source>E&nter New Password:</source>
+ <translation>&ป้อนรหัสผ่านใหม่:</translation>
+ </message>
+ <message>
+ <source>Holds the password to be assigned to the virtual machine.</source>
+ <translation>เก็บรหัสผ่านที่จะถูกใช้กับเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>C&onfirm New Password:</source>
+ <translation>&ยืนยันรหัสผ่านใหม่:</translation>
+ </message>
+ <message>
+ <source>Confirms the password to be assigned to the virtual machine.</source>
+ <translation>ยืนยันรหัสผ่านใหม่ที่จะถูกใช้กับเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>You are trying to encrypt this virtual machine. However, this requires the <i>%1</i> to be installed. Please install the Extension Pack from the VirtualBox download site.</source>
+ <translation>คุณกำลังพยายามเข้ารหัสลับเวอร์ชวลแมชชีน แต่คุณสมบัตินี้จำเป็นต้องมี <i>%1</i> ติดตั้งไว้ กรุณาติดตั้งแพคขยายจากไซต์ดาวน์โหลดเวอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>Encryption cipher type not specified.</source>
+ <translation>ไม่ได้ระบุชนิดของไซเฟอร์สำหรับการเข้ารหัสลับ</translation>
+ </message>
+ <message>
+ <source>Encryption password empty.</source>
+ <translation>ไม่ได้ระบุรหัสผ่านสำหรับการเข้ารหัสลับ</translation>
+ </message>
+ <message>
+ <source>Encryption passwords do not match.</source>
+ <translation>รหัสผ่านสำหรับการเข้ารหัสลับไม่ตรงกัน</translation>
+ </message>
+ <message>
+ <source>Leave Unchanged</source>
+ <comment>cipher type</comment>
+ <translation>คงค่าเดิมไว้</translation>
+ </message>
+ <message>
+ <source>Selects the cipher to be used for encrypting the virtual machine disks.</source>
+ <translation>เลือกไซเฟอร์เพื่อใช้เข้ารหัสดิสก์ของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Holds the path where snapshots of this virtual machine will be stored. Be aware that snapshots can take quite a lot of storage space.</source>
+ <translation>เก็บเส้นทางไปยังที่จัดเก็บสแนปช็อตของเวอร์ชวลแมชชีนนี้ โปรดทราบว่าสแนปช็อตอาจใช้พื้นที่จัดเก็บข้อมูลเป็นจำนวนมาก</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsInterface</name>
+ <message>
+ <source>Allows to modify VM menu-bar contents.</source>
+ <translation>อนุญาตให้แก้ไขเนื้อหาแถบเมนูของ VM ได้</translation>
+ </message>
+ <message>
+ <source>Mini ToolBar:</source>
+ <translation>แถบเครื่องมือขนาดเล็ก:</translation>
+ </message>
+ <message>
+ <source>Show at &Top of Screen</source>
+ <translation>แสดงที่ด้าน&บนของจอภาพ</translation>
+ </message>
+ <message>
+ <source>Allows to modify VM status-bar contents.</source>
+ <translation>อนุญาตให้แก้ไขเนื้อหาแถบสถานะของ VM ได้</translation>
+ </message>
+ <message>
+ <source>When checked, show the Mini ToolBar in full-screen and seamless modes.</source>
+ <translation>หากเลือกไว้ แถบเครื่องมือขนาดเล็กจะถูกแสดงในโหมดเต็มจอและโหมดไร้ขอบ</translation>
+ </message>
+ <message>
+ <source>Show in &Full-screen/Seamless</source>
+ <translation>แสดงเมื่อเ&ต็มจอ/ไร้ขอบ</translation>
+ </message>
+ <message>
+ <source>When checked, show the Mini ToolBar at the top of the screen, rather than in its default position at the bottom of the screen.</source>
+ <translation>หากเลือกไว้ แถบเครื่องมือขนาดเล็กจะถูกแสดงไว้ที่ด้านบนของจอภาพแทนที่จะแสดงตามค่าตั้งต้นที่ด้านล่างของจอภาพ</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsNetwork</name>
+ <message>
+ <source>When checked, plugs this virtual network adapter into the virtual machine.</source>
+ <translation>เลือกที่นี่เพื่อติดตั้งแผงวงจรเครือข่ายเสมือนลงในเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Enable Network Adapter</source>
+ <translation>&ใช้แผงวงจรเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Selects the type of the virtual network adapter. Depending on this value, VirtualBox will provide different network hardware to the virtual machine.</source>
+ <translation>เลือกชนิดแผงวงจรเครือข่ายเสมือนเวอร์ชวลบอกซ์ใช้ค่านี้เพื่อระบุชนิดของฮาร์ดแวร์เครือข่ายที่จะใช้กับเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Attached to:</source>
+ <translation>เชื่อม&ต่อกับ:</translation>
+ </message>
+ <message>
+ <source>Adapter &Type:</source>
+ <translation>ช&นิดของแผงวงจร:</translation>
+ </message>
+ <message>
+ <source>Not selected</source>
+ <comment>network adapter name</comment>
+ <translation>ไม่ได้เลือก</translation>
+ </message>
+ <message>
+ <source>&Name:</source>
+ <translation>&ชื่อ:</translation>
+ </message>
+ <message>
+ <source>A&dvanced</source>
+ <translation>ขั้น&สูง</translation>
+ </message>
+ <message>
+ <source>Holds the MAC address of this adapter. It contains exactly 12 characters chosen from {0-9,A-F}. Note that the second character must be an even digit.</source>
+ <translation>เก็บที่อยู่ MAC ของอแดปเตอร์นี้ ค่านี้มีความยาว 12 ตัวอักษรเลือกมาจาก {0-0,A-F} โปรดทราบว่าตัวอักษรตัวที่สองต้องเป็นเลขคู่</translation>
+ </message>
+ <message>
+ <source>Generates a new random MAC address.</source>
+ <translation>สุ่มแมคแอดเดรสใหม่</translation>
+ </message>
+ <message>
+ <source>&Cable Connected</source>
+ <translation>เชื่อมต่อเ&คเบิลไว้</translation>
+ </message>
+ <message>
+ <source>&Port Forwarding</source>
+ <translation>การส่งต่อ&พอร์ต</translation>
+ </message>
+ <message>
+ <source>&Promiscuous Mode:</source>
+ <translation>โหมด &Promiscuous:</translation>
+ </message>
+ <message>
+ <source>Selects the promiscuous mode policy of the network adapter when attached to an internal network, host only network or a bridge.</source>
+ <translation>เลือกใช้โหมด promiscuous ของอแดปเตอร์เครือข่ายขณะเชื่อมต่อเข้ากับเครือข่ายภายใน เครือข่ายเฉพาะโฮสต์ หรือบริดจ์</translation>
+ </message>
+ <message>
+ <source>Generic Properties:</source>
+ <translation>คุณสมบัติทั่วไป:</translation>
+ </message>
+ <message>
+ <source>Selects the network adapter on the host system that traffic to and from this network card will go through.</source>
+ <translation>เลือกแผงวงจรเครือข่ายของโฮสต์ที่ต้องการให้การ์ดเครือข่ายนี้ใช้สื่อสารทั้งขาเข้าและขาออก</translation>
+ </message>
+ <message>
+ <source>Holds the name of the internal network that this network card will be connected to. You can create a new internal network by choosing a name which is not used by any other network cards in this virtual machine or others.</source>
+ <translation>เก็บชื่อเครือข่ายภายในที่การ์ดเครือข่ายนี้จะถูกเชื่อมต่อไว้ คุณสามารถสร้างเครือข่ายภายในขึ้นมาใหม่โดยเลือกใช้ชื่อที่ไม่ได้ถูกใช้งานโดยเวอร์ชวลแมชชีนเครื่องนี้หรือเครื่องอื่น ๆ</translation>
+ </message>
+ <message>
+ <source>Selects the virtual network adapter on the host system that traffic to and from this network card will go through. You can create and remove adapters using the global network settings in the virtual machine manager window.</source>
+ <translation>เลือกแผงวงจรเครือข่ายเสมือนของโฮสต์ที่ต้องการให้การ์ดเครือข่ายนี้ใช้สื่อสารทั้งขาเข้าและขาออก คุณสามารถสร้างและถอนแผงวงจรได้โดยใช้การตั้งค่าเครือข่ายกลางในหน้าต่างจัดการเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Selects the driver to be used with this network card.</source>
+ <translation>เลือกไดร์เวอร์ที่จะใช้กับการ์ดเครือข่ายนี้</translation>
+ </message>
+ <message>
+ <source>&MAC Address:</source>
+ <translation>แ&มคแอดเดรส:</translation>
+ </message>
+ <message>
+ <source>No bridged network adapter is currently selected.</source>
+ <translation>ไม่ได้เลือกอแดปเตอร์เครือข่ายที่เชื่อมต่อกับบริดจ์ไว้</translation>
+ </message>
+ <message>
+ <source>No internal network name is currently specified.</source>
+ <translation>ไม่ได้ระบุชื่อเครือข่ายภายในไว้</translation>
+ </message>
+ <message>
+ <source>No host-only network adapter is currently selected.</source>
+ <translation>ไม่ได้เลือกอแดปเตอร์เครือข่ายเฉพาะโฮสต์ไว้</translation>
+ </message>
+ <message>
+ <source>No generic driver is currently selected.</source>
+ <translation>ไม่ได้เลือกไดร์เวอร์ทั่วไปไว้</translation>
+ </message>
+ <message>
+ <source>The MAC address must be 12 hexadecimal digits long.</source>
+ <translation>ที่อยู่ MAC ต้องเป็นเลขฐานสิบหกความยาว 12 หลักเท่านั้น</translation>
+ </message>
+ <message>
+ <source>The second digit in the MAC address may not be odd as only unicast addresses are allowed.</source>
+ <translation>เลขตัวที่สองของที่อยู่ MAC ไม่สามารถเป็นเลขคี่ได้เนื่องจากอนุญาตให้ใช้ที่อยู่แบบยูนิคาสต์เท่านั้น</translation>
+ </message>
+ <message>
+ <source>No NAT network name is currently specified.</source>
+ <translation>ไม่ได้ระบุชื่อเครือข่าย NAT ไว้</translation>
+ </message>
+ <message>
+ <source>Holds the name of the NAT network that this network card will be connected to. You can create and remove networks using the global network settings in the virtual machine manager window.</source>
+ <translation>เก็บชื่อเครือข่าย NAT ที่การ์ดเครือข่ายนี้จะถูกเชื่อมต่อไว้ คุณสามารถสร้างและนำเครือข่ายออกได้ที่การตั้งค่าเครือข่ายส่วนกลางในหน้าต่างตัวจัดการเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Selects how this virtual adapter is attached to the real network of the Host OS.</source>
+ <translation>เลือกว่าแผงวงจรเสมือนจะถูกเชื่อมต่อกับเครือข่ายจริงของโฮสต์โอเอสอย่างไร</translation>
+ </message>
+ <message>
+ <source>Shows additional network adapter options.</source>
+ <translation>แสดงตัวเลือกเพิ่มเติมสำหรับแผงวงจรเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Holds the configuration settings for the network attachment driver. The settings should be of the form <b>name=value</b> and will depend on the driver. Use <b>shift-enter</b> to add a new entry.</source>
+ <translation>เก็บการตั้ังค่าสำหรับไดร์เวอร์การเชื่อมต่อเครือข่าย ค่านี้ควรอยู่ในรูปแบบ <b>name=value</b> และขึ้นอยู่กับไดร์เวอร์ที่ใช้ กด <b>shift-enter</b> เพื่อเพิ่มรายการใหม่</translation>
+ </message>
+ <message>
+ <source>When checked, the virtual network cable is plugged in.</source>
+ <translation>เลือกที่นี่หากต้องการเชื่อมต่อสายเคเบิลเครือข่ายเสมือน</translation>
+ </message>
+ <message>
+ <source>Displays a window to configure port forwarding rules.</source>
+ <translation>แสดงหน้าต่างเพื่อกำหนดค่ากฎการส่งต่อพอร์ต</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsParallel</name>
+ <message>
+ <source>Port %1</source>
+ <comment>parallel ports</comment>
+ <translation>พอร์ต %1</translation>
+ </message>
+ <message>
+ <source>When checked, enables the given parallel port of the virtual machine.</source>
+ <translation>เลือกที่นี่เพื่อเปิดใช้พอร์ตขนานของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Enable Parallel Port</source>
+ <translation>ใ&ช้พอร์ตขนาน</translation>
+ </message>
+ <message>
+ <source>Port &Number:</source>
+ <translation>หมายเ&ลขพอร์ต:</translation>
+ </message>
+ <message>
+ <source>Holds the parallel port number. You can choose one of the standard parallel ports or select <b>User-defined</b> and specify port parameters manually.</source>
+ <translation>เลือกหมายเลขพอร์ตขนาน คุณสามารถเลือกจากรายการพอร์ตมาตรฐานหรือเลือก <b>กำหนดโดยผู้ใช้</b> และกำหนดพารามิเตอร์ของพอร์ตด้วยตนเอง</translation>
+ </message>
+ <message>
+ <source>&IRQ:</source>
+ <translation>&IRQ:</translation>
+ </message>
+ <message>
+ <source>I/O Po&rt:</source>
+ <translation>&พอร์ต I/O:</translation>
+ </message>
+ <message>
+ <source>Port &Path:</source>
+ <translation>เ&ส้นทางพอร์ต:</translation>
+ </message>
+ <message>
+ <source>Holds the host parallel device name.</source>
+ <translation>เก็บชื่ออุปกรณ์แบบขนานของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Holds the IRQ number of this parallel port. This should be a whole number between <tt>0</tt> and <tt>255</tt>. Values greater than <tt>15</tt> may only be used if the <b>I/O APIC</b> setting is enabled for this virtual machine.</source>
+ <translation>เก็บหมายเลข IRQ ของพอร์ตขนานนี้ ค่านี้ควรเป็นจำนวนเต็มระหว่าง <tt>0</tt> และ <tt>255</tt> ค่าที่มากกว่า <tt>15</tt> จะสามารถใช้ได้ในกรณีที่เปิดใช้ <b>I/O APIC</b> สำหรับเวอร์ชวลแมชชีนนี้เท่านั้น</translation>
+ </message>
+ <message>
+ <source>Holds the base I/O port address of this parallel port. Valid values are integer numbers in range from <tt>0</tt> to <tt>0xFFFF</tt>.</source>
+ <translation>เก็บที่อยู่พอร์ต I/O พื้นฐานสำหรับพอร์ตขนานนี้ ค่าที่ใช้ได้คือเลขจำนวนเต็มตั้งแต่ <tt>0</tt> ถึง <tt>0xFFFF</tt></translation>
+ </message>
+ <message>
+ <source>No IRQ is currently specified.</source>
+ <translation>ไม่ได้ระบุ IRQ ไว้</translation>
+ </message>
+ <message>
+ <source>No I/O port is currently specified.</source>
+ <translation>ไม่ได้ระบุพอร์ต I/O ไว้</translation>
+ </message>
+ <message>
+ <source>Two or more ports have the same settings.</source>
+ <translation>มีสองพอร์ตหรือมากกว่าที่ใช้ค่าเดียวกัน</translation>
+ </message>
+ <message>
+ <source>No port path is currently specified.</source>
+ <translation>ไม่ได้ระบุเส้นทางพอร์ตไว้</translation>
+ </message>
+ <message>
+ <source>There are currently duplicate port paths specified.</source>
+ <translation>มีการกำหนดเส้นทางพอร์ตซ้ำกันอยู่</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsPortForwardingDlg</name>
+ <message>
+ <source>Port Forwarding Rules</source>
+ <translation>กฎการส่งต่อพอร์ต</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsSF</name>
+ <message>
+ <source> Machine Folders</source>
+ <translation>โฟลเดอร์ของเครื่อง</translation>
+ </message>
+ <message>
+ <source> Transient Folders</source>
+ <translation>โฟลเดอร์ชั่วคราว</translation>
+ </message>
+ <message>
+ <source>Full</source>
+ <translation>เต็มที่</translation>
+ </message>
+ <message>
+ <source>Read-only</source>
+ <translation>อ่านอย่างเดียว</translation>
+ </message>
+ <message>
+ <source>Lists all shared folders accessible to this machine. Use 'net use x: \\vboxsvr\share' to access a shared folder named <i>share</i> from a DOS-like OS, or 'mount -t vboxsf share mount_point' to access it from a Linux OS. This feature requires Guest Additions.</source>
+ <translation>แสดงรายการโฟลเดอร์ใช้ร่วมกันทั้งหมดที่เข้าถึงได้จากเครื่องนี้ ใช้ 'net use x: \\vboxsvr \share' เพื่อเข้าถึงโฟลเดอร์ใช้ร่วมกันชื่อ <i>share</i> จากระบบปฏิบัติการแบบดอส หรือ 'mount -t vboxsf share mount_point' เพื่อเข้าถึงจากระบบปฏิบัติการลินุกซ์ คุณสมบัตินี้ต้องใช้โปรแกรมเสริมสำหรับเกสต์</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>เส้นทาง</translation>
+ </message>
+ <message>
+ <source>Access</source>
+ <translation>การเข้าถึง</translation>
+ </message>
+ <message>
+ <source>&Folders List</source>
+ <translation>รายการโ&ฟลเดอร์</translation>
+ </message>
+ <message>
+ <source>Auto-mount</source>
+ <translation>เมาต์อัตโนมัติ</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>ใช่</translation>
+ </message>
+ <message>
+ <source>Add Shared Folder</source>
+ <translation>เพิ่มโฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>Edit Shared Folder</source>
+ <translation>แก้ไขโฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>Remove Shared Folder</source>
+ <translation>นำโฟลเดอร์ใช้ร่วมกันออก</translation>
+ </message>
+ <message>
+ <source>Adds new shared folder.</source>
+ <translation>เพิ่มโฟลเดอร์ใช้ร่วมกันใหม่</translation>
+ </message>
+ <message>
+ <source>Edits selected shared folder.</source>
+ <translation>แก้ไขโฟลเดอร์ใช้ร่วมกันที่เลือก</translation>
+ </message>
+ <message>
+ <source>Removes selected shared folder.</source>
+ <translation>นำโฟลเดอร์ใช้ร่วมกันที่เลือกออก</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsSFDetails</name>
+ <message>
+ <source>Add Share</source>
+ <translation>เพิ่มแชร์</translation>
+ </message>
+ <message>
+ <source>Edit Share</source>
+ <translation>แก้ไขแชร์</translation>
+ </message>
+ <message>
+ <source>Folder Path:</source>
+ <translation>เส้นทางโฟลเดอร์:</translation>
+ </message>
+ <message>
+ <source>Folder Name:</source>
+ <translation>ชื่อโฟลเดอร์:</translation>
+ </message>
+ <message>
+ <source>Holds the name of the shared folder (as it will be seen by the guest OS).</source>
+ <translation>แสดงชื่อโฟลเดอร์ที่ใช้ร่วมกัน (เช่นเดียวกับที่เห็นโดยเกสต์โอเอส)</translation>
+ </message>
+ <message>
+ <source>When checked, the guest OS will not be able to write to the specified shared folder.</source>
+ <translation>เลือกที่นี่เพื่อป้องกันไม่ให้ระบบปฏิบัติการเกสต์เขียนลงในโฟลเดอร์ใช้ร่วมกันที่ระบุได้</translation>
+ </message>
+ <message>
+ <source>&Read-only</source>
+ <translation>&อ่านอย่างเดียว</translation>
+ </message>
+ <message>
+ <source>&Make Permanent</source>
+ <translation>ทำให้คงอยู่&ถาวร</translation>
+ </message>
+ <message>
+ <source>When checked, the guest OS will try to automatically mount the shared folder on startup.</source>
+ <translation>เลือกที่นี่เพื่อให้ระบบปฏิบัติการเกสต์พยายามเมาต์โฟลเดอร์ใช้ร่วมกันโดยอัตโนมัติขณะเริ่มการทำงาน</translation>
+ </message>
+ <message>
+ <source>&Auto-mount</source>
+ <translation>เมาต์&อัตโนมัติ</translation>
+ </message>
+ <message>
+ <source>When checked, this shared folder will be permanent.</source>
+ <translation>หากเลือกไว้ โฟลเดอร์ใช้ร่วมกันจะคงอยู่ถาวร</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsSerial</name>
+ <message>
+ <source>Port %1</source>
+ <comment>serial ports</comment>
+ <translation>พอร์ต %1</translation>
+ </message>
+ <message>
+ <source>When checked, enables the given serial port of the virtual machine.</source>
+ <translation>เลือกที่นี่เพื่อเปิดใช้พอร์ตอนุกรมของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Enable Serial Port</source>
+ <translation>ใ&ช้พอร์ตอนุกรม</translation>
+ </message>
+ <message>
+ <source>Port &Number:</source>
+ <translation>หมายเ&ลขพอร์ต:</translation>
+ </message>
+ <message>
+ <source>Selects the serial port number. You can choose one of the standard serial ports or select <b>User-defined</b> and specify port parameters manually.</source>
+ <translation>เลือกหมายเลขพอร์ตอนุกรม คุณสามารถเลือกจากรายการพอร์ตมาตรฐานหรือเลือก <b>กำหนดโดยผู้ใช้</b> และกำหนดพารามิเตอร์ด้วยตนเอง</translation>
+ </message>
+ <message>
+ <source>&IRQ:</source>
+ <translation>&IRQ:</translation>
+ </message>
+ <message>
+ <source>I/O Po&rt:</source>
+ <translation>&พอร์ต I/O:</translation>
+ </message>
+ <message>
+ <source>Port &Mode:</source>
+ <translation>โ&หมดของพอร์ต:</translation>
+ </message>
+ <message>
+ <source>Holds the IRQ number of this serial port. This should be a whole number between <tt>0</tt> and <tt>255</tt>. Values greater than <tt>15</tt> may only be used if the <b>I/O APIC</b> setting is enabled for this virtual machine.</source>
+ <translation>เก็บหมายเลข IRQ ของพอร์ตอนุกรมนี้ ค่านี้ควรเป็นจำนวนเต็มระหว่าง <tt>0</tt> และ <tt>255</tt> ค่าที่มากกว่า <tt>15</tt> จะสามารถใช้ได้ในกรณีที่เปิดใช้ <b>I/O APIC</b> สำหรับเวอร์ชวลแมชชีนนี้เท่านั้น</translation>
+ </message>
+ <message>
+ <source>Holds the base I/O port address of this serial port. Valid values are integer numbers in range from <tt>0</tt> to <tt>0xFFFF</tt>.</source>
+ <translation>เก็บที่อยู่พอร์ต I/O พื้นฐานสำหรับพอร์ตอนุกรมนี้ ค่าที่ใช้ได้คือเลขจำนวนเต็มตั้งแต่ <tt>0</tt> ถึง <tt>0xFFFF</tt></translation>
+ </message>
+ <message>
+ <source>&Connect to existing pipe/socket</source>
+ <translation>เ&ชื่อมต่อไปยังไปป์/ซอคเก็ตที่มีอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>&Path/Address:</source>
+ <translation>เ&ส้นทาง/ที่อยู่:</translation>
+ </message>
+ <message>
+ <source><p>In <b>Host Pipe</b> mode: Holds the path to the serial port's pipe on the host. Examples: "\\.\pipe\myvbox" or "/tmp/myvbox", for Windows and UNIX-like systems respectively.</p><p>In <b>Host Device</b> mode: Holds the host serial device name. Examples: "COM1" or "/dev/ttyS0".</p><p>In <b>Raw File</b> mode: Holds the file-path on the host system, where the seri [...]
+ <translation><p>ในโหมด<b>ท่อของโฮสต์</b>: เก็บเส้นทางไปยังท่อของพอร์ตอนุกรมบนโฮสต์ ตัวอย่าง: "\\.\pipe\myvbox" หรือ "/tmp/myvbox" สำหรับวินโดวส์และระบบปฏิบัติการกลุ่มยูนิกส์ตามลำดับ</p><p>ในโหมด<b>อุปกรณ์ของโฮสต์</b>: เก็บชื่ออุปกรณ์อนุกรมบนโฮสต์ ตัวอย่าง: "COM1" หรือ "/dev/ttyS0"</p><p>ในโหมด<b>ไฟล์ดิบ</b>: เก็บเส้นทางไปยังไฟล์บนโฮสต์ซึ่งเอาต์พุตจากพอร์ตอนุกรมจะถูกส่งไปบันทึ [...]
+ </message>
+ <message>
+ <source>Selects the working mode of this serial port. If you select <b>Disconnected</b>, the guest OS will detect the serial port but will not be able to operate it.</source>
+ <translation>เลือกโหมดการทำงานของพอร์ตอนุกรมนี้ หากคุณเลือก<b>ไม่เชื่อมต่อ</b> โอเอสของเกสต์จะตรวจพบพอร์ตอนุกรมแต่จะไม่สามารถใช้งานพอร์ตดังกล่าวได้</translation>
+ </message>
+ <message>
+ <source>When checked, the virtual machine will assume that the pipe or socket specified in the <b>Path/Address</b> field exists and try to use it. Otherwise, the pipe or socket will be created by the virtual machine when it starts.</source>
+ <translation>หากเลือกไว้ เวอร์ชวลแมชชีนจะถือว่าไปป์หรือซอคเกตที่ระบุไว้ใน<b>เส้นทาง/ที่อยู่</b>มีอยู่แล้วและจะพยายามเข้าใช้งาน มิฉะนั้น ไปป์หรือซอคเก็ตจะถูกสร้างขึ้นโดยเวอร์ชวลแมชชีนขณะเริ่มทำงาน</translation>
+ </message>
+ <message>
+ <source>No IRQ is currently specified.</source>
+ <translation>ไม่ได้ระบุ IRQ ไว้</translation>
+ </message>
+ <message>
+ <source>No I/O port is currently specified.</source>
+ <translation>ไม่ได้ระบุพอร์ต I/O ไว้</translation>
+ </message>
+ <message>
+ <source>Two or more ports have the same settings.</source>
+ <translation>มีสองพอร์ตหรือมากกว่าที่ใช้ค่าเดียวกัน</translation>
+ </message>
+ <message>
+ <source>No port path is currently specified.</source>
+ <translation>ไม่ได้ระบุเส้นทางพอร์ตไว้</translation>
+ </message>
+ <message>
+ <source>There are currently duplicate port paths specified.</source>
+ <translation>มีการกำหนดเส้นทางพอร์ตซ้ำกันอยู่</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsStorage</name>
+ <message>
+ <source><nobr><b>%1</b></nobr><br><nobr>Bus: %2</nobr><br><nobr>Type: %3</nobr></source>
+ <translation><nobr><b>%1</b></nobr><br><nobr>บัส: %2</nobr><br><nobr>ชนิด: %3</nobr></translation>
+ </message>
+ <message>
+ <source>Add Controller</source>
+ <translation>เพิ่มตัวควบคุม</translation>
+ </message>
+ <message>
+ <source>Add IDE Controller</source>
+ <translation>เพิ่มตัวควบคุม IDE</translation>
+ </message>
+ <message>
+ <source>Add SATA Controller</source>
+ <translation>เพิ่มตัวควบคุม SATA</translation>
+ </message>
+ <message>
+ <source>Add SCSI Controller</source>
+ <translation>เพิ่มตัวควบคุม SCSI</translation>
+ </message>
+ <message>
+ <source>Add Floppy Controller</source>
+ <translation>เพิ่มตัวควบคุมฟลอปปี้</translation>
+ </message>
+ <message>
+ <source>Remove Controller</source>
+ <translation>เอาตัวควบคุมออก</translation>
+ </message>
+ <message>
+ <source>Add Attachment</source>
+ <translation>เพิ่มส่วนเชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>Add Hard Disk</source>
+ <translation>เพิ่มฮาร์ดดิสก์</translation>
+ </message>
+ <message>
+ <source>Remove Attachment</source>
+ <translation>นำส่วนเชื่อมต่อออก</translation>
+ </message>
+ <message>
+ <source>Hard &Disk:</source>
+ <translation>ฮาร์ด&ดิสก์:</translation>
+ </message>
+ <message>
+ <source>&Storage Tree</source>
+ <translation>&ทรีหน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>ข้อมูล</translation>
+ </message>
+ <message>
+ <source>The Storage Tree can contain several controllers of different types. This machine currently has no controllers.</source>
+ <translation>ทรีของหน่วยเก็บข้อมูลสามารถเก็บตัวควบคุมได้หลายชนิด ขณะนี้เครื่องนี้ไม่มีตัวควบคุมติดตั้งไว้</translation>
+ </message>
+ <message>
+ <source>Attributes</source>
+ <translation>คุณสมบัติเฉพาะ</translation>
+ </message>
+ <message>
+ <source>&Name:</source>
+ <translation>&ชื่อ:</translation>
+ </message>
+ <message>
+ <source>&Type:</source>
+ <translation>ช&นิด:</translation>
+ </message>
+ <message>
+ <source>Selects the sub-type of the storage controller currently selected in the Storage Tree.</source>
+ <translation>เลือกชนิดย่อยของตัวควบคุมหน่วยเก็บข้อมูลที่เลือกไว้ในทรีของหน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Selects the slot on the storage controller used by this attachment. The available slots depend on the type of the controller and other attachments on it.</source>
+ <translation>เลือกสล็อตบนตัวควบคุมหน่วยเก็บข้อมูลที่ใช้โดยส่วนเชื่อมต่อนี้ สล็อตที่สามารถใช้งานได้ขึ้นอยู่กับชนิดของตัวควบคุมและอุปกรณ์ต่าง ๆ ที่เชื่อมต่ออยู่</translation>
+ </message>
+ <message>
+ <source>When checked, allows the guest to send ATAPI commands directly to the host-drive which makes it possible to use CD/DVD writers connected to the host inside the VM. Note that writing audio CD inside the VM is not yet supported.</source>
+ <translation>หากเลือกไว้ จะอนุญาตให้เกสต์ส่งคำสั่ง ATAPI ไปยังไดรฟ์ของโฮสต์โดยตรง ซึ่งจะทำให้สามารถใช้เครื่องเขียนซีดี/ดีวีดีที่เชื่อมต่ออยู่กับโฮสต์จากภายใน VM ได้ โปรดทราบว่าการเขียนซีดีเพลงจากภายใน VM ยังไม่สามารถทำได้</translation>
+ </message>
+ <message>
+ <source>&Passthrough</source>
+ <translation>ส่ง&ผ่านได้</translation>
+ </message>
+ <message>
+ <source>Virtual Size:</source>
+ <translation>ขนาดเสมือน:</translation>
+ </message>
+ <message>
+ <source>Actual Size:</source>
+ <translation>ขนาดจริง:</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>ขนาด:</translation>
+ </message>
+ <message>
+ <source>Location:</source>
+ <translation>ที่ตั้ง:</translation>
+ </message>
+ <message>
+ <source>Type (Format):</source>
+ <translation>ชนิด (รูปแบบ):</translation>
+ </message>
+ <message>
+ <source>Attached to:</source>
+ <translation>เชื่อมต่อกับ:</translation>
+ </message>
+ <message>
+ <source>Use Host I/O Cache</source>
+ <translation>ใช้แคช I/O ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Add SAS Controller</source>
+ <translation>เพิ่มตัวควบคุม SAS</translation>
+ </message>
+ <message>
+ <source>Type:</source>
+ <translation>ชนิด:</translation>
+ </message>
+ <message>
+ <source>Host Drive</source>
+ <translation>ไดรฟ์ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Choose or create a virtual hard disk file. The virtual machine will see the data in the file as the contents of the virtual hard disk.</source>
+ <translation>เลือกหรือสร้างไฟล์ฮาร์ดดิสก์เสมือน เวอร์ชวลแมชชีนจะมองเห็นข้อมูลในไฟล์เป็นเนื้อหาของฮาร์ดดิสก์เสมือน</translation>
+ </message>
+ <message>
+ <source>Floppy &Drive:</source>
+ <translation>ไ&ดรฟ์ฟลอปปี้:</translation>
+ </message>
+ <message>
+ <source>Choose a virtual floppy disk or a physical drive to use with the virtual drive. The virtual machine will see a disk inserted into the drive with the data in the file or on the disk in the physical drive as its contents.</source>
+ <translation>เลือกแผ่นฟลอปปี้ดิสก์เสมือนหรือแผ่นจริงเพื่อใช้กับเวอร์ชวลแมชชีน เวอร์ชวลแมชชีนจะมองเห็นข้อมูลในไฟล์หรือข้อมูลในแผ่นที่อยู่ในไดรฟ์จริงเป็นเนื้อหาของแผ่นที่ถูกใส่ไว้</translation>
+ </message>
+ <message>
+ <source>Remove disk from virtual drive</source>
+ <translation>นำดิสก์ออกจากไดรฟ์เสมือน</translation>
+ </message>
+ <message>
+ <source>&Live CD/DVD</source>
+ <translation>ซีดี/ดีวีดีแบบ &Live</translation>
+ </message>
+ <message>
+ <source>&Solid-state Drive</source>
+ <translation>ไดรฟ์โ&ซลิดสเตต</translation>
+ </message>
+ <message>
+ <source>Details:</source>
+ <translation>รายละเอียด:</translation>
+ </message>
+ <message>
+ <source>at most one supported</source>
+ <comment>controller</comment>
+ <translation>รองรับเพียงหนึ่งเท่านั้น</translation>
+ </message>
+ <message>
+ <source>up to %1 supported</source>
+ <comment>controllers</comment>
+ <translation>รองรับไม่เกิน %1</translation>
+ </message>
+ <message>
+ <source>&Port Count:</source>
+ <translation>จำนวน&พอร์ต:</translation>
+ </message>
+ <message>
+ <source>Selects the port count of the SATA storage controller currently selected in the Storage Tree. This must be at least one more than the highest port number you need to use.</source>
+ <translation>เลือกจำนวนพอร์ตของตัวควบคุมหน่วยเก็บข้อมูล SATA ที่ถูกเลือกไว้ในทรีของหน่วยเก็บข้อมูล จำนวนนี้ต้องมีค่ามากกว่าจำนวนพอร์ตสูงสุดที่คุณต้องการใช้อย่างน้อยหนึ่งพอร์ต</translation>
+ </message>
+ <message>
+ <source>Controller: %1</source>
+ <translation>ตัวควบคุม: %1</translation>
+ </message>
+ <message>
+ <source>No name is currently specified for the controller at position <b>%1</b>.</source>
+ <translation>ตัวควบคุมที่ตำแหน่ง <b>%1</b> ไม่ได้กำหนดชื่อไว้</translation>
+ </message>
+ <message>
+ <source>The controller at position <b>%1</b> has the same name as the controller at position <b>%2</b>.</source>
+ <translation>ตัวควบคุมที่ตำแหน่ง <b>%1</b> มีชื่อซ้ำกันกับตัวควบคุมที่ตำแหน่ง <b>%2</b></translation>
+ </message>
+ <message>
+ <source>No hard disk is selected for <i>%1</i>.</source>
+ <translation>ไม่ได้เลือกฮาร์ดดิสก์ไว้สำหรับ <i>%1</i></translation>
+ </message>
+ <message>
+ <source><i>%1</i> is using a disk that is already attached to <i>%2</i>.</source>
+ <translation><i>%1</i> กำลังใช้ฮาร์ดดิสก์ที่เชื่อมต่ออยู่กับ <i>%2</i></translation>
+ </message>
+ <message>
+ <source>The machine currently has more storage controllers assigned than a %1 chipset supports. Please change the chipset type on the System settings page or reduce the number of the following storage controllers on the Storage settings page: %2</source>
+ <translation>ขณะนี้เครื่องมีจำนวนตัวควบคุมหน่วยเก็บข้อมูลมากกว่าที่ชิปเซ็ต %1 รองรับ กรุณาเลือกชนิดชิปเซ็ตใหม่ในหน้าการตั้งค่าหลักของระบบ หรือลดจำนวนตัวควบคุมหน่วยเก็บข้อมูลต่อไปนี้ในหน้าการตั้งค่าหน่วยเก็บข้อมูล: %2</translation>
+ </message>
+ <message>
+ <source>Add USB Controller</source>
+ <translation>เพิ่มตัวควบคุม USB</translation>
+ </message>
+ <message>
+ <source>&Hot-pluggable</source>
+ <translation>&ถอดได้ไม่ต้องปิดเครื่อง</translation>
+ </message>
+ <message>
+ <source>Add Optical Drive</source>
+ <translation>เพิ่มไดรฟ์ออปติคัล</translation>
+ </message>
+ <message>
+ <source>Add Floppy Drive</source>
+ <translation>เพิ่มไดรฟ์ฟลอปปี้</translation>
+ </message>
+ <message>
+ <source>Optical &Drive:</source>
+ <translation>ออปติคัลไ&ดรฟ์</translation>
+ </message>
+ <message>
+ <source>Choose a virtual optical disk or a physical drive to use with the virtual drive. The virtual machine will see a disk inserted into the drive with the data in the file or on the disk in the physical drive as its contents.</source>
+ <translation>เลือกออปติคัลดิสก์เสมือนหรือดิสก์จริงเพื่อใช้กับไดรฟ์เสมือน เวอร์ชวลแมชชีนจะมองเห็นข้อมูลของไฟล์หรือบนดิสก์จริงที่ใส่ไว้เป็นเนื้อหาในไดรฟ์</translation>
+ </message>
+ <message>
+ <source>Encrypted with key:</source>
+ <translation>เข้ารหัสลับด้วยกุญแจ:</translation>
+ </message>
+ <message>
+ <source>Lists all storage controllers for this machine and the virtual images and host drives attached to them.</source>
+ <translation>แสดงรายการตัวควบคุมหน่วยเก็บข้อมูลทั้งหมดของเครื่องนี้รวมถึงอิมเมจเสมือนและไดรฟ์ของโฮสต์ที่เชื่อมต่ออยู่</translation>
+ </message>
+ <message>
+ <source>Holds the name of the storage controller currently selected in the Storage Tree.</source>
+ <translation>เก็บชื่อตัวควบคุมหน่วยเก็บข้อมูลที่ถูกเลือกไว้ในทรีของหน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>When checked, allows to use host I/O caching capabilities.</source>
+ <translation>หากเลือกไว้ จะอนุญาตให้ใช้ความสามารถในการแคช I/O ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>When checked, the virtual disk will not be removed when the guest system ejects it.</source>
+ <translation>หากเลือกไว้ ดิสก์เสมือนจะไม่ถูกนำออกไปเมื่อระบบของเกสต์ดีดแผ่นออก</translation>
+ </message>
+ <message>
+ <source>When checked, the guest system will see the virtual disk as a solid-state device.</source>
+ <translation>หากเลือกไว้ ระบบของเกสต์จะมองเห็นดิสก์เสมือนเป็นอุปกรณ์โซลิดสเตต</translation>
+ </message>
+ <message>
+ <source>When checked, the guest system will see the virtual disk as a hot-pluggable device.</source>
+ <translation>หากเลือกไว้ ระบบของเกสต์จะมองเห็นดิสก์เสมือนเป็นอุปกรณ์ที่ถอดออกได้โดยไม่ต้องปิดเครื่อง</translation>
+ </message>
+ <message>
+ <source>Image</source>
+ <comment>storage image</comment>
+ <translation>อิมเมจ</translation>
+ </message>
+ <message>
+ <source><nobr>Expands/Collapses item.</nobr></source>
+ <translation><nobr>ขยาย/ยุบรายการ</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Adds hard disk.</nobr></source>
+ <translation><nobr>เพิ่มฮาร์ดดิสก์</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Adds optical drive.</nobr></source>
+ <translation><nobr>เพิ่มไดรฟ์ออปติคัล</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Adds floppy drive.</nobr></source>
+ <translation><nobr>เพิ่มไดรฟ์ฟลอปปี้</nobr></translation>
+ </message>
+ <message>
+ <source>Adds new storage controller.</source>
+ <translation>เพิ่มตัวควบคุมหน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Removes selected storage controller.</source>
+ <translation>นำตัวควบคุมหน่วยเก็บข้อมูลที่เลือกออก</translation>
+ </message>
+ <message>
+ <source>Adds new storage attachment.</source>
+ <translation>เพิ่มส่วนเชื่อมต่อหน่วยเก็บข้อมูลใหม่</translation>
+ </message>
+ <message>
+ <source>Removes selected storage attachment.</source>
+ <translation>นำส่วนเชื่อมต่อหน่วยเก็บข้อมูลออก</translation>
+ </message>
+ <message>
+ <source>Create New Hard Disk...</source>
+ <translation>สร้างฮาร์ดดิสก์ใหม่...</translation>
+ </message>
+ <message>
+ <source>Choose Virtual Hard Disk File...</source>
+ <translation>เลือกไฟล์ฮาร์ดดิสก์เสมือน...</translation>
+ </message>
+ <message>
+ <source>Choose Virtual Optical Disk File...</source>
+ <translation>เลือกไฟล์ออปติคัลดิสก์เสมือน...</translation>
+ </message>
+ <message>
+ <source>Remove Disk from Virtual Drive</source>
+ <translation>นำดิสก์ออกจากไดรฟ์เสมือน</translation>
+ </message>
+ <message>
+ <source>Choose Virtual Floppy Disk File...</source>
+ <translation>เลือกไฟล์ฟลอปปี้ดิสก์เสมือน...</translation>
+ </message>
+ <message>
+ <source>Choose disk image...</source>
+ <comment>This is used for hard disks, optical media and floppies</comment>
+ <translation>เลือกดิสก์อิมเมจ...</translation>
+ </message>
+ <message>
+ <source>Add NVMe Controller</source>
+ <translation>เพิ่มตัวควบคุม NVMe</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsSystem</name>
+ <message>
+ <source>&Motherboard</source>
+ <translation>แ&ผงวงจรหลัก</translation>
+ </message>
+ <message>
+ <source>Base &Memory:</source>
+ <translation>&หน่วยความจำหลัก:</translation>
+ </message>
+ <message>
+ <source>Controls the amount of memory provided to the virtual machine. If you assign too much, the machine might not start.</source>
+ <translation>ควบคุมจำนวนหน่วยความจำที่จัดสรรให้เวอร์ชวลแมชชีน หากคุณกำหนดไว้มากเกินไปเครื่องอาจไม่สามารถทำงานได้</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <translation>MB</translation>
+ </message>
+ <message>
+ <source>&Boot Order:</source>
+ <translation>ลำดับการ&บูต:</translation>
+ </message>
+ <message>
+ <source>Defines the boot device order. Use the checkboxes on the left to enable or disable individual boot devices. Move items up and down to change the device order.</source>
+ <translation>กำหนดลำดับอุปกรณ์สำหรับบูตระบบ ใช้เช็คบอกซ์ทางด้านซ้ายมือเพื่อเปิดหรือปิดการใช้งานอุปกรณ์แต่ละตัว แล้วเลื่อนขึ้นหรือลงให้อยู่ตามลำดับที่ต้องการ</translation>
+ </message>
+ <message>
+ <source>Moves the selected boot device down.</source>
+ <translation>เลื่อนอุปกรณ์สำหรับการบูตที่เลือกลง</translation>
+ </message>
+ <message>
+ <source>Moves the selected boot device up.</source>
+ <translation>เลื่อนอุปกรณ์สำหรับการบูตที่เลือกขึ้น</translation>
+ </message>
+ <message>
+ <source>Extended Features:</source>
+ <translation>คุณสมบัติเพิ่มเติม:</translation>
+ </message>
+ <message>
+ <source>When checked, the virtual machine will support the Input Output APIC (I/O APIC), which may slightly decrease performance. <b>Note:</b> don't disable this feature after having installed a Windows guest operating system!</source>
+ <translation>หากเลือกไว้ เวอร์ชวลแมชชีนจะรองรับการอินพุตและเอาต์พุตแบบ APIC (I/O APIC) ซึ่งอาจส่งผลให้ประสิทธิภาพลดลงเล็กน้อย <b>หมายเหตุ:</b> อย่าปิดการใช้งานคุณสมบัตินี้หากได้ติดตั้งวินโดวส์เป็นระบบปฏิบัติการของเกสต์แล้ว!</translation>
+ </message>
+ <message>
+ <source>Enable &I/O APIC</source>
+ <translation>เปิดใช้ &I/O APIC</translation>
+ </message>
+ <message>
+ <source>&Processor</source>
+ <translation>โ&ปรเซสเซอร์</translation>
+ </message>
+ <message>
+ <source>&Processor(s):</source>
+ <translation>โ&ปรเซสเซอร์</translation>
+ </message>
+ <message>
+ <source>When checked, the Physical Address Extension (PAE) feature of the host CPU will be exposed to the virtual machine.</source>
+ <translation>เลือกที่นี่หากต้องการให้เวอร์ชวลแมชชีนเข้าถึงส่วนขยายหน่วยความจำกายภาพ (PAE) บนซีพียูของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Enable PA&E/NX</source>
+ <translation>เปิดใช้ PA&E/NX</translation>
+ </message>
+ <message>
+ <source>Acce&leration</source>
+ <translation>ตัวเ&ร่งความเร็ว</translation>
+ </message>
+ <message>
+ <source>Hardware Virtualization:</source>
+ <translation>เวอร์ชวลไลเซชันฮาร์ดแวร์:</translation>
+ </message>
+ <message>
+ <source>When checked, the virtual machine will try to make use of the host CPU's hardware virtualization extensions such as Intel VT-x and AMD-V.</source>
+ <translation>เมื่อเลือก เวอร์ชวลแมชชีนจะพยายามใช้งานส่วนขยายเวอร์ชวลไลเซชันฮาร์ดแวร์ในซีพียูของโฮสต์ เช่น Intel VT-x และ AMD-V</translation>
+ </message>
+ <message>
+ <source>Enable &VT-x/AMD-V</source>
+ <translation>เปิดใช้ &VT-x/AMD-V</translation>
+ </message>
+ <message>
+ <source>When checked, the virtual machine will try to make use of the nested paging extension of Intel VT-x and AMD-V.</source>
+ <translation>เลือกที่นี่หากต้องการให้เวอร์ชวลแมชชีนลองใช้ส่วนขยายการแบ่งหน้าซ้ำซ้อน (nested paging) ของ Intel VT-x และ AMD-V</translation>
+ </message>
+ <message>
+ <source>Enable Nested Pa&ging</source>
+ <translation>เปิดใช้การแบ่ง&หน้าซ้อนกัน</translation>
+ </message>
+ <message>
+ <source>When checked, the guest will support the Extended Firmware Interface (EFI), which is required to boot certain guest OSes. Non-EFI aware OSes will not be able to boot if this option is activated.</source>
+ <translation>เลือกที่นี่หากต้องการให้เกสต์รองรับส่วนเชื่อมต่อเฟิร์มแวร์แบบขยาย (EFI) ซึ่งจำเป็นต้องใช้เพื่อบูตโอเอสบางชนิด โอเอสที่ไม่รู้จัก EFI จะไม่สามารถบูตได้หากตัวเลือกนี้เปิดใช้งานอยู่</translation>
+ </message>
+ <message>
+ <source>Enable &EFI (special OSes only)</source>
+ <translation>เปิดใช้ &EFI (เฉพาะโอเอสที่ต้องใช้)</translation>
+ </message>
+ <message>
+ <source>Hardware Clock in &UTC Time</source>
+ <translation>นาฬิกาฮาร์ดแวร์เป็นเวลา &UTC</translation>
+ </message>
+ <message>
+ <source>Controls the number of virtual CPUs in the virtual machine. You need hardware virtualization support on your host system to use more than one virtual CPU.</source>
+ <translation>ควบคุมจำนวนซีพียูเสมือนในเวอร์ชวลแมชชีน คุณต้องใช้เวอร์ชวลไลเซชันฮาร์ดแวร์บนโฮสต์ของคุณเพื่อใช้ซีพียูเสมือนมากกว่าหนึ่งตัว</translation>
+ </message>
+ <message>
+ <source>&Chipset:</source>
+ <translation>&ชิปเซ็ต:</translation>
+ </message>
+ <message>
+ <source>Selects the chipset to be emulated in this virtual machine. Note that the ICH9 chipset emulation is experimental and not recommended except for guest systems (such as Mac OS X) which require it.</source>
+ <translation>เลือกชิปเซ็ตที่ต้องการจำลองการทำงานในเวอร์ชวลแมชชีน โปรดทราบว่าการจำลองการทำงานของชิปเซ็ต ICH9 อยู่ในขั้นทดลอง และไม่แนะนำให้ใช้เว้นแต่จำเป็นสำหรับระบบปฏิบัติการเกสต์ (เช่น Mac OS X) </translation>
+ </message>
+ <message>
+ <source>&Execution Cap:</source>
+ <translation>จำกัดการ&ประมวลผล:</translation>
+ </message>
+ <message>
+ <source>Limits the amount of time that each virtual CPU is allowed to run for. Each virtual CPU will be allowed to use up to this percentage of the processing time available on one physical CPU. The execution cap can be disabled by setting it to 100%. Setting the cap too low can make the machine feel slow to respond.</source>
+ <translation>จำกัดเวลาที่อนุญาตให้ซีพียูเสมือนแต่ละตัวทำงานได้ แต่ละซีพียูจะได้รับอนุญาตให้ใช้เวลาไม่เกินร้อยละที่กำหนดให้บนซีพียูจริงหนึ่งตัว การจำกัดการประมวลผลนี้สามารถปิดการใช้งานได้หากกำหนดให้เป็น 100% การตั้งค่านี้ต่ำเกินไปอาจทำให้รู้สึกว่าเครื่องตอบสนองล่าช้าได้</translation>
+ </message>
+ <message>
+ <source>&Pointing Device:</source>
+ <translation>อุปกรณ์&ชี้ตำแหน่ง:</translation>
+ </message>
+ <message>
+ <source>Determines whether the emulated pointing device is a standard PS/2 mouse, a USB tablet or a USB multi-touch tablet.</source>
+ <translation>กำหนดว่าจะให้อุปกรณ์ชี้ตำแหน่งถูกแปลงเป็นเมาส์ PS/2 มาตรฐาน แท็บเล็ต USB หรือแท็บเล็ต USB แบบมีหลายจุดสัมผัส</translation>
+ </message>
+ <message>
+ <source>More than <b>%1%</b> of the host computer's memory (<b>%2</b>) is assigned to the virtual machine. Not enough memory is left for the host operating system. Please select a smaller amount.</source>
+ <translation>หน่วยความจำของโฮสต์ (<b>%2</b>) มากกว่า <b>%1%</b> ถูกจัดสรรให้กับเวอร์ชวลแมชชีน ทำให้มีหน่วยความจำเหลือไม่เพียงพอสำหรับระบบปฏิบัติการของโฮสต์ โปรดเลือกขนาดที่เล็กลง</translation>
+ </message>
+ <message>
+ <source>More than <b>%1%</b> of the host computer's memory (<b>%2</b>) is assigned to the virtual machine. There might not be enough memory left for the host operating system. Please consider selecting a smaller amount.</source>
+ <translation>หน่วยความจำของโฮสต์ (<b>%2</b>) มากกว่า <b>%1%</b> ถูกจัดสรรให้กับเวอร์ชวลแมชชีน อาจมีหน่วยความจำเหลือไม่เพียงพอสำหรับระบบปฏิบัติการของโฮสต์ โปรดพิจารณาเลือกขนาดที่เล็กลง</translation>
+ </message>
+ <message>
+ <source>For performance reasons, the number of virtual CPUs attached to the virtual machine may not be more than twice the number of physical CPUs on the host (<b>%1</b>). Please reduce the number of virtual CPUs.</source>
+ <translation>เพื่อวัตถุประสงค์ด้านประสิทธิภาพ จำนวนซีพียูเสมือนที่เชื่อมต่อกับเวอร์ชวลแมชชีนไม่อาจมีจำนวนเกินกว่าสองเท่าของจำนวนซีพียูจริงบนโฮสต์ (<b>%1</b>) กรุณาลดจำนวนซีพียูเสมือนลง</translation>
+ </message>
+ <message>
+ <source>More virtual CPUs are assigned to the virtual machine than the number of physical CPUs on the host system (<b>%1</b>). This is likely to degrade the performance of your virtual machine. Please consider reducing the number of virtual CPUs.</source>
+ <translation>จำนวนซีพียูที่กำหนดให้เวอร์ชวลแมชชีนมากกว่าจำนวนซีพียูจริงที่มีบนโฮสต์ (<b>%1</b>) ซึ่งอาจลดประสิทธิภาพของเวอร์ชวลแมชชีนของคุณลงได้ โปรดพิจารณาลดจำนวนซีพียูเสมือนลง</translation>
+ </message>
+ <message>
+ <source>The processor execution cap is set to a low value. This may make the machine feel slow to respond.</source>
+ <translation>การจำกัดการประมวลผลของหน่วยประมวลผลถูกกำหนดค่าไว้ต่ำซึ่งอาจส่งผลให้รู้สึกว่าเครื่องตอบสนองล่าช้า</translation>
+ </message>
+ <message>
+ <source>&Paravirtualization Interface:</source>
+ <translation>ส่วนเชื่อมต่อ&พาราเวอร์ชวลไลเซชัน:</translation>
+ </message>
+ <message>
+ <source>Selects the paravirtualization guest interface provider to be used by this virtual machine.</source>
+ <translation>เลือกผู้ให้บริการส่วนเชื่อมต่อพาราเวอร์ชวลไลเซชันของเกสต์ที่จะใช้กับเวอร์ชวลแมชชีนนี้</translation>
+ </message>
+ <message>
+ <source>The I/O APIC feature is not currently enabled in the Motherboard section of the System page. This is needed in order to support a chip set of type ICH9 you have enabled for this VM. It will be done automatically if you confirm your changes.</source>
+ <translation>คุณสมบัติ I/O APIC ไม่ได้เปิดใช้งานอยู่ในส่วนแผงวงจรหลักของหน้าระบบ คุณสมบัตินี้จำเป็นต่อการสนับสนุนการทำงานของชิป ICH9 ที่คุณเปิดใช้กับ VM นี้ ระบบจะเปิดใช้งานให้โดยอัตโนมัติหากคุณยืนยันการเปลี่ยนแปลงนี้</translation>
+ </message>
+ <message>
+ <source>USB controller emulation is not currently enabled on the USB page. This is needed to support an emulated USB input device you have enabled for this VM. It will be done automatically if you confirm your changes.</source>
+ <translation>การจำลองตัวควบคุม USB ไม่ได้ถูกเปิดใช้อยู่บนหน้า USB ตัวเลือกนี้จำเป็นต่อการสนับสนุนการจำลองอุปกรณ์รับข้อมูลเข้าแบบ USB ที่คุณเปิดใช้สำหรับ VM นี้ ระบบจะเปิดใช้งานให้โดยอัตโนมัติหากคุณยืนยันการเปลี่ยนแปลงนี้</translation>
+ </message>
+ <message>
+ <source>The I/O APIC feature is not currently enabled in the Motherboard section of the System page. This is needed in order to support more than one virtual processor you have chosen for this VM. It will be done automatically if you confirm your changes.</source>
+ <translation>คุณสมบัติ I/O APIC ไม่ได้เปิดใช้งานอยู่ในส่วนแผงวงจรหลักของหน้าระบบ คุณสมบัตินี้จำเป็นต่อการใช้งานมากกว่าหนึ่งหน่วยประมวลผลที่คุณเปิดใช้กับ VM นี้ ระบบจะเปิดใช้งานให้โดยอัตโนมัติหากคุณยืนยันการเปลี่ยนแปลงนี้</translation>
+ </message>
+ <message>
+ <source>Hardware virtualization is not currently enabled in the Acceleration section of the System page. This is needed in order to support more than one virtual processor you have chosen for this VM. It will be done automatically if you confirm your changes.</source>
+ <translation>เวอร์ชวลไลเซชันฮาร์ดแวร์ไม่ได้ถูกเปิดใช้อยู่ในส่วนตัวเร่งความเร็วของหน้าระบบ คุณสมบัตินี้จำเป็นต่อการรองรับการใช้งานมากกว่าหนึ่งหน่วยประมวลผลที่คุณเปิดใช้กับ VM นี้ ระบบจะเปิดใช้งานให้โดยอัตโนมัติหากคุณยืนยันการเปลี่ยนแปลงนี้</translation>
+ </message>
+ <message>
+ <source>When checked, the RTC device will report the time in UTC, otherwise in local (host) time. Unix usually expects the hardware clock to be set to UTC.</source>
+ <translation>หากเลือกไว้ อุปกรณ์ RTC จะรายงานเวลาเป็น UTC มิฉะนั้นจะรายงานเป็นเวลาท้องถิ่น (ของโฮสต์) ยูนิกซ์มักต้องการให้นาฬิกาฮาร์ดแวร์ตั้งเป็น UTC</translation>
+ </message>
+ <message>
+ <source>%</source>
+ <translation>%</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>%1 CPU</source>
+ <comment>%1 is 1 for now</comment>
+ <translation>%1 ซีพียู</translation>
+ </message>
+ <message>
+ <source>%1 CPUs</source>
+ <comment>%1 is host cpu count * 2 for now</comment>
+ <translation>%1 ซีพียู</translation>
+ </message>
+ <message>
+ <source>%1%</source>
+ <translation>%1%</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsUSB</name>
+ <message>
+ <source>New Filter %1</source>
+ <comment>usb</comment>
+ <translation>ฟิลเตอร์ %1 ใหม่</translation>
+ </message>
+ <message>
+ <source>When checked, enables the virtual USB controller of this machine.</source>
+ <translation>เลือกที่นี่เพื่อเปิดใช้ตัวควบคุม USB เสมือนของเครื่องนี้</translation>
+ </message>
+ <message>
+ <source>Enable &USB Controller</source>
+ <translation>เปิดใช้ตัวควบคุม &USB</translation>
+ </message>
+ <message>
+ <source>USB Device &Filters</source>
+ <translation>&ฟิลเตอร์อุปกรณ์ USB</translation>
+ </message>
+ <message>
+ <source>Lists all USB filters of this machine. The checkbox to the left defines whether the particular filter is enabled or not. Use the context menu or buttons to the right to add or remove USB filters.</source>
+ <translation>แสดงรายการฟิลเตอร์ USB ทั้งหมดของเครื่องนี้ กล่องเลือกทางด้านซ้ายกำหนดว่าฟิลเตอร์แต่ละตัวถูกเปิดใช้หรือไม่ และใช้เมนูหรือปุ่มทางด้านขวาเพื่อเพิ่มหรือนำฟิลเตอร์ USB ออก</translation>
+ </message>
+ <message>
+ <source>[filter]</source>
+ <translation>[ฟิลเตอร์]</translation>
+ </message>
+ <message>
+ <source><nobr>Vendor ID: %1</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>รหัสผู้ผลิต: %1</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Product ID: %2</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>รหัสผลิตภัณฑ์: %2</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Revision: %3</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>ครั้งที่แก้ไข: %3</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Product: %4</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>ผลิตภัณฑ์: %4</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Manufacturer: %5</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>ผู้ผลิต: %5</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Serial No.: %1</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>เลขลำดับ: %1</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Port: %1</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>พอร์ต: %1</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>State: %1</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>สถานะ: %1</nobr></translation>
+ </message>
+ <message>
+ <source>USB &1.1 (OHCI) Controller</source>
+ <translation>ตัวควบคุม USB &1.1 (OHCI)</translation>
+ </message>
+ <message>
+ <source>USB &2.0 (EHCI) Controller</source>
+ <translation>ตัวควบคุม USB &2.0 (EHCI)</translation>
+ </message>
+ <message>
+ <source>USB &3.0 (xHCI) Controller</source>
+ <translation>ตัวควบคุม USB &3.0 (xHCI)</translation>
+ </message>
+ <message>
+ <source>USB 2.0/3.0 is currently enabled for this virtual machine. However, this requires the <i>%1</i> to be installed. Please install the Extension Pack from the VirtualBox download site or disable USB 2.0/3.0 to be able to start the machine.</source>
+ <translation>USB 2.0/3.0 ถูกเปิดใช้อยู่สำหรับเวอร์ชวลแมชชีนนี้ แต่จำเป็นต้องมี <i>%1</i> ติดตั้งไว้ กรุณาติดตั้งแพคขยายจากไซต์ดาวน์โหลดเวอร์ชวลบอกซ์หรือปิดการใช้งาน USB 2.0/3.0 เพื่อให้เครื่องสามารถเริ่มการทำงานได้</translation>
+ </message>
+ <message>
+ <source>When chosen, enables the virtual USB OHCI controller of this machine. The USB OHCI controller provides USB 1.0 support.</source>
+ <translation>หากเลือกไว้ ระบบจะเปิดใช้ตัวควบคุม USB OHCI เสมือนของเครื่องนี้ ตัวควบคุม USB OHCI รองรับการทำงานของ USB 1.0</translation>
+ </message>
+ <message>
+ <source>When chosen, enables the virtual USB EHCI controller of this machine. The USB EHCI controller provides USB 2.0 support.</source>
+ <translation>หากเลือกไว้ ระบบจะเปิดใช้ตัวควบคุม USB EHCI เสมือนของเครื่องนี้ ตัวควบคุม USB EHCI รองรับการทำงานของ USB 2.0</translation>
+ </message>
+ <message>
+ <source>When chosen, enables the virtual USB xHCI controller of this machine. The USB xHCI controller provides USB 3.0 support.</source>
+ <translation>หากเลือกไว้ ระบบจะเปิดใช้ตัวควบคุม USB xHCI เสมือนของเครื่องนี้ ตัวควบคุม USB xHCI รองรับการทำงานของ USB 3.0</translation>
+ </message>
+ <message>
+ <source>Add Empty Filter</source>
+ <translation>เพิ่มฟิลเตอร์ว่าง</translation>
+ </message>
+ <message>
+ <source>Add Filter From Device</source>
+ <translation>เพิ่มฟิลเตอร์จากอุปกรณ์</translation>
+ </message>
+ <message>
+ <source>Edit Filter</source>
+ <translation>แก้ไขฟิลเตอร์</translation>
+ </message>
+ <message>
+ <source>Remove Filter</source>
+ <translation>นำฟิลเตอร์ออก</translation>
+ </message>
+ <message>
+ <source>Move Filter Up</source>
+ <translation>เลื่อนฟิลเตอร์ขึ้น</translation>
+ </message>
+ <message>
+ <source>Move Filter Down</source>
+ <translation>เลื่อนฟิลเตอร์ลง</translation>
+ </message>
+ <message>
+ <source>Adds new USB filter with all fields initially set to empty strings. Note that such a filter will match any attached USB device.</source>
+ <translation>เพิ่มฟิลเตอร์ USB ใหม่โดยมีทุกฟิลด์เป็นค่าว่าง โปรดทราบว่าฟิลเตอร์นี้จะแมทช์กับอุปกรณ์ USB ใด ๆ ที่เชื่อมต่ออยู่</translation>
+ </message>
+ <message>
+ <source>Adds new USB filter with all fields set to the values of the selected USB device attached to the host PC.</source>
+ <translation>เพิ่มฟิลเตอร์ USB ใหม่โดยใช้ค่าจากอุปกรณ์ USB ที่เชื่อมต่ออยู่กับโฮสต์พีซีที่เลือกไว้</translation>
+ </message>
+ <message>
+ <source>Edits selected USB filter.</source>
+ <translation>แก้ไขฟิลเตอร์ USB ที่เลือก</translation>
+ </message>
+ <message>
+ <source>Removes selected USB filter.</source>
+ <translation>นำฟิลเตอร์ USB ที่เลือกออก</translation>
+ </message>
+ <message>
+ <source>Moves selected USB filter up.</source>
+ <translation>เลื่อนลำดับฟิลเตอร์ USB ที่เลือกขึ้น</translation>
+ </message>
+ <message>
+ <source>Moves selected USB filter down.</source>
+ <translation>เลื่อนลำดับฟิลเตอร์ USB ที่เลือกลง</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineSettingsUSBFilterDetails</name>
+ <message>
+ <source>Any</source>
+ <comment>remote</comment>
+ <translation>ใด ๆ</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <comment>remote</comment>
+ <translation>ใช่</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <comment>remote</comment>
+ <translation>ไม่ใช่</translation>
+ </message>
+ <message>
+ <source>&Name:</source>
+ <translation>&ชื่อ:</translation>
+ </message>
+ <message>
+ <source>Holds the filter name.</source>
+ <translation>เก็บชื่อฟิลเตอร์</translation>
+ </message>
+ <message>
+ <source>&Vendor ID:</source>
+ <translation>&ID ผู้ผลิต:</translation>
+ </message>
+ <message>
+ <source>&Product ID:</source>
+ <translation>ID ผ&ลิตภัณฑ์:</translation>
+ </message>
+ <message>
+ <source>&Revision:</source>
+ <translation>&รุ่น:</translation>
+ </message>
+ <message>
+ <source>&Manufacturer:</source>
+ <translation>ผู้&ผลิต:</translation>
+ </message>
+ <message>
+ <source>Pro&duct:</source>
+ <translation>ผลิต&ภัณฑ์:</translation>
+ </message>
+ <message>
+ <source>&Serial No.:</source>
+ <translation>&ลำดับที่ผลิต:</translation>
+ </message>
+ <message>
+ <source>Por&t:</source>
+ <translation>&พอร์ต:</translation>
+ </message>
+ <message>
+ <source>R&emote:</source>
+ <translation>&ระยะไกล:</translation>
+ </message>
+ <message>
+ <source>USB Filter Details</source>
+ <translation>รายละเอียดฟิลเตอร์ USB</translation>
+ </message>
+ <message>
+ <source>Holds the vendor ID filter. The <i>exact match</i> string format is <tt>XXXX</tt> where <tt>X</tt> is a hexadecimal digit. An empty string will match any value.</source>
+ <translation>เก็บตัวกรอง ID ผู้ผลิต รูปแบบสตริงที่<i>จับคู่โดยตรง</i>คือ <tt>XXXX</tt> โดย <tt>X</tt> คือตัวเลขฐานสิบหกหนึ่งตัว ในที่นี้ สตริงว่างจะจับคู่ได้กับทุกค่า</translation>
+ </message>
+ <message>
+ <source>Holds the product ID filter. The <i>exact match</i> string format is <tt>XXXX</tt> where <tt>X</tt> is a hexadecimal digit. An empty string will match any value.</source>
+ <translation>เก็บตัวกรอง ID ผลิตภัณฑ์ รูปแบบสตริงที่<i>จับคู่โดยตรง</i>คือ <tt>XXXX</tt> โดย <tt>X</tt> คือตัวเลขฐานสิบหกหนึ่งตัว ในที่นี้ สตริงว่างจะจับคู่ได้กับทุกค่า</translation>
+ </message>
+ <message>
+ <source>Holds the revision number filter. The <i>exact match</i> string format is <tt>IIFF</tt> where <tt>I</tt> is a decimal digit of the integer part and <tt>F</tt> is a decimal digit of the fractional part. An empty string will match any value.</source>
+ <translation>เก็บตัวกรองหมายเลขรุ่น รูปแบบสตริงที่<i>จับคู่โดยตรง</i>คือ <tt>IIFF</tt> โดย <tt>I</tt> คือตัวเลขฐานสิบหนึ่งตัวในภาคจำนวนเต็ม และ <tt>F</tt>เป็นตัวเลขฐานสิบหนึ่งตัวในภาคเศษส่วน ในที่นี้ สตริงว่างจะจับคู่ได้กับทุกค่า</translation>
+ </message>
+ <message>
+ <source>Holds the manufacturer filter as an <i>exact match</i> string. An empty string will match any value.</source>
+ <translation>เก็บตัวกรองผู้ผลิต เป็นสตริงที่<i>จับคู่โดยตรง</i> ในที่นี้ สตริงว่างจะจับคู่ได้กับทุกค่า</translation>
+ </message>
+ <message>
+ <source>Holds the product name filter as an <i>exact match</i> string. An empty string will match any value.</source>
+ <translation>เก็บตัวกรองชื่อผลิตภัณฑ์ เป็นสตริงที่<i>จับคู่โดยตรง</i> ในที่นี้ สตริงว่างจะจับคู่ได้กับทุกค่า</translation>
+ </message>
+ <message>
+ <source>Holds the serial number filter as an <i>exact match</i> string. An empty string will match any value.</source>
+ <translation>เก็บตัวกรองหมายเลขลำดับที่ผลิต เป็นสตริงที่<i>จับคู่โดยตรง</i> ในที่นี้ สตริงว่างจะจับคู่ได้กับทุกค่า</translation>
+ </message>
+ <message>
+ <source>Holds the host USB port filter as an <i>exact match</i> string. An empty string will match any value.</source>
+ <translation>เก็บตัวกรองพอร์ต USB ของโฮสต์ เป็นสตริงที่<i>จับคู่โดยตรง</i> ในที่นี้ สตริงว่างจะจับคู่ได้กับทุกค่า</translation>
+ </message>
+ <message>
+ <source>Holds whether this filter applies to USB devices attached locally to the host computer (<i>No</i>), to a VRDP client's computer (<i>Yes</i>), or both (<i>Any</i>).</source>
+ <translation>เก็บค่าว่าฟิลเตอร์นี้จะถูกใช้กับอุปกรณ์ USB ที่เชื่อมต่ออยู่กับโฮสต์โดยตรง (<i>ไม่ใช่</i>) หรือเชื่อมต่อไปยังไคลเอนต์ VRDP (<i>ใช่</i> หรือทั้งคู่ (<i>Any</i>)</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineWindow</name>
+ <message>
+ <source> EXPERIMENTAL build %1r%2 - %3</source>
+ <translation>บิลต์ทดลอง %1r%2 - %3</translation>
+ </message>
+</context>
+<context>
+ <name>UIMachineWindowNormal</name>
+ <message>
+ <source>Shows the currently assigned Host key.<br>This key, when pressed alone, toggles the keyboard and mouse capture state. It can also be used in combination with other keys to quickly perform actions from the main menu.</source>
+ <translation>แสดงโฮสต์คีย์ทีกำหนดไว้ <br> การกดปุ่มนี้เป็นการสลับสถานะการจับแป้นพิมพ์และเมาส์ของเกสต์ นอกจากนี้ยังสามารถใช้ร่วมกับปุ่มอื่น ๆ เป็นทางลัดสำหรับการกระทำต่าง ๆ ในเมนูหลักได้</translation>
+ </message>
+</context>
+<context>
+ <name>UIMediumManager</name>
+ <message>
+ <source>&Optical disks</source>
+ <translation>&ออปติคัลดิสก์</translation>
+ </message>
+ <message>
+ <source>&Floppy disks</source>
+ <translation>&ฟลอปปี้ดิสก์</translation>
+ </message>
+ <message>
+ <source>Removing medium...</source>
+ <translation>กำลังนำสื่อบันทึกออก...</translation>
+ </message>
+ <message>
+ <source>&Hard disks</source>
+ <translation>&ฮาร์ดดิสก์:</translation>
+ </message>
+</context>
+<context>
+ <name>UIMediumTypeChangeDialog</name>
+ <message>
+ <source>Modify medium attributes</source>
+ <translation>เปลี่ยนลักษณะเฉพาะของมีเดีย</translation>
+ </message>
+ <message>
+ <source><p>You are about to change the settings of the disk image file <b>%1</b>.</p><p>Please choose one of the following modes and press <b>%2</b> to proceed or <b>%3</b> otherwise.</p></source>
+ <translation><p>คุณกำลังจะเปลี่ยนแปลงการตั้งค่าไฟล์ดิสก์อิมเมจ <b>%1</b></p><p>โปรดเลือกหนึ่งในโหมดต่อไปนี้แล้วกด <b>%2</b> เพื่อดำเนินการต่อหรือกด <b>%3</b> เพื่อยกเลิก</p></translation>
+ </message>
+ <message>
+ <source>Choose mode:</source>
+ <translation>เลือกโหมด:</translation>
+ </message>
+ <message>
+ <source>This type of medium is attached directly or indirectly, preserved when taking snapshots.</source>
+ <translation>สื่อชนิดนี้เชื่อมต่อได้โดยตรงหรือโดยอ้อม และจะถูกเก็บไว้ขณะเก็บสแนปช็อต</translation>
+ </message>
+ <message>
+ <source>This type of medium is attached indirectly, changes are wiped out the next time the virtual machine is started.</source>
+ <translation>สื่อชนิดนี้ถูกเชื่อมต่อโดยอ้อม ความเปลี่ยนแปลงทั้งหมดจะถูกละทิ้งเมื่อเวอร์ชวลแมชชีนเริ่มการทำงานในครั้งต่อไป</translation>
+ </message>
+ <message>
+ <source>This type of medium is attached directly, ignored when taking snapshots.</source>
+ <translation>สื่อชนิดนี้ถูกเชื่อมต่อโดยตรง และจะถูกเพิกเฉยขณะเก็บสแนปช็อต</translation>
+ </message>
+ <message>
+ <source>This type of medium is attached directly, allowed to be used concurrently by several machines.</source>
+ <translation>สื่อชนิดนี้ถูกเชื่อมต่อโดยตรง และสามารถถูกใช้จากเวอร์ชวลแมชชีนหลายเครื่องได้พร้อมกัน</translation>
+ </message>
+ <message>
+ <source>This type of medium is attached directly, and can be used by several machines.</source>
+ <translation>สื่อชนิดนี้ถูกเชื่อมต่อโดยตรง และสามารถถูกใช้จากเวอร์ชวลแมชชีนได้หลายเครื่อง</translation>
+ </message>
+ <message>
+ <source>This type of medium is attached indirectly, so that one base medium can be used for several VMs which have their own differencing medium to store their modifications.</source>
+ <translation>สื่อชนิดนี้ถูกเชื่อมต่อโดยอ้อม ดังนั้นสื่อพื้นฐานหนึ่ง ๆ สามารถถูกใช้กับหลาย ๆ VM ที่มีสื่อแบบเก็บส่วนต่างของตัวเองเพื่อเก็บข้อมูลในส่วนที่เกิดการเปลี่ยนแปลง</translation>
+ </message>
+</context>
+<context>
+ <name>UIMenuBarEditorWidget</name>
+ <message>
+ <source>Virtual Screen Resize</source>
+ <translation>ปรับขนาดจอภาพเสมือน</translation>
+ </message>
+ <message>
+ <source>Virtual Screen Mapping</source>
+ <translation>จับคู่จอภาพเสมือน</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Switch</source>
+ <translation>สลับ</translation>
+ </message>
+ <message>
+ <source>Enable Menu Bar</source>
+ <translation>เปิดใช้แถบเมนู</translation>
+ </message>
+</context>
+<context>
+ <name>UIMessageCenter</name>
+ <message>
+ <source>VirtualBox - Information</source>
+ <comment>msg box title</comment>
+ <translation>เวอร์ชวลบอกซ์ - ข้อมูลข่าวสาร</translation>
+ </message>
+ <message>
+ <source>VirtualBox - Question</source>
+ <comment>msg box title</comment>
+ <translation>เวอร์ชวลบอกซ์ - คำถาม</translation>
+ </message>
+ <message>
+ <source>VirtualBox - Warning</source>
+ <comment>msg box title</comment>
+ <translation>เวอร์ชวลบอกซ์ - คำเตือน</translation>
+ </message>
+ <message>
+ <source>VirtualBox - Error</source>
+ <comment>msg box title</comment>
+ <translation>เวอร์ชวลบอกซ์ - ข้อผิดพลาด</translation>
+ </message>
+ <message>
+ <source>VirtualBox - Critical Error</source>
+ <comment>msg box title</comment>
+ <translation>เวอร์ชวลบอกซ์ - ข้อผิดพลาดร้ายแรง</translation>
+ </message>
+ <message>
+ <source>Do not show this message again</source>
+ <comment>msg box flag</comment>
+ <translation>ไม่ต้องแสดงข้อความนี้อีก</translation>
+ </message>
+ <message>
+ <source>Failed to open <tt>%1</tt>. Make sure your desktop environment can properly handle URLs of this type.</source>
+ <translation>ไม่สามารถเปิด <tt>%1</tt> ได้ โปรดตรวจสอบว่าสภาพแวดล้อมเดสก์ทอปของคุณรองรับ URL ชนิดนี้</translation>
+ </message>
+ <message>
+ <source><p>Failed to initialize COM or to find the VirtualBox COM server. Most likely, the VirtualBox server is not running or failed to start.</p><p>The application will now terminate.</p></source>
+ <translation><p>ไม่สามารถเริ่มการทำงานของ COM หรือไม่พบเซอร์ฟเวอร์ COM ของเวอร์ชวลบอกซ์ เป็นไปได้อย่างยิ่งว่าเซอร์ฟเวอร์เวอร์ชวลบอกซ์ไม่ได้ทำงานอยู่หรือไม่สามารถเริ่มการทำงานได้</p><p>แอพพลิเคชันจะยุติการทำงานทันที</p></translation>
+ </message>
+ <message>
+ <source>Failed to set global VirtualBox properties.</source>
+ <translation>ไม่สามารถกำหนดคุณสมบัติกลางของเวอร์ชวลบอกซ์ได้</translation>
+ </message>
+ <message>
+ <source>Failed to access the USB subsystem.</source>
+ <translation>ไม่สามารถเข้าถึงระบบย่อย USB ได้</translation>
+ </message>
+ <message>
+ <source>Failed to create a new virtual machine.</source>
+ <translation>ไม่สามารถสร้างเวอร์ชวลแมชชีนใหม่ได้</translation>
+ </message>
+ <message>
+ <source>Failed to start the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถเริ่มการทำงานของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to pause the execution of the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถหยุดเวอร์ชวลแมชชีน <b>%1</b> ชั่วคราวได้</translation>
+ </message>
+ <message>
+ <source>Failed to resume the execution of the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถทำให้เวอร์ชวลแมชชีน <b>%1</b> ทำงานต่อได้</translation>
+ </message>
+ <message>
+ <source>Failed to save the state of the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถบันทึกสถานะของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to create a snapshot of the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถสร้างสแนปช็อตของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to stop the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถหยุดการทำงานของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to remove the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถลบเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to discard the saved state of the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถทิ้งสถานะที่บันทึกไว้ของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>There is no virtual machine named <b>%1</b>.</source>
+ <translation>ไม่มีเวอร์ชวลแมชชีนชื่อ <b>%1</b></translation>
+ </message>
+ <message>
+ <source>Failed to create a new session.</source>
+ <translation>ไม่สามารถสร้างเซสชันใหม่ได้</translation>
+ </message>
+ <message>
+ <source>Failed to open a session for the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถเปิดเซสชันสำหรับเวอร์ชวลแมชชีน <b>%1</b></translation>
+ </message>
+ <message>
+ <source>Failed to remove the host network interface <b>%1</b>.</source>
+ <translation>ไม่สามารถนำส่วนเชื่อมต่อเครือข่าย <b>%1</b> ของโฮสต์ออกได้</translation>
+ </message>
+ <message>
+ <source>Failed to attach the USB device <b>%1</b> to the virtual machine <b>%2</b>.</source>
+ <translation>ไม่สามารถเชื่อมต่ออุปกรณ์ USB <b>%1</b> เข้ากับเวอร์ชวลแมชชีน <b>%2</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to detach the USB device <b>%1</b> from the virtual machine <b>%2</b>.</source>
+ <translation>ไม่สามารถถอดอุปกรณ์ USB <b>%1</b> ออกจากเวอร์ชวลแมชชีน <b>%2</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to create the shared folder <b>%1</b> (pointing to <nobr><b>%2</b></nobr>) for the virtual machine <b>%3</b>.</source>
+ <translation>ไม่สามารถสร้างโฟลเดอร์ที่ใช้ร่วมกัน <b>%1</b> (ชี้ไปยัง <nobr><b>%2</b></nobr>) สำหรับเวอร์ชวลแมชชีน <b>%3</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>The Virtual Machine reports that the guest OS does not support <b>mouse pointer integration</b> in the current video mode. You need to capture the mouse (by clicking over the VM display or pressing the host key) in order to use the mouse inside the guest OS.</p></source>
+ <translation><p>เวอร์ชวลแมชชีนรายงานว่าโอเอสของเกสต์ไม่รองรับ<b>การใช้เมาส์ร่วมกับโฮสต์</b>ในโหมดแสดงผลปัจจุบัน คุณต้องจับเมาส์ (โดยคลิกเข้าไปในหน้าจอของ VM หรือกดปุ่มโฮสต์) เพื่อใช้เมาส์ในโอเอสของเกสต์</p></translation>
+ </message>
+ <message>
+ <source><p>The Virtual Machine is currently in the <b>Paused</b> state and not able to see any keyboard or mouse input. If you want to continue to work inside the VM, you need to resume it by selecting the corresponding action from the menu bar.</p></source>
+ <translation><p>เวอร์ชวลแมชชีนอยู่ในสถานะ<b>หยุดชั่วคราว</b>และไม่สามารถมองเห็นการป้อนข้อมูลทั้งเมาส์หรือคีย์บอร์ด หากคุณต้องการทำงานภายใน VM คุณต้องให้เวอร์ชวลแมชชีนกลับมาทำงานต่อโดยเลือกคำสั่งจากแถบเมนู</p></translation>
+ </message>
+ <message>
+ <source><nobr>Fatal Error</nobr></source>
+ <comment>runtime error info</comment>
+ <translation><nobr>ความผิดพลาดร้ายแรง</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Non-Fatal Error</nobr></source>
+ <comment>runtime error info</comment>
+ <translation><nobr>ความผิดพลาดไม่ร้ายแรง</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Warning</nobr></source>
+ <comment>runtime error info</comment>
+ <translation><nobr>คำเตือน</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Error ID: </nobr></source>
+ <comment>runtime error info</comment>
+ <translation>รหัสความผิดพลาด:</translation>
+ </message>
+ <message>
+ <source>Severity: </source>
+ <comment>runtime error info</comment>
+ <translation>ระดับความร้ายแรง:</translation>
+ </message>
+ <message>
+ <source><p>A fatal error has occurred during virtual machine execution! The virtual machine will be powered off. Please copy the following error message using the clipboard to help diagnose the problem:</p></source>
+ <translation><p>เกิดความผิดพลาดร้ายแรงขณะเวอร์ชวลแมชชีนกำลังทำงาน! เวอร์ชวลแมชชีนจะปิดตัวลง โปรดคัดลอกข้อความแสดงความผิดพลาดโดยใช้คลิปบอร์ดเพื่อใช้ในการวินิจฉัยปัญหา</p></translation>
+ </message>
+ <message>
+ <source><p>An error has occurred during virtual machine execution! The error details are shown below. You may try to correct the error and resume the virtual machine execution.</p></source>
+ <translation><p>เกิดความผิดพลาดขณะเวอร์ชวลแมชชีนกำลังทำงาน! รายละเอียดความผิดพลาดถูกแสดงไว้ด้านล่าง คุณอาจแก้ไขความผิดพลาดดังกล่าวและลองให้เวอร์ชวลแมชชีนทำงานต่ออีกครั้ง</p></translation>
+ </message>
+ <message>
+ <source><p>The virtual machine execution may run into an error condition as described below. We suggest that you take an appropriate action to avert the error.</p></source>
+ <translation><p>การทำงานของเวอร์ชวลแมชชีนอาจพบข้อผิดพลาดดังที่อธิบายไว้ด้านล่าง เราขอแนะนำให้คุณดำเนินการแก้ไขตามความเหมาะสมเพื่อเลี่ยงข้อผิดพลาดดังกล่าว</p></translation>
+ </message>
+ <message>
+ <source>Result Code: </source>
+ <comment>error info</comment>
+ <translation>รหัสการทำงาน:</translation>
+ </message>
+ <message>
+ <source>Component: </source>
+ <comment>error info</comment>
+ <translation>ส่วนประกอบ:</translation>
+ </message>
+ <message>
+ <source>Interface: </source>
+ <comment>error info</comment>
+ <translation>แผงวงจร:</translation>
+ </message>
+ <message>
+ <source>Callee: </source>
+ <comment>error info</comment>
+ <translation>ฟังก์ชันที่ถูกเรียก: </translation>
+ </message>
+ <message>
+ <source>Callee RC: </source>
+ <comment>error info</comment>
+ <translation>RC ฟังก์ชันที่ถูกเรียก: </translation>
+ </message>
+ <message>
+ <source><p>Failed to remove the shared folder <b>%1</b> (pointing to <nobr><b>%2</b></nobr>) from the virtual machine <b>%3</b>.</p><p>Please close all programs in the guest OS that may be using this shared folder and try again.</p></source>
+ <translation><p>ไม่สามารถนำโฟลเดอร์ที่ใช้ร่วมกัน <b>%1</b> (ชี้ไปที่ <nobr><b>%2</b></nobr>) ออกจากเวอร์ชวลแมชชีน <b>%3</b> ได้</p><p>โปรดปิดโปรแกรมทั้งหใดในโอเอสของเกสต์ที่อาจใช้โฟลเดอร์ที่ใช้ร่วมกันดังกล่าวก่อนลองอีกครั้ง</p></translation>
+ </message>
+ <message>
+ <source>Failed to open the license file <nobr><b>%1</b></nobr>. Check file permissions.</source>
+ <translation>ไม่สามารถเปิดไฟล์ไลเซนส์ <nobr><b>%1</b></nobr> โปรดตรวจสอบสิทธิการเข้าถึงไฟล์</translation>
+ </message>
+ <message>
+ <source>Failed to send the ACPI Power Button press event to the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถส่งเหตุการณ์กดปุ่มเพาเวอร์ ACPI ไปยังเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>Failed to load the global GUI configuration from <b><nobr>%1</nobr></b>.</p><p>The application will now terminate.</p></source>
+ <translation><p>ไม่สามารถโหลดการตั้งค่า GUI กลางจาก <b><nobr>%1</nobr></b> ได้</p><p>แอพพลิเคชันจะยุติการทำงานทันที</p></translation>
+ </message>
+ <message>
+ <source><p>Failed to save the global GUI configuration to <b><nobr>%1</nobr></b>.</p><p>The application will now terminate.</p></source>
+ <translation><p>ไม่สามารถบันทึกการตั้งค่า GUI กลางไปยัง <b><nobr>%1</nobr></b> ได้</p><p>แอพพลิเคชันจะยุติการทำงานทันที</p></translation>
+ </message>
+ <message>
+ <source>Failed to save the settings of the virtual machine <b>%1</b> to <b><nobr>%2</nobr></b>.</source>
+ <translation>ไม่สามารถบันทึกการตั้งค่าของเวอร์ชวลแมชชีน <b>%1</b> ไปยัง <b><nobr>%2</nobr></b> ได้</translation>
+ </message>
+ <message>
+ <source>Discard</source>
+ <comment>saved state</comment>
+ <translation>ทิ้ง</translation>
+ </message>
+ <message>
+ <source><p>The host key is currently defined as <b>%1</b>.</p></source>
+ <comment>additional message box paragraph</comment>
+ <translation><p>ขณะนี้ปุ่มโฮสต์ถูกกำหนดไว้เป็น <b>%1</b></p></translation>
+ </message>
+ <message>
+ <source>Capture</source>
+ <comment>do input capture</comment>
+ <translation>จับ</translation>
+ </message>
+ <message>
+ <source>Check</source>
+ <comment>inaccessible media message box</comment>
+ <translation>ตรวจสอบ</translation>
+ </message>
+ <message>
+ <source>Reset</source>
+ <comment>machine</comment>
+ <translation>รีเซ็ต</translation>
+ </message>
+ <message>
+ <source>Continue</source>
+ <comment>no hard disk attached</comment>
+ <translation>ทำต่อไป</translation>
+ </message>
+ <message>
+ <source>Go Back</source>
+ <comment>no hard disk attached</comment>
+ <translation>ย้อนกลับ</translation>
+ </message>
+ <message>
+ <source><p>Could not enter seamless mode due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p></source>
+ <translation><p>ไม่สามารถเข้าสู่โหมดไร้ขอบได้เนื่องจากเกสต์มีหน่วยความจำวิดีโอไม่เพียงพอ</p><p>คุณควรกำหนดให้เวอร์ชวลแมชชีนมีหน่วยความจำวิดีโอไม่น้อยกว่า <b>%1</b></p></translation>
+ </message>
+ <message>
+ <source>You are already running the most recent version of VirtualBox.</source>
+ <translation>คุณกำลังใช้งานเวอร์ชวลบอกซ์รุ่นล่าสุด</translation>
+ </message>
+ <message>
+ <source><p>You have <b>clicked the mouse</b> inside the Virtual Machine display or pressed the <b>host key</b>. This will cause the Virtual Machine to <b>capture</b> the host mouse pointer (only if the mouse pointer integration is not currently supported by the guest OS) and the keyboard, which will make them unavailable to other applications running on your host machine.</p><p>You can press the <b>host key</b> at [...]
+ <translation><p>คุณได้<b>คลิกเมาส์</b>ในหน้าจอเวอร์ชวลแมชชีนหรือกด<b>ปุ่มโฮสต์</b> ซึ่งจะทำให้เวอร์ชวลแมชชีน<b>จับ</b>เมาส์พอยเตอร์ (เฉพาะในกรณีที่โอเอสของเกสต์ไม่รองรับการใช้เมาส์ร่วมกับโฮสต์) และแป้นพิมพ์ของโฮสต์ ซึ่งจะทำให้ทำให้ไม่สามารถเข้าถึงได้โดยแอพพลิเคชันอื่นบนโฮสต์</p><p>คุณสามารถกด<b>ปุ่มโฮสต์</b>ได้ทุกเมื่อเพื่อ<b>ปล่อย</b>แป้นพิมพ์และเมาส์ (หากถูกจับไว้) และกลับสู่การทำงานปกติ ปุ่มโฮสต์ที่ถ [...]
+ </message>
+ <message>
+ <source><p>You have the <b>Auto capture keyboard</b> option turned on. This will cause the Virtual Machine to automatically <b>capture</b> the keyboard every time the VM window is activated and make it unavailable to other applications running on your host machine: when the keyboard is captured, all keystrokes (including system ones like Alt-Tab) will be directed to the VM.</p><p>You can press the <b>host key</b> at any time t [...]
+ <translation><p>คุณเปิดใช้ตัวเลือก <b>จับแป้นพิมพ์อัตโนมัติ</b> ซึ่งจะทำให้เวอร์ชวลแมชชีน<b>จับ</b>แป้นพิมพ์ทุกครั้งที่หน้าต่างของเวอร์ชวลแมชชีนถูกเรียกใช้ และทำให้แอพพลิเคชันอื่น ๆ ที่ทำงานอยู่บนโฮสต์ของคุณไม่สามารถใช้แป้นพิมพ์ได้ เมื่อแป้นพิมพ์ถูกจับไว้ การกดปุ่มทั้งหมด (รวมถึงปุ่มของระบบ เช่น Alt-Tab) จะถูกส่งให้เวอร์ชวลแมชชีน </p><p>คุณสามารถกด <b>ปุ่มโฮสต์</b> ได้ทุกเมื่อเพื่อ<b>ปล่อย</b>แป้นพิมพ์และเมาส์ (หาก [...]
+ </message>
+ <message>
+ <source><p>The Virtual Machine reports that the guest OS supports <b>mouse pointer integration</b>. This means that you do not need to <i>capture</i> the mouse pointer to be able to use it in your guest OS -- all mouse actions you perform when the mouse pointer is over the Virtual Machine's display are directly sent to the guest OS. If the mouse is currently captured, it will be automatically uncaptured.</p><p>The mouse icon on the s [...]
+ <translation><p>เวอร์ชวลแมชชีนรายงานว่าโอเอสของเกสต์รองรับ<b>การใช้เมาส์ร่วมกับโฮสต์</b> นั่นแสดงว่าคุณไม่ต้อง<i>จับ</i>เมาส์พอยเตอร์เพื่อใช้ในเกสต์โอเอสของคุณ -- กิจกรรมเกี่ยวกับเมาส์ทั้งหมดที่คุณกระทำขณะที่เมาส์พอยเตอร์อยู่เหนือหน้าจอเวอร์ชวลแมชชีนจะถูกส่งให้โอเอสของเกสต์โดยตรง หากขณะนี้เมาส์ถูกจับไว้มันจะถูกปล่อยโดยอัตโนมัติ</p><p>ไอคอนเมาส์บนแถบสถานะจะแสดงเป็น <img src=:/mouse_seamless_16px.png/> เพื่อแสดงว่าเก [...]
+ </message>
+ <message>
+ <source>Release</source>
+ <comment>detach medium</comment>
+ <translation>ปล่อย</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <comment>medium</comment>
+ <translation>นำออก</translation>
+ </message>
+ <message>
+ <source><p>The hard disk storage unit at location <b>%1</b> already exists. You cannot create a new virtual hard disk that uses this location because it can be already used by another virtual hard disk.</p><p>Please specify a different location.</p></source>
+ <translation><p>หน่วยเก็บข้อมูลฮาร์ดดิสก์ที่ <b>%1</b> มีอยู่แล้ว คุณไม่สามารถสร้างฮาร์ดดิสก์เสมือนที่ใช้ที่ตั้งเดียวกันนี้ได้ เนื่องจากมันอาจถูกใช้อยู่แล้วโดยฮาร์ดดิสก์เสมือนอื่น</p><p>กรุณาระบุที่ตั้งที่แตกต่างออกไป</p></translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <comment>hard disk storage</comment>
+ <translation>ลบ</translation>
+ </message>
+ <message>
+ <source>Keep</source>
+ <comment>hard disk storage</comment>
+ <translation>เก็บไว้</translation>
+ </message>
+ <message>
+ <source>Failed to delete the storage unit of the hard disk <b>%1</b>.</source>
+ <translation>ไม่สามารถลบหน่วยเก็บข้อมูลของฮาร์ดดิสก์ <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to create the hard disk storage <nobr><b>%1</b>.</nobr></source>
+ <translation>ไม่สามารถสร้างหน่วยเก็บข้อมูลฮาร์ดดิสก์ <nobr><b>%1</b></nobr> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to access the disk image file <nobr><b>%1</b></nobr>.</source>
+ <translation>ไม่สามารถเข้าถึงไฟล์ดิสก์อิมเมจ <nobr><b>%1</b></nobr></translation>
+ </message>
+ <message>
+ <source>The following files already exist:<br /><br />%1<br /><br />Are you sure you want to replace them? Replacing them will overwrite their contents.</source>
+ <translation>ไฟล์ต่อไปนี้มีอยู่แล้ว: <br /><br />%1<br /><br />แน่ใจหรือไม่ว่าต้องการแทนที่ การแทนที่ไฟล์เหล่านี้จะทำให้ข้อมูลในไฟล์ถูกเขียนทับ</translation>
+ </message>
+ <message>
+ <source>You are running a prerelease version of VirtualBox. This version is not suitable for production use.</source>
+ <translation>คุณกำลังใช้เวอร์ชวลบอกซ์รุ่นก่อนเผยแพร่ รุ่นนี้ไม่เหมาะสำหรับการใช้งานจริง</translation>
+ </message>
+ <message>
+ <source>You are trying to shut down the guest with the ACPI power button. This is currently not possible because the guest does not support software shutdown.</source>
+ <translation>คุณกำลังพยายามปิดเครื่องเกสต์ด้วยปุ่มเพาเวอร์ ACPI ซึ่งไม่สามารถดำเนินการได้เพราะเกสต์ไม่รองรับการปิดเครื่องด้วยซอฟต์แวร์</translation>
+ </message>
+ <message>
+ <source><p>VT-x/AMD-V hardware acceleration has been enabled, but is not operational. Your 64-bit guest will fail to detect a 64-bit CPU and will not be able to boot.</p><p>Please ensure that you have enabled VT-x/AMD-V properly in the BIOS of your host computer.</p></source>
+ <translation><p>ตัวเร่งความเร็วฮาร์ดแวร์ VT-x/AMD-V ถูกเปิดใช้งานแต่ไม่สามารถทำงานได้ เกสต์ 64 บิตของคุณจะไม่สามารถตรวจพบซีพียู 64 บิตและจะไม่สามารถบูตได้</p><p>โปรดตรวจสอบว่าคุณได้เปิดใช้ VT-x/AMD-V ใน BIOS ของเครื่องโฮสต์ไว้อย่างถูกต้อง</p></translation>
+ </message>
+ <message>
+ <source>Close VM</source>
+ <translation>ปิด VM</translation>
+ </message>
+ <message>
+ <source>Continue</source>
+ <translation>ทำต่อไป</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+ <message>
+ <source>Failed to open/interpret appliance <b>%1</b>.</source>
+ <translation>ไม่สามารถเปิด/แปล เครื่องใช้ <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to import appliance <b>%1</b>.</source>
+ <translation>ไม่สามารถนำเข้าเครื่องใช้ <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to prepare the export of the appliance <b>%1</b>.</source>
+ <translation>ไม่สามารถเตรียมการส่งออกแอพพลายแอนซ์ <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to export appliance <b>%1</b>.</source>
+ <translation>ไม่สามารถส่งออกแอพพลายแอนซ์ <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>Deleting this host-only network will remove the host-only interface this network is based on. Do you want to remove the (host-only network) interface <nobr><b>%1</b>?</nobr></p><p><b>Note:</b> this interface may be in use by one or more virtual network adapters belonging to one of your VMs. After it is removed, these adapters will no longer be usable until you correct their settings by either choosing a different in [...]
+ <translation><p>การลบเครือข่ายเฉพาะโฮสต์จะนำแผงวงจรเครือข่ายเฉพาะโฮสต์ที่ใช้สำหรับเครือข่ายนี้ออกด้วย คุณต้องการถอนแผงวงจร (เครือข่ายเฉพาะโฮสต์) <nobr><b>%1</b> นี้หรือไม่?</nobr></p><p><b>หมายเหตุ:</b> แผงวงจรนี้อาจถูกใช้อยู่โดยแผงวงจรเครือข่ายเสมือนของ VM เครื่องใดเครื่องหนึ่งของคุณ หลังจากแผงวงจรนี้ถูกนำออกไปแล้วแผงวงจรเครือข่ายดังกล่าวจะไม่สามารถใช้งานได้จนกว่าคุณจะแก้ไขการตั้งค่าโดยการเลือกแผงวงจรอื่นหรือเปลี่ยนไปใช้การเช [...]
+ </message>
+ <message>
+ <source>A file named <b>%1</b> already exists. Are you sure you want to replace it?<br /><br />Replacing it will overwrite its contents.</source>
+ <translation>ไฟล์ชื่อ <b>%1</b> มีอยู่แล้ว คุณแน่ใจหรือไม่ว่าต้องการแทนที่ไฟล์?<br /><br />การแทนที่จะเขียนทับข้อมูลในไฟล์นี์</translation>
+ </message>
+ <message>
+ <source><p>VT-x/AMD-V hardware acceleration has been enabled, but is not operational. Certain guests (e.g. OS/2 and QNX) require this feature.</p><p>Please ensure that you have enabled VT-x/AMD-V properly in the BIOS of your host computer.</p></source>
+ <translation><p>ตัวเร่งความเร็วฮาร์ดแวร์ VT-x/AMD-V ถูกเปิดใช้งานแต่ไม่สามารถทำงานได้ เกสต์บางชนิด (เช่น OS/2 และ QNX) ต้องการคุณสมบัตินี้</p><p>โปรดตรวจสอบว่าคุณได้เปิดใช้ VT-x/AMD-V ใน BIOS ของเครื่องโฮสต์ไว้อย่างถูกต้อง</p></translation>
+ </message>
+ <message>
+ <source>Failed to check files.</source>
+ <translation>การตรวจสอบไฟล์ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Failed to remove file.</source>
+ <translation>การลบไฟล์ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>You seem to have the USBFS filesystem mounted at /sys/bus/usb/drivers. We strongly recommend that you change this, as it is a severe mis-configuration of your system which could cause USB devices to fail in unexpected ways.</source>
+ <translation>ดูเหมือนว่าคุณได้เมาต์ระบบไฟล์ USBFS ไว้ที่ /sys/bus/usb/drivers เราขอแนะนำอย่างยิ่งให้คุณแก้ไขค่านี้เนื่องจากเป็นการกำหนดค่าที่ผิดพลาดในระบบของคุณอย่างร้ายแรง และอาจทำให้อุปกรณ์ USB ล้มเหลวอย่างไม่สามารถคาดการณ์ได้</translation>
+ </message>
+ <message>
+ <source>You are running an EXPERIMENTAL build of VirtualBox. This version is not suitable for production use.</source>
+ <translation>คุณกำลังใช้เวอร์ชวลบอกซ์รุ่นทดลอง รุ่นนี้ไม่เหมาะสำหรับการใช้งานจริง</translation>
+ </message>
+ <message>
+ <source>Restore</source>
+ <translation>คืนค่า</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>ลบ</translation>
+ </message>
+ <message>
+ <source>Failed to restore the snapshot <b>%1</b> of the virtual machine <b>%2</b>.</source>
+ <translation>ไม่สามารถคืนค่าสแนปช็อต <b>%1</b> ของเวอร์ชวลแมชชีน <b>%2</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to delete the snapshot <b>%1</b> of the virtual machine <b>%2</b>.</source>
+ <translation>ไม่สามารถลบสแนปช็อต <b>%1</b> ของเวอร์ชวลแมชชีน <b>%2</b> ได้</translation>
+ </message>
+ <message>
+ <source>Force Unmount</source>
+ <translation>บังคับถอนออก</translation>
+ </message>
+ <message>
+ <source>&Remove</source>
+ <comment>medium</comment>
+ <translation>&นำออก</translation>
+ </message>
+ <message>
+ <source><p>VT-x/AMD-V hardware acceleration is not available on your system. Your 64-bit guest will fail to detect a 64-bit CPU and will not be able to boot.</source>
+ <translation><p>ระบบของคุณไม่มีตัวเร่งความเร็วฮาร์ดแวร์ VT-x/AMD-V เกสต์ 64 บิตของคุณจะไม่สามารถตรวจพบซีพียู 64 บิต และจะไม่สามารถบูตได้</translation>
+ </message>
+ <message>
+ <source><p>VT-x/AMD-V hardware acceleration is not available on your system. Certain guests (e.g. OS/2 and QNX) require this feature and will fail to boot without it.</p></source>
+ <translation><p>ระบบของคุณไม่มีตัวเร่งความเร็วฮาร์ดแวร์ VT-x/AMD-V เกสต์บางชนิด (เช่น OS/2 และ QNX) ต้องการคุณสมบัตินี้ และจะไม่สามารถบูตได้<p></translation>
+ </message>
+ <message>
+ <source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p></source>
+ <translation><p>ไม่สามารถเปลี่ยนหน้าจอของเกสต์มาใช้หน้าจอของโฮสต์ได้เนื่องจากหน่วยความจำแสดงผลของเกสต์ไม่เพียงพอ</p><p>คุณควรกำหนดให้เวอร์ชวลแมชชีนมีหน่วยความจำแสดงผลอย่างน้อย<b>%1</b></p></translation>
+ </message>
+ <message>
+ <source><p>Could not change the guest screen to this host screen due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p><p>Press <b>Ignore</b> to switch the screen anyway or press <b>Cancel</b> to cancel the operation.</p></source>
+ <translation><p>ไม่สามารถเปลี่ยนหน้าจอของเกสต์มาใช้หน้าจอของโฮสต์ได้เนื่องจากหน่วยความจำแสดงผลของเกสต์ไม่เพียงพอ</p><p>คุณควรกำหนดให้เวอร์ชวลแมชชีนมีหน่วยความจำแสดงผลอย่างน้อย<b>%1</b></p><p>กด<b>เพิกเฉย</b>เพื่อสลับจอภาพต่อไป หรือกด<b>ยกเลิก</b>เพื่อยกเลิกการทำงาน</p></translation>
+ </message>
+ <message>
+ <source>Failed to open virtual machine located in %1.</source>
+ <translation>ไม่สามารถเปิดเวอร์ชวลแมชชีนใน %1 ได้</translation>
+ </message>
+ <message>
+ <source>Failed to add virtual machine <b>%1</b> located in <i>%2</i> because its already present.</source>
+ <translation>ไม่สามารถเพิ่มเวอร์ชวลแมชชีน <b>%1</b> ที่อยู่ใน <i>%2</i> ได้ เนื่องจากมีอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>Delete all files</source>
+ <translation>ลบไฟล์ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Remove only</source>
+ <translation>นำออกอย่างเดียว</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>นำออก</translation>
+ </message>
+ <message>
+ <source><p>You are about to add a virtual hard disk to controller <b>%1</b>.</p><p>Would you like to create a new, empty file to hold the disk contents or select an existing one?</p></source>
+ <translation><p>คุณกำลังจะเพิ่มฮาร์ดดิสก์เสมือนไปยังตัวควบคุม <b>%1</b></p><p>คุณต้องการสร้างขึ้นมาใหม่ สร้างไฟล์ว่างเพื่อเก็บเนื้อหาของดิสก์ หรือเลือกจากที่มีอยู่แล้ว?</p></translation>
+ </message>
+ <message>
+ <source><p>You are about to add a new floppy drive to controller <b>%1</b>.</p><p>Would you like to choose a virtual floppy disk to put in the drive or to leave it empty for now?</p></source>
+ <translation><p>คุณกำลังจะเพิ่มไดร์ฟฟลอปปี้ไปยังตัวควบคุม <b>%1</b></p><p>คุณต้องการเลือกดิสก์ฟลอปปี้เสมือนเพื่อใส่ไว้ในไดร์ฟ หรือต้องการปล่อยให้ว่างไว้?</p></translation>
+ </message>
+ <message>
+ <source>Failed to detach the hard disk (<nobr><b>%1</b></nobr>) from the slot <i>%2</i> of the machine <b>%3</b>.</source>
+ <translation>ไม่สามารถถอดฮาร์ดดิสก์ (<nobr><b>%1</b></nobr>) ออกจากสลอต <i>%2</i>ของเวอร์ชวลแมชชีน <b>%3</b></translation>
+ </message>
+ <message>
+ <source>Failed to update Guest Additions. The Guest Additions disk image file will be inserted for user installation.</source>
+ <translation>ไม่สามารถอัพเดตส่วนขยายสำหรับเกสต์ได้ ไฟล์ดิสก์อิมเมจของส่วนขยายสำหรับเกสต์จะถูกใส่เข้าไปเพื่อทำการติดตั้ง</translation>
+ </message>
+ <message>
+ <source>Failed to install the Extension Pack <b>%1</b>.</source>
+ <translation>ไม่สามารถติดตั้งแพคขยาย <b>%1</b></translation>
+ </message>
+ <message>
+ <source>Failed to uninstall the Extension Pack <b>%1</b>.</source>
+ <translation>ไม่สามารถถอนการติดตั้งแพคขยาย <b>%1</b></translation>
+ </message>
+ <message>
+ <source>&Remove</source>
+ <translation>&นำออก</translation>
+ </message>
+ <message>
+ <source>The current port forwarding rules are not valid. None of the host or guest port values may be set to zero.</source>
+ <translation>กฎการส่งต่อพอร์ตที่ใช้อยู่ไม่ถูกต้อง ไม่สามารถกำหนดให้ค่าพอร์ตของโฮสต์หรือของเกสต์เป็นศูนย์ได้</translation>
+ </message>
+ <message>
+ <source><p>There are unsaved changes in the port forwarding configuration.</p><p>If you proceed your changes will be discarded.</p></source>
+ <translation><p>มีการกำหนดค่าการส่งต่อพอร์ตที่ยังไม่ได้รับการบันทึก</p><p>หากคุณทำต่อไปการเปลี่ยนแปลงที่คุณทำไว้จะถูกละทิ้ง</p></translation>
+ </message>
+ <message>
+ <source>Failed to attach the hard disk (<nobr><b>%1</b></nobr>) to the slot <i>%2</i> of the machine <b>%3</b>.</source>
+ <translation>ไม่สามารถเชื่อมต่อฮาร์ดดิสก์ (<nobr><b>%1</b></nobr>) ไปยังสล็อต <i>%2</i> ของเครื่อง <b>%3</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>Note that the storage unit of this medium will not be deleted and that it will be possible to use it later again.</p></source>
+ <translation><p>โปรดทราบว่าหน่วยบันทึกข้อมูลของสื่อนี้จะไม่ถูกลบและยังสามารถนำกลับมาใช้ได้อีกในภายหลัง</p></translation>
+ </message>
+ <message>
+ <source><p>The virtual machine window will be now switched to <b>Seamless</b> mode. You can go back to windowed mode at any time by pressing <b>%1</b>.</p><p>Note that the <i>Host</i> key is currently defined as <b>%2</b>.</p><p>Note that the main menu bar is hidden in seamless mode. You can access it by pressing <b>Host+Home</b>.</p></source>
+ <translation><p>หน้าต่างเวอร์ชวลแมชชีนกำลังจะสลับไปใช้โหมด<b>ไร้ขอบ</b> คุณสามารถกลับไปใช้โหมดหน้าต่างได้ทุกเมื่อด้วยการกด <b>%1</b></p><p>โปรดทราบว่าปุ่ม<i>โฮสต์</i>ถูกกำหนดไว้เป็น <b>%2</b></p><p> และแถบเมนูหลักจะถูกซ่อนไว้ขณะอยู่ในโหมดไร้ขอบ คุณสามารถเข้าถึงแถบเมนูได้ด้วยการกดปุ่ม<b>โฮสต์+Home</b></p></translation>
+ </message>
+ <message>
+ <source><p>The virtual machine window will be now switched to <b>Scale</b> mode. You can go back to windowed mode at any time by pressing <b>%1</b>.</p><p>Note that the <i>Host</i> key is currently defined as <b>%2</b>.</p><p>Note that the main menu bar is hidden in scaled mode. You can access it by pressing <b>Host+Home</b>.</p></source>
+ <translation><p>หน้าต่างเวอร์ชวลแมชชีนกำลังจะสลับไปใช้โหมด<b>สเกล</b> คุณสามารถกลับไปใช้โหมดหน้าต่างได้ทุกเมื่อด้วยการกด <b>%1</b></p><p>โปรดทราบว่าปุ่ม<i>โฮสต์</i>ถูกกำหนดไว้เป็น <b>%2</b></p><p> และแถบเมนูหลักจะถูกซ่อนไว้ขณะอยู่ในโหมดสเกล คุณสามารถเข้าถึงแถบเมนูได้ด้วยการกดปุ่ม<b>โฮสต์+Home</b></p></translation>
+ </message>
+ <message>
+ <source>Failed to open the Extension Pack <b>%1</b>.</source>
+ <translation>ไม่สามารถเปิดแพคขยาย <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>You are about to install a VirtualBox extension pack. Extension packs complement the functionality of VirtualBox and can contain system level software that could be potentially harmful to your system. Please review the description below and only proceed if you have obtained the extension pack from a trusted source.</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name: </b></td><td>%1< [...]
+ <translation><p>คุณกำลังจะติดตั้งแพคขยายของเวอร์ชวลบอกซ์ แพคขยายจะช่วยเติมเต็มความสามารถของเวอร์ชวลบอกซ์และอาจมีซอฟต์แวร์ที่ต้องทำงานในระดับของระบบที่อาจเป็นอันตรายต่อระบบของคุณได้ กรุณาอ่านคำอธิบายด้านล่างโดยละเอียดและดำเนินการต่อไปก็ต่อเมื่อคุณได้รับส่วนขยายมาจากแหล่งที่เชื่อถือได้เท่านั้น</p><p><table cellpadding=0 cellspacing=0><tr><td><b>ชื่อ: </b></td><td>%1</td></tr><tr><td& [...]
+ </message>
+ <message>
+ <source>Extension packs complement the functionality of VirtualBox and can contain system level software that could be potentially harmful to your system. Please review the description below and only proceed if you have obtained the extension pack from a trusted source.</source>
+ <translation>แพคขยายจะช่วยเติมเต็มความสามารถของเวอร์ชวลบอกซ์และอาจมีซอฟต์แวร์ที่ต้องทำงานในระดับของระบบที่อาจเป็นอันตรายต่อระบบของคุณได้ กรุณาอ่านคำอธิบายด้านล่างโดยละเอียดและดำเนินการต่อไปก็ต่อเมื่อคุณได้รับส่วนขยายมาจากแหล่งที่เชื่อถือได้เท่านั้น</translation>
+ </message>
+ <message>
+ <source><p>An older version of the extension pack is already installed, would you like to upgrade? <p>%1</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name: </b></td><td>%2</td></tr><tr><td><b>New Version: </b></td><td>%3</td></tr><tr><td><b>Current Version: </b></td& [...]
+ <translation><p>แพคขยายรุ่นเก่ากว่าถูกติดตั้งไว้แล้ว คุณต้องการอัพเกรดหรือไม่? <p>%1</p><p><table cellpadding=0 cellspacing=0><tr><td><b>ชื่อ: </b></td><td>%2</td></tr><tr><td><b>รุ่นใหม่: </b></td><td>%3</td></tr><tr><td><b>รุ่นปัจจุบัน: </b></td><td>%4</td> [...]
+ </message>
+ <message>
+ <source>&Upgrade</source>
+ <translation>&อัพเกรด</translation>
+ </message>
+ <message>
+ <source><p>An newer version of the extension pack is already installed, would you like to downgrade? <p>%1</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name: </b></td><td>%2</td></tr><tr><td><b>New Version: </b></td><td>%3</td></tr><tr><td><b>Current Version: </b></t [...]
+ <translation><p>แพคขยายรุ่นใหม่กว่าถูกติดตั้งไว้แล้ว คุณต้องการดาวน์เกรดหรือไม่? <p>%1</p><p><table cellpadding=0 cellspacing=0><tr><td><b>ชื่อ: </b></td><td>%2</td></tr><tr><td><b>รุ่นใหม่: </b></td><td>%3</td></tr><tr><td><b>รุ่นปัจจุบัน: </b></td><td>%4</td&g [...]
+ </message>
+ <message>
+ <source>&Downgrade</source>
+ <translation>&ดาวน์เกรด</translation>
+ </message>
+ <message>
+ <source><p>The extension pack is already installed with the same version, would you like reinstall it? <p>%1</p><p><table cellpadding=0 cellspacing=0><tr><td><b>Name: </b></td><td>%2</td></tr><tr><td><b>Version: </b></td><td>%3</td></tr><tr><td><b>Description: </b></td>& [...]
+ <translation><p>แพคขยายที่ติดตั้งอยู่เป็นรุ่นเดียวกันอยู่แล้ว, คุณต้องการติดตั้งใหม่หรือไม่? <p>%1</p><p><table cellpadding=0 cellspacing=0><tr><td><b>ชื่อ: </b></td><td>%2</td></tr><tr><td><b>รุ่น: </b></td><td>%3</td></tr><tr><td><b>คำอธิบาย: </b></td><td>%4</ [...]
+ </message>
+ <message>
+ <source>&Reinstall</source>
+ <translation>ติดตั้งใ&หม่</translation>
+ </message>
+ <message>
+ <source><p>You are about to remove the VirtualBox extension pack <b>%1</b>.</p><p>Are you sure you want to proceed?</p></source>
+ <translation><p>คุณกำลังจะนำแพคขยายของเวอร์ชวลบอกซ์ออก <b>%1</b>.</p><p>แน่ใจหรือไม่ว่าคุณต้องการทำต่อไป?</p></translation>
+ </message>
+ <message>
+ <source>The extension pack <br><nobr><b>%1</b><nobr><br> was installed successfully.</source>
+ <translation>ถอนการติดตั้งแพคขยาย <br><nobr><b>%1</b><nobr><br> เสร็จสมบูรณ์</translation>
+ </message>
+ <message>
+ <source><p>Cannot create the machine folder <b>%1</b> in the parent folder <nobr><b>%2</b>.</nobr></p><p>Please check that the parent really exists and that you have permissions to create the machine folder.</p></source>
+ <translation><p>ไม่สามารถสร้างโฟลเดอร์ของเครื่อง <b>%1</b> ไว้ในโฟลเดอร์ชั้นก่อนหน้าได้ <nobr><b>%2</b></nobr></p><p>โปรดตรวจสอบว่าชั้นก่อนหน้าที่ระบุมีอยู่จริงและคุณมีสิทธิในการสร้างโฟลเดอร์ของเครื่องได้</p></translation>
+ </message>
+ <message>
+ <source>Failed to register the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถลงทะเบียนเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>The machine settings were changed while you were editing them. You currently have unsaved setting changes.</p><p>Would you like to reload the changed settings or to keep your own changes?</p></source>
+ <translation><p>การตั้งค่าของเครื่องถูกเปลี่ยนแปลงไประหว่างคุณกำลังแก้ไขอยู่ ขณะนี้คุณมีการตั้งค่าที่ยังไม่ได้รับการบันทึก</p><p>คุณต้องการโหลดการตั้งค่าที่ถูกเปลี่ยนแปลงขึ้นมา หรือต้องการบันทึกการเปลี่ยนแปลงของคุณ?</p></translation>
+ </message>
+ <message>
+ <source>Reload settings</source>
+ <translation>โหลดการตั้งค่าใหม่</translation>
+ </message>
+ <message>
+ <source>Keep changes</source>
+ <translation>เก็บความเปลี่ยนแปลง</translation>
+ </message>
+ <message>
+ <source>The virtual machine that you are changing has been started. Only certain settings can be changed while a machine is running. All other changes will be lost if you close this window now.</source>
+ <translation>เวอร์ชวลแมชชีนที่คุณกำลังแก้ไขถูกเปิดใช้งานอยู่ มีเพียงบางส่วนของการตั้งค่าเท่านั้นที่สามารถเปลี่ยนแปลงได้ขณะเครื่องกำลังทำงาน การเปลี่ยนแปลงอื่น ๆ จะหายไปหากคุณปิดหน้าต่างตอนนี้</translation>
+ </message>
+ <message>
+ <source>Failed to clone the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถโคลนเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Create a snapshot of the current machine state</source>
+ <translation>สร้างสแนปช็อตสถานะปัจจุบันของเครี่อง</translation>
+ </message>
+ <message>
+ <source><p>Error changing disk image mode from <b>%1</b> to <b>%2</b>.</p></source>
+ <translation><p>เกิดความผิดพลาดในการเปลี่ยนโหมดดิสอิมเมจจาก <b>%1</b> เป็น <b>%2</b></p></translation>
+ </message>
+ <message>
+ <source>Could not load the Host USB Proxy Service (VERR_FILE_NOT_FOUND). The service might not be installed on the host computer</source>
+ <translation>ไม่สามารถโหลดบริการพรอกซี USB ของโฮสต์ได้ (VERR_FILE_NOT_FOUND) บริการนี้อาจไม่ได้ถูกติดตั้งไว้บนคอมพิวเตอร์โฮสต์</translation>
+ </message>
+ <message>
+ <source>VirtualBox is not currently allowed to access USB devices. You can change this by adding your user to the 'vboxusers' group. Please see the user manual for a more detailed explanation</source>
+ <translation>เวอร์ชวลบอกซ์ไม่ได้รับอนุญาตให้เข้าถึงอุปกรณ์ USB คุณสามารถแก้ไขได้ด้วยการเพิ่มผู้ใช้ของคุณไปยังกลุ่ม 'vboxusers' คำอธิบายโดยละเอียดสามารถดูเพิ่มเติมได้จากคู่มือผู้ใช้</translation>
+ </message>
+ <message>
+ <source>VirtualBox is not currently allowed to access USB devices. You can change this by allowing your user to access the 'usbfs' folder and files. Please see the user manual for a more detailed explanation</source>
+ <translation>เวอร์ชวลบอกซ์ไม่ได้รับอนุญาตให้เข้าถึงอุปกรณ์ USB คุณสามารถแก้ไขได้ด้วยการอนุญาตให้ผู้ใช้ของคุณเข้าถึงโฟลเดอร์และไฟล์ 'usbfs' คำอธิบายโดยละเอียดสามารถดูเพิ่มเติมได้จากคู่มือผู้ใช้</translation>
+ </message>
+ <message>
+ <source>The USB Proxy Service has not yet been ported to this host</source>
+ <translation>บริการ USB พรอกซียังไม่สามารถใช้บนโฮสต์นี้ได้</translation>
+ </message>
+ <message>
+ <source>Could not load the Host USB Proxy service</source>
+ <translation>ไม่สามารถโหลดบริการ USB พรอกซีของโฮสต์ได้</translation>
+ </message>
+ <message>
+ <source>Can't find snapshot named <b>%1</b>.</source>
+ <translation>ไม่พบสแนปช็อตชื่อ <b>%1</b></translation>
+ </message>
+ <message>
+ <source><p>You have an old version (%1) of the <b><nobr>%2</nobr></b> installed.</p><p>Do you wish to download latest one from the Internet?</p></source>
+ <translation><p>คุณมีรุ่นเก่า (%1) ของ <b><nobr>%2</nobr></b> ติดตั้งอยู่</p><p>คุณควรดาวน์โหลดรุ่นล่าสุดจากอินเทอร์เน็ตหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to download the <b><nobr>%1</nobr></b> from <nobr><a href="%2">%2</a></nobr> (size %3 bytes)?</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการดาวน์โหลด <b><nobr>%1</nobr></b> จาก <nobr><a href="%2">%2</a></nobr> (ขนาด %3 ไบต์)?</p></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>.</nobr></p><p>Do you wish to install this extension pack?</p></source>
+ <translation><p>เสร็จสิ้นการดาวน์โหลด <b><nobr>%1</nobr></b> จาก <nobr><a href="%2">%2</a></nobr> และบันทึกไว้ที่ <nobr><b>%3</b></nobr></p><p>คุณต้องการติดตั้งแพคขยายนี้หรือไม่?</p></translation>
+ </message>
+ <message>
+ <source>Install</source>
+ <comment>extension pack</comment>
+ <translation>ติดตั้ง</translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> but can't be saved locally as <nobr><b>%3</b>.</nobr></p><p>Please choose another location for that file.</p></source>
+ <translation><p>เสร็จสิ้นการดาวน์โหลด <b><nobr>%1</nobr></b> จาก <nobr><a href="%2">%2</a></nobr> แต่ไม่สามารถบันทึกไว้ที่ <nobr><b>%3</b> ได้</nobr></p><p>กรุณาเลือกที่อื่นเพื่อจัดเก็บไฟล์นี้</p></translation>
+ </message>
+ <message>
+ <source><p>You have version %1 of the <b><nobr>%2</nobr></b> installed.</p><p>You should download and install version %3 of this extension pack from Oracle!</p></source>
+ <translation><p>คุณมีรุ่น %1 ของ <b><nobr>%2</nobr></b> ติดตั้งอยู่</p><p>คุณควรดาวน์โหลดและติดตั้งแพคขยายนี้รุ่น %3 จากออราเคิล!</p></translation>
+ </message>
+ <message>
+ <source><p>Failed to initialize COM because the VirtualBox global configuration directory <b><nobr>%1</nobr></b> is not accessible. Please check the permissions of this directory and of its parent directory.</p><p>The application will now terminate.</p></source>
+ <translation><p>ไม่สามารถเริ่มการทำงาน COM เพราะไดเรกทอรีการตั้งค่าส่วนกลางของเวอร์ชวลบอกซ์ <b><nobr>%1</nobr></b> ไม่สามารถเข้าถึงได้ กรุณาตรวจสอบสิทธิการใช้งานของไดเรกทอรีนี้รวมทั้งไดเรกทอรีชั้นก่อนหน้า</p><p>แอพพลิเคชันจะยุติการทำงานทันที</p></translation>
+ </message>
+ <message>
+ <source><p>You are about to remove following virtual machine items from the machine list:</p><p><b>%1</b></p><p>Do you wish to proceed?</p></source>
+ <translation><p>คุณกำลังจะนำเวอร์ชวลแมชชีนต่อไปนี้ออกจากรายการ:</p><p><b>%1</b></p><p>คุณต้องการทำต่อไปหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source><p>You are about to remove following inaccessible virtual machines from the machine list:</p><p>%1</p><p>Do you wish to proceed?</p></source>
+ <translation><p>คุณกำลังจะนำเวอร์ชวลแมชชีนที่ไม่สามารถเข้าถึงได้ต่อไปนี้ออกจากรายการ:</p><p>%1</p><p>คุณต้องการทำต่อไปหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source><p>You are about to remove following virtual machines from the machine list:</p><p>%1</p><p>Would you like to delete the files containing the virtual machine from your hard disk as well? Doing this will also remove the files containing the machine's virtual hard disks if they are not in use by another machine.</p></source>
+ <translation><p>คุณกำลังจะนำเวอร์ชวลแมชชีนต่อไปนี้ออกจากรายการ:</p><p>%1</p><p>คุณต้องการลบไฟล์ที่ใช้จัดเก็บเวอร์ชวลแมชชีนจากฮาร์ดดิสก์ของคุณด้วยหรือไม่? การกระทำนี้จะนำไฟล์ฮาร์ดดิสก์เสมือนของคุณออกไปด้วย หากไฟล์ดังกล่าวไม่ได้ถูกใช้อยู่โดยเครื่องอื่น</p></translation>
+ </message>
+ <message>
+ <source><p>You are about to remove following virtual machines from the machine list:</p><p>%1</p><p>Would you like to delete the files containing the virtual machine from your hard disk as well?</p></source>
+ <translation><p>คุณกำลังจะนำเวอร์ชวลแมชชีนต่อไปนี้ออกจากรายการ:</p><p>%1</p><p>คุณต้องการลบไฟล์ที่ใช้จัดเก็บเวอร์ชวลแมชชีนจากฮาร์ดดิสก์ของคุณด้วยหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source>Do you wish to cancel all current network operations?</source>
+ <translation>คุณต้องการยกเลิกกระบวนการทางเครือข่ายทั้งหมดหรือไม่?</translation>
+ </message>
+ <message>
+ <source>ACPI Shutdown</source>
+ <comment>machine</comment>
+ <translation>ชัตดาวน์ด้วย ACPI</translation>
+ </message>
+ <message>
+ <source>Power Off</source>
+ <comment>machine</comment>
+ <translation>ปิดสวิตซ์</translation>
+ </message>
+ <message>
+ <source><p>Cannot remove the machine folder <nobr><b>%1</b>.</nobr></p><p>Please check that this folder really exists and that you have permissions to remove it.</p></source>
+ <translation><p>ไม่สามารถนำโฟลเดอร์ของเครื่อง <nobr><b>%1</b> ออกได้ </nobr></p><p>โปรดตรวจสอบว่าโฟลเดอร์นี้มีอยู่จริงและคุณมีสิทธิลบโฟลเดอร์ได้</p></translation>
+ </message>
+ <message>
+ <source><p>Cannot create the machine folder <b>%1</b> in the parent folder <nobr><b>%2</b>.</nobr></p><p>This folder already exists and possibly belongs to another machine.</p></source>
+ <translation><p>ไม่สามารถสร้างโฟลเดอร์ของเครื่อง <b>%1</b> ไว้ในโฟลเดอร์ชั้นก่อนหน้าได้ <nobr><b>%2</b></nobr></p><p>โฟลเดอร์นี้มีอยู่แล้วและอาจถูกใช้โดยเครื่องอื่นอยู่</p></translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to discard the saved state of the following virtual machines?</p><p><b>%1</b></p><p>This operation is equivalent to resetting or powering off the machine without doing a proper shutdown of the guest OS.</p></source>
+ <translation><p>คุณแน่ใจหรือไม่ว่าต้องการทิ้งสถานะที่บันทึกไว้ของเวอร์ชวลแมชชีนต่อไปนี้?</p><p><b>%1</b></p><p>กระบวนการนี้จะส่งผลเช่นเดียวกับการกดรีเซ็ตหรือปิดเครื่องโดยไม่ได้ชัตดาวน์โอเอสของเกสต์ตามชั้นตอน</p></translation>
+ </message>
+ <message>
+ <source><p>Do you really want to reset the following virtual machines?</p><p><b>%1</b></p><p>This will cause any unsaved data in applications running inside it to be lost.</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการรีเซ็ตเวอร์ชวลแมชชีนต่อไปนี้?</p><p><b>%1</b></p><p>นี่จะทำให้ข้อมูลที่ยังไม่ได้รับการบันทึกของแอพพลิเคชันที่รันอยู่ทั้งหมดหายไป</p></translation>
+ </message>
+ <message>
+ <source><p>Do you really want to send an ACPI shutdown signal to the following virtual machines?</p><p><b>%1</b></p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการส่งสัญญาณชัตดาวน์ ACPI ให้กับเวอร์ชวลแมชชีนต่อไปนี้?</p><p><b>%1</b></p></translation>
+ </message>
+ <message>
+ <source><p>Do you really want to power off the following virtual machines?</p><p><b>%1</b></p><p>This will cause any unsaved data in applications running inside it to be lost.</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการปิดสวิตซ์ของเวอร์ชวลแมชชีนต่อไปนี้?</p><p><b>%1</b></p><p>คุณจะเสียข้อมูลที่ไม่ได้บันทึกไว้ของแอพพลิเคชันที่ทำงานอยู่ในเวอร์ชวลแมชชีนดังกล่าวไป</p></translation>
+ </message>
+ <message>
+ <source><p>You are trying to move machine <nobr><b>%1</b></nobr> to group <nobr><b>%2</b></nobr> which already have sub-group <nobr><b>%1</b></nobr>.</p><p>Please resolve this name-conflict and try again.</p></source>
+ <translation><p>คุณกำลังย้ายเครื่อง <nobr><b>%1</b></nobr> ไปยังกลุ่ม <nobr><b>%2</b></nobr> ซึ่งมีกลุ่มย่อย <nobr><b>%1</b></nobr> อยู่แล้ว</p><p>โปรดแก้ไขชื่อที่ซ้ำกันนี้แล้วลองอีกครั้ง</p></translation>
+ </message>
+ <message>
+ <source><p>You are trying to move group <nobr><b>%1</b></nobr> to group <nobr><b>%2</b></nobr> which already have another item with the same name.</p><p>Would you like to automatically rename it?</p></source>
+ <translation><p>คุณกำลังย้ายกลุ่ม <nobr><b>%1</b></nobr> ไปยังกลุ่ม <nobr><b>%2</b></nobr> ซึ่งมีรายการที่มีชื่อซ้ำกันอยู่แล้ว</p><p>คุณต้องการให้เปลี่ยนชื่อโดยอัตโนมัติหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>เปลี่ยนชื่อ</translation>
+ </message>
+ <message>
+ <source><p>You are about to restore snapshot <nobr><b>%1</b></nobr>.</p><p>You can create a snapshot of the current state of the virtual machine first by checking the box below; if you do not do this the current state will be permanently lost. Do you wish to proceed?</p></source>
+ <translation><p>คุณกำลังจะเรียกคืนสแนปช็อต <nobr><b>%1</b></nobr></p><p>คุณสามารถสร้างสแนปช็อตของสถานะปัจจุบันขึ้นมาก่อนได้โดยเลือกกล่องด้านล่าง หากคุณไม่สร้างสแนปช็อต สถานะปัจจุบันจะหายไป คุณต้องการทำต่อไปหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to restore snapshot <nobr><b>%1</b></nobr>?</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการเรียกคืนสแนปช็อต <nobr><b>%1</b></nobr>?</p></translation>
+ </message>
+ <message>
+ <source>Failed to set groups of the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถจัดกลุ่มของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>Could not start the machine <b>%1</b> because the following physical network interfaces were not found:</p><p><b>%2</b></p><p>You can either change the machine's network settings or stop the machine.</p></source>
+ <translation><p>ไม่สามารถเริ่มการทำงานเครื่อง <b>%1</b> ได้ เนื่องจากไม่พบแผงวงจรเครือข่ายจริงต่อไปนี้:</p><p><b>%2</b></p><p>คุณสามารถเปลี่ยนการตั้งค่าเครือข่ายเพื่อทำงานต่อไปหรือหยุดการทำงานของเครื่องก่อนได้</p></translation>
+ </message>
+ <message>
+ <source>Change Network Settings</source>
+ <translation>เปลี่ยนการตั้งค่าเครือข่าย</translation>
+ </message>
+ <message>
+ <source><p>Cannot start the VirtualBox Manager due to local restrictions.</p><p>The application will now terminate.</p></source>
+ <translation><p>ไม่สามารถเริ่มการทำงานส่วนจัดการเวอร์ชวลบอกซ์เนื่องจากข้อจำกัดของเครื่องนี้</p><p>แอพพลิเคชันจะยุติการทำงานทันที</p></translation>
+ </message>
+ <message>
+ <source><p>Could not find a language file for the language <b>%1</b> in the directory <b><nobr>%2</nobr></b>.</p><p>The language will be temporarily reset to the system default language. Please go to the <b>Preferences</b> window which you can open from the <b>File</b> menu of the VirtualBox Manager window, and select one of the existing languages on the <b>Language</b> page.</p></source>
+ <translation><p>ไม่พบไฟล์สำหรับภาษา <b>%1</b> ในไดเรกทอรี <b><nobr>%2</nobr></b></p><p>ระบบจะกลับไปใช้ภาษาตั้งต้นเป็นการชั่วคราว กรุณาไปที่หน้าต่าง<b>ค่าตั้งพึงใจ</b>ที่คุณสามารถเปิดได้จากเมนู<b>ไฟล์</b>ของหน้าต่างส่วนจัดการเวอร์ชวลบอกซ์ แล้วเลือกภาษาที่มีให้ใช้จากหน้า <b>ภาษา</b></p></translation>
+ </message>
+ <message>
+ <source><p>Could not load the language file <b><nobr>%1</nobr></b>. <p>The language will be temporarily reset to English (built-in). Please go to the <b>Preferences</b> window which you can open from the <b>File</b> menu of the VirtualBox Manager window, and select one of the existing languages on the <b>Language</b> page.</p></source>
+ <translation><p>ไม่สามารถโหลดไฟล์ภาษา <b><nobr>%1</nobr></b> <p>ระบบจะกลับไปใช้ภาษาอังกฤษ (มีในตัว) เป็นการชั่วคราว กรุณาไปที่หน้าต่าง<b>ค่าตั้งพึงใจ</b>ที่คุณสามารถเปิดได้จากเมนู<b>ไฟล์</b>ของหน้าต่างส่วนจัดการเวอร์ชวลบอกซ์ แล้วเลือกภาษาที่มีให้ใช้จากหน้า <b>ภาษา</b></p></translation>
+ </message>
+ <message>
+ <source>There is no virtual machine with the identifier <b>%1</b>.</source>
+ <translation>ไม่มีเวอร์ชวลแมชชีนที่มีตัวระบุเป็น <b>%1</b></translation>
+ </message>
+ <message>
+ <source>Ignore</source>
+ <translation>เพิกเฉย</translation>
+ </message>
+ <message>
+ <source>Failed to create NAT network.</source>
+ <translation>ไม่สามารถสร้างเครือข่าย NAT ได้</translation>
+ </message>
+ <message>
+ <source>Failed to remove NAT network <b>%1</b>.</source>
+ <translation>ไม่สามารถนำเครือข่าย NAT <b>%1</b> ออกได้</translation>
+ </message>
+ <message>
+ <source>Failed to create DHCP server.</source>
+ <translation>ไม่สามารถสร้างเซอร์ฟเวอร์ DHCP ได้</translation>
+ </message>
+ <message>
+ <source>Failed to remove DHCP server for network interface <b>%1</b>.</source>
+ <translation>ไม่สามารถนำเซอร์ฟเวอร์ DHCP สำหรับแผงวงจรเครือข่าย <b>%1</b> ออกได้</translation>
+ </message>
+ <message>
+ <source>Failed to create the host network interface.</source>
+ <translation>ไม่สามารถสร้างส่วนเชื่อมต่อเครือข่ายของโฮสต์ได้</translation>
+ </message>
+ <message>
+ <source>Create &new disk</source>
+ <translation>สร้างดิสก์ใ&หม่</translation>
+ </message>
+ <message>
+ <source>&Choose existing disk</source>
+ <translation>เ&ลือกดิสก์ที่มีอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>Leave &empty</source>
+ <translation>ปล่อยให้&ว่างไว้</translation>
+ </message>
+ <message>
+ <source>&Choose disk</source>
+ <translation>เ&ลือกดิสก์</translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to remove the virtual hard disk <nobr><b>%1</b></nobr> from the list of known disk image files?</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการนำฮาร์ดดิสก์เสมือน <nobr><b>%1</b></nobr> ออกจากรายการไฟล์ดิสก์อิมเมจที่รู้จัก?</p></translation>
+ </message>
+ <message>
+ <source><p>As this hard disk is inaccessible its image file can not be deleted.</p></source>
+ <translation><p>เนื่องจากไม่สามารถเข้าถึงฮาร์ดดิสก์ได้ จึงไม่สามารถลบไฟล์อิมเมจของฮาร์ดดิสก์ได้</p></translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to remove the virtual optical disk <nobr><b>%1</b></nobr> from the list of known disk image files?</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการนำออปติคัลดิสก์เสมือน <nobr><b>%1</b></nobr> ออกจากรายการไฟล์ดิสก์อิมเมจที่รู้จัก?</p></translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to remove the virtual floppy disk <nobr><b>%1</b></nobr> from the list of known disk image files?</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการนำฟลอปปี้ดิสก์เสมือน <nobr><b>%1</b></nobr> ออกจากรายการไฟล์ดิสก์อิมเมจที่รู้จัก?</p></translation>
+ </message>
+ <message>
+ <source><p>Unable to insert the virtual optical disk <nobr><b>%1</b></nobr> into the machine <b>%2</b>.</p></source>
+ <translation><p>ไม่สามารถใส่แผ่นออปติคัลดิสก์เสมือน <nobr><b>%1</b></nobr> ลงในเครื่อง <b>%2</b> ได้</p></translation>
+ </message>
+ <message>
+ <source><p>Would you like to try to force insertion of this disk?</p></source>
+ <translation><p>คุณต้องการลองบังคับใส่แผ่นดิสก์นี้หรือไม่?</p></translation>
+ </message>
+ <message>
+ <source><p>Unable to eject the virtual optical disk <nobr><b>%1</b></nobr> from the machine <b>%2</b>.</p></source>
+ <translation><p>ไม่สามารถดีดแผ่นออปติคัลดิสก์เสมือน <nobr><b>%1</b></nobr> ออกจากเครื่อง <b>%2</b> ได้</p></translation>
+ </message>
+ <message>
+ <source><p>Would you like to try to force ejection of this disk?</p></source>
+ <translation><p>คุณต้องการลองบังคับดีดแผ่นดิสก์นี้ออกหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source><p>Unable to insert the virtual floppy disk <nobr><b>%1</b></nobr> into the machine <b>%2</b>.</p></source>
+ <translation><p>ไม่สามารถใส่แผ่นฟลอปปี้ดิสก์เสมือน <nobr><b>%1</b></nobr> ลงในเครื่อง <b>%2</b> ได้</p></translation>
+ </message>
+ <message>
+ <source><p>Unable to eject the virtual floppy disk <nobr><b>%1</b></nobr> from the machine <b>%2</b>.</p></source>
+ <translation><p>ไม่สามารถดีดแผ่นฟลอปปี้ดิสก์เสมือน <nobr><b>%1</b></nobr> ออกจากเครื่อง <b>%2</b> ได้</p></translation>
+ </message>
+ <message numerus="yes">
+ <source><p>The %n following virtual machine(s) are currently in a saved state: <b>%1</b></p><p>If you continue the runtime state of the exported machine(s) will be discarded. The other machine(s) will not be changed.</p></source>
+ <comment>This text is never used with n == 0. Feel free to drop the %n where possible, we only included it because of problems with Qt Linguist (but the user can see how many machines are in the list and doesn't need to be told).</comment>
+ <translation>
+ <numerusform><p>เวอร์ชวลแมชชีน %n เครื่องต่อไปนี้อยู่ในสถานะที่บันทึกไว้:<b>%1</b></p><p>หากคุณดำเนินการต่อ สถานะการทำงานของเครื่องที่ถูกส่งออกจะถูกทิ้งไป แต่เครื่องอื่น ๆ จะไม่เกิดการเปลี่นยแปลงใด ๆ</p></numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>Switch</source>
+ <translation>สลับ</translation>
+ </message>
+ <message>
+ <source>Failed to enable the remote desktop server for the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถเปิดใช้เซอร์ฟเวอร์เดสก์ทอประยะไกลของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to disable the remote desktop server for the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถปิดการทำงานของเซอร์ฟเวอร์เดสก์ทอประยะไกลของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to enable video capturing for the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถเปิดการจับภาพวิดีโอของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to disable video capturing for the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถปิดการจับภาพวิดีโอของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>Could not find the <b>VirtualBox Guest Additions</b> disk image file.</p><p>Do you wish to download this disk image file from the Internet?</p></source>
+ <translation><p>ไม่พบไฟล์ดิสก์อิมเมจของ<b>ส่วนขยายสำหรับเกสต์เวอร์ชวลบอกซ์</b></p><p>คุณต้องการดาวน์โหลดไฟล์ดิสก์อิมเมจนี้จากอินเทอร์เน็ตหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>ดาวน์โหลด</translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to download the <b>VirtualBox Guest Additions</b> disk image file from <nobr><a href="%1">%1</a></nobr> (size %2 bytes)?</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการดาวน์โหลด<b>ส่วนขยายสำหรับเกสต์เวอร์ชวลบอกซ์</b> จาก <nobr><a href="%1">%1</a></nobr> (ขนาด %2 ไบต์)?</p></translation>
+ </message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> but can't be saved locally as <nobr><b>%2</b>.</nobr></p><p>Please choose another location for that file.</p></source>
+ <translation><p>ดาวน์โหลดไฟล์ดิสก์อิมเมจของ<b>โปรแกรมเสริมสำหรับเกสต์</b>มาจาก<nobr><a href="%1">%1</a></nobr>สำเร็จแล้ว แต่ไม่สามารถบันทึกเป็น <nobr><b>%2</b> ได้</nobr></p><p>โปรดเลือกที่ตั้งสำหรับไฟล์นี้ใหม่อีกครั้ง</p></translation>
+ </message>
+ <message>
+ <source><p>Could not find the <b>VirtualBox User Manual</b> <nobr><b>%1</b>.</nobr></p><p>Do you wish to download this file from the Internet?</p></source>
+ <translation><p>ไม่พบ<b>คู่มือผู้ใช้เวอร์ชวลบอกซ์</b> <nobr><b>%1</b></nobr></p><p>คุณต้องการดาวน์โหลดไฟล์นี้จากอินเทอร์เน็ตหรือไม่?</p></translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to download the <b>VirtualBox User Manual</b> from <nobr><a href="%1">%1</a></nobr> (size %2 bytes)?</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการดาวน์โหลด <b>คู่มือผู้ใช้เวอร์ชวลบอกซ์</b> จาก <nobr><a href="%1">%1</a></nobr> (ขนาด %2 ไบต์)?</p></translation>
+ </message>
+ <message>
+ <source><p>The VirtualBox User Manual has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> but can't be saved locally as <nobr><b>%2</b>.</nobr></p><p>Please choose another location for that file.</p></source>
+ <translation><p>ดาวน์โหลดคู่มือผู้ใช้เวอร์ชวลบอกซ์มาจาก <nobr><a href="%1">%1</a></nobr> สำเร็จแล้ว แต่ไม่สามารถบันทึกเป็น <nobr><b>%2</b> ได้</nobr></p><p>โปรดเลือกที่ตั้งสำหรับไฟล์นี้ใหม่อีกครั้ง</p></translation>
+ </message>
+ <message>
+ <source><p>The VirtualBox User Manual has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>.</nobr></p></source>
+ <translation><p>ดาวน์โหลดคู่มือผู้ใช้เวอร์ชวลบอกซ์มาจาก <nobr><a href="%1">%1</a></nobr> สำเร็จแล้ว และถูกบันทึกไว้เป็น <nobr><b>%2</b></nobr></p></translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Ok</source>
+ <translation>ตกลง</translation>
+ </message>
+ <message>
+ <source>Do not show this message again</source>
+ <translation>ไม่ต้องแสดงข้อความนี้อีก</translation>
+ </message>
+ <message>
+ <source><p>Do you want to remove the NAT network <nobr><b>%1</b>?</nobr></p><p>If this network is in use by one or more virtual machine network adapters these adapters will no longer be usable until you correct their settings by either choosing a different network name or a different adapter attachment type.</p></source>
+ <translation><p>คุณต้องการนำเครือข่าย NAT <nobr><b>%1</b> ออกหรือไม่?</nobr></p><p>หากเครือข่ายนี้ถูกใช้อยู่โดยแผงวงจรเครือข่ายของเวอร์ชวลแมชชีนเครื่องใดเครื่องหนึ่ง แผงวงจรเหล่านี้จะไม่สามารถใช้งานได้จนกว่าคุณจะเลือกชื่อเครือข่ายใหม่หรือเปลี่ยนไปใช้การเชื่อมต่อเครือข่ายชนิดอื่น</p></translation>
+ </message>
+ <message>
+ <source>Failed to attach the webcam <b>%1</b> to the virtual machine <b>%2</b>.</source>
+ <translation>ไม่สามารถเชื่อมต่อเว็บแคม <b>%1</b> เข้ากับเวอร์ชวลแมชชีน <b>%2</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to detach the webcam <b>%1</b> from the virtual machine <b>%2</b>.</source>
+ <translation>ไม่สามารถนำเว็บแคม <b>%1</b> ออกจากเวอร์ชวลแมชชีน <b>%2</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>The VirtualBox Guest Additions do not appear to be available on this virtual machine, and shared folders cannot be used without them. To use shared folders inside the virtual machine, please install the Guest Additions if they are not installed, or re-install them if they are not working correctly, by selecting <b>Insert Guest Additions CD image</b> from the <b>Devices</b> menu. If they are installed but the machine is not yet fully starte [...]
+ <translation><p>ไม่พบส่วนขยายสำหรับเกสต์บนเวอร์ชวลแมชชีนเครื่องนี้ โฟลเดอร์ใช้ร่วมกันไม่สามารถทำงานได้หากไม่มีส่วนขยายดังกล่าว หากต้องการใช้โฟลเดอร์ใช้ร่วมกันในเวอร์ชวลแมชชีน โปรดติดตั้งส่วนขยายสำหรับเกสต์หากยังไม่ได้ติดตั้ง หรือติดตั้งใหม่หากติดตั้งไว้แล้วแต่ไม่สามารถทำงานได้ โดยเลือก<b>ใส่ซีดีอิมเมจโปรแกรมเสริมสำหรับเกสต์</b>จากเมนู<b>อุปกรณ์</b> ทั้งนี้ โปรดทราบว่าโฟลเดอร์ใช้ร่วมกันจะสามารถใช้งานได้หลังจากเวอร์ชวลแมชชีนเริ่มการทำงานโดยสมบูรณ์แล้วเ [...]
+ </message>
+ <message>
+ <source>Insert</source>
+ <comment>additions</comment>
+ <translation>ใส่</translation>
+ </message>
+ <message>
+ <source><p>The virtual screen is currently set to a <b>%1 bit</b> color mode. For better performance please change this to <b>%2 bit</b>. This can usually be done from the <b>Display</b> section of the guest operating system's Control Panel or System Settings.</p></source>
+ <translation><p>หน้าจอเสมือนกำลังทำงานอยู่ในโหมดระดับสี <b>%1 บิต</b> เพื่อประสิทธิภาพที่ดีขึ้น กรุณาเปลี่ยนค่านี้เป็น <b>%2 บิต</b> โดยทั่วไปแล้วสามารถดำเนินการได้ที่ส่วน<b>แสดงผล</b>ในแผงควบคุมระบบปฏิบัติการของเกสต์หรือส่วนของการตั้งค่าระบบ</p></translation>
+ </message>
+ <message>
+ <source>The current port forwarding rules are not valid. Rule names should be unique.</source>
+ <translation>กฎการส่งต่อพอร์ตนี้ไม่ถูกต้อง ชื่อของกฎแต่ละข้อต้องไม่ซ้ำกัน</translation>
+ </message>
+ <message>
+ <source>The current port forwarding rules are not valid. Few rules have same host ports and conflicting IP addresses.</source>
+ <translation>กฎการส่งต่อพอร์ตที่ใช้อยู่ไม่ถูกต้อง มีบางกฎที่ใช้พอร์ตของโฮสต์ซ้ำกันและมีไอพีแอดเดรสขัดแย้งกัน</translation>
+ </message>
+ <message>
+ <source><p>Failed to create the VirtualBoxClient COM object.</p><p>The application will now terminate.</p></source>
+ <translation><p>ไม่สามารถสร้างอ็อบเจคต์ VirtualBoxClient COM ได้</p><p>แอพพลิเคชันจะยุติการทำงานทันที</p></translation>
+ </message>
+ <message>
+ <source>Failed to set the global VirtualBox extra data for key <i>%1</i> to value <i>{%2}</i>.</source>
+ <translation>ไม่สามารถกำหนดข้อมูลเพิ่มเติมของเวอร์ชวลบอกซ์สำหรับคีย์ <i>%1</i> ให้เป็น <i>{%2}</i> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to set the extra data for key <i>%1</i> of machine <i>%2</i> to value <i>{%3}</i>.</source>
+ <translation>ไม่สามารถกำหนดข้อมูลเพิ่มเติมสำหรับคีย์ <i>%1</i> ของเครื่อง <i>%2</i> ให้เป็น <i>{%3}</i> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to save the settings.</source>
+ <translation>ไม่สามารถบันทึกการตั้งค่าได้</translation>
+ </message>
+ <message>
+ <source><p>You are about to add a new optical drive to controller <b>%1</b>.</p><p>Would you like to choose a virtual optical disk to put in the drive or to leave it empty for now?</p></source>
+ <translation><p>คุณกำลังจะเพิ่มไดรฟ์ออปติคัลไปยังตัวควบคุม <b>%1</b></p><p>คุณต้องการเลือกออปติคัลดิสก์เสมือนเพื่อใส่ในไดรฟ์นี้เลย หรือต้องการให้ปล่อยว่างไว้ก่อน</p></translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to delete the optical drive?</p><p>You will not be able to insert any optical disks or ISO images or install the Guest Additions without it!</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการลบไดรฟ์ออปติคัล?</p><p>คุณจะไม่สามารถใส่แผ่นดิสก์ออปติคัลหรือไฟล์ ISO ใด ๆ หรือติดตั้งส่วนขยายสำหรับเกสต์ได้หากไม่มีไดรฟ์ออปติคัล!</p></translation>
+ </message>
+ <message>
+ <source>Failed to attach the optical drive (<nobr><b>%1</b></nobr>) to the slot <i>%2</i> of the machine <b>%3</b>.</source>
+ <translation>ไม่สามารถเชื่อมต่อไดรฟ์ออปติคัล (<nobr><b>%1</b></nobr>) ไปยังสล็อต <i>%2</i> ของเครื่อง <b>%3</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to attach the floppy drive (<nobr><b>%1</b></nobr>) to the slot <i>%2</i> of the machine <b>%3</b>.</source>
+ <translation>ไม่สามารถเชื่อมต่อไดรฟ์ฟลอปปี้ (<nobr><b>%1</b></nobr>) ไปยังสล็อต <i>%2</i> ของเครื่อง <b>%3</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to detach the optical drive (<nobr><b>%1</b></nobr>) from the slot <i>%2</i> of the machine <b>%3</b>.</source>
+ <translation>ไม่สามารถถอดไดรฟ์ออปติคัล (<nobr><b>%1</b></nobr>) ออกจากสล็อต <i>%2</i> ของเครื่อง <b>%3</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to detach the floppy drive (<nobr><b>%1</b></nobr>) from the slot <i>%2</i> of the machine <b>%3</b>.</source>
+ <translation>ไม่สามารถถอดไดรฟ์ฟลอปปี้ (<nobr><b>%1</b></nobr>) ออกจากสล็อต <i>%2</i> ของเครื่อง <b>%3</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>Could not insert the <b>VirtualBox Guest Additions</b> disk image file into the virtual machine <b>%1</b>, as the machine has no optical drives. Please add a drive using the storage page of the virtual machine settings window.</p></source>
+ <translation><p>ไม่สามารถใส่ไฟล์ดิสก์อิมเมจ<b>ส่วนขยายสำหรับเกสต์เวอร์ชวลบอกซ์</b>ลงในเวอร์ชวลแมชชีน <b>%1</b> ได้ เนื่องจากเครื่องไม่มีไดรฟ์ออปติคัล โปรดเพิ่มไดรฟ์ได้ที่หน้าหน่วยเก็บข้อมูลของหน้าต่างการตั้งค่าเวอร์ชวลแมชชีน</p></translation>
+ </message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>.</nobr></p><p>Do you wish to register this disk image file and insert it into the virtual optical drive?</p></source>
+ <translation><p>ดาวน์โหลดไฟล์ดิสก์อิมเมจของ<b>โปรแกรมเสริมสำหรับเกสต์</b>มาจาก<nobr><a href="%1">%1</a></nobr>สำเร็จแล้ว และถูกบันทึกไว้เป็น <nobr><b>%2</b></nobr></p><p>คุณต้องการลงทะเบียนไฟล์ดิสก์อิมเมจนี้และใส่ลงในไดรฟ์ออปติคัลเสมือนหรือไม่</p></translation>
+ </message>
+ <message>
+ <source>Bad password or authentication failure.</source>
+ <translation>รหัสผ่านไม่ถูกต้องหรือการพิสูจน์ตัวตนล้มเหลว</translation>
+ </message>
+ <message>
+ <source><p>A critical error has occurred while running the virtual machine and the machine execution has been stopped.</p><p>For help, please see the Community section on <a href=https://www.virtualbox.org>https://www.virtualbox.org</a> or your support contract. Please provide the contents of the log file <tt>VBox.log</tt> and the image file <tt>VBox.png</tt>, which you can find in the <nobr><b>%1</b></nob [...]
+ <translation><p>เกิดความผิดพลาดร้ายแรงขณะเวอร์ชวลแมชชีนกำลังทำงาน และการประมวลผลถูกหยุดไว้</p><p>หากต้องการความช่วยเหลือ โปรดดูได้จากส่วน Community บน <a href=https://www.virtualbox.org>https://www.virtualbox.org</a> หรือติดต่อคู่สัญญาสนับสนุนทางเทคนิคของคุณ โปรดให้ข้อมูลจากล็อกไฟล์ <tt>VBox.log</tt> และไฟล์รูป <tt>VBox.png</tt> ที่คุณจะพบได้จากไดเรกทอรี <nobr><b>%1</b></nobr> พร้อมทั้งอธิบายสิ่งที่คุณท [...]
+ </message>
+ <message>
+ <source><p>A critical error has occurred while running the virtual machine and the machine execution should be stopped.</p><p>For help, please see the Community section on <a href=https://www.virtualbox.org>https://www.virtualbox.org</a> or your support contract. Please provide the contents of the log file <tt>VBox.log</tt>, which you can find in the virtual machine log directory, as well as a description of what you were doing when this [...]
+ <translation><p>เกิดความผิดพลาดร้ายแรงขณะเวอร์ชวลแมชชีนกำลังทำงาน และการประมวลผลควรหยุดลงแล้ว</p><p>หากต้องการความช่วยเหลือ โปรดดูได้จากส่วน Community บน <a href=https://www.virtualbox.org>https://www.virtualbox.org</a> หรือติดต่อคู่สัญญาสนับสนุนทางเทคนิคของคุณ โปรดให้ข้อมูลจากล็อกไฟล์ <tt>VBox.log</tt> ที่คุณจะพบได้จากไดเรกทอรีสำหรับเก็บล็อกของเวอร์ชวลบอกซ์ พร้อมทั้งอธิบายสิ่งที่คุณทำอยู่ขณะเกิดความผิดพลาดนี้ขึ้น โปรดทราบว่าคุณสามารถเข้า [...]
+ </message>
+ <message>
+ <source><p>A new version of VirtualBox has been released! Version <b>%1</b> is available at <a href="https://www.virtualbox.org/">virtualbox.org</a>.</p><p>You can download this version using the link:</p><p><a href=%2>%3</a></p></source>
+ <translation><p>เวอร์ชวลบอกซ์รุ่นใหม่ออกแล้ว! รุ่น <b>%1</b> พร้อมใช้งานแล้วที่ <a href="https://www.virtualbox.org/">virtualbox.org</a></p><p>คุณสามารถดาวน์โหลดรุ่นนี้ได้จากลิงค์:</p><p><a href=%2>%3</a></p></translation>
+ </message>
+ <message>
+ <source>Drag and drop operation from host to guest failed.</source>
+ <translation>เกิดความล้มเหลวในการลากแล้วปล่อยจากโฮสต์ไปเกสต์</translation>
+ </message>
+ <message>
+ <source>Unable to cancel host to guest drag and drop operation.</source>
+ <translation>ไม่สามารถยกเลิกการลากแล้วปล่อยจากโฮสต์ไปเกสต์ได้</translation>
+ </message>
+ <message>
+ <source>Drag and drop operation from guest to host failed.</source>
+ <translation>เกิดความล้มเหลวในการลากแล้วปล่อยจากเกสต์ไปโฮสต์</translation>
+ </message>
+ <message>
+ <source>Failed to connect the network adapter cable of the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถเชื่อมต่อเคเบิลแผงวงจรเครือข่ายของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to disconnect the network adapter cable of the virtual machine <b>%1</b>.</source>
+ <translation>ไม่สามารถถอดเคเบิลแผงวงจรเครือข่ายของเวอร์ชวลแมชชีน <b>%1</b> ได้</translation>
+ </message>
+ <message>
+ <source><p>One or more disk image files are not currently accessible. As a result, you will not be able to operate virtual machines that use these files until they become accessible later.</p><p>Press <b>Check</b> to open the Virtual Media Manager window and see which files are inaccessible, or press <b>Ignore</b> to ignore this message.</p></source>
+ <translation><p>ไม่สามารถเข้าถึงไฟล์ดิสก์อิมเมจได้บางไฟล์ ซึ่งจะส่งผลให้เวอร์ชวลแมชชีนที่ใช้ไฟล์เหล่านี้ไม่สามารถทำงานได้จนกว่าจะเข้าถึงไฟล์ดังกล่าวได้อีกครั้ง</p><p>กด <b>ตรวจสอบ</b> เปิดหน้าต่างส่วนจัดการมีเดียเสมือนเพื่อตรวจสอบว่าไม่สามารถเข้าถึงไฟล์ใดได้ หรือกด <b>เพิกเฉย</b> เพื่อปิดข้อความนี้</p></translation>
+ </message>
+ <message>
+ <source><p>Deleting the snapshot will cause the state information saved in it to be lost, and storage data spread over several image files that VirtualBox has created together with the snapshot will be merged into one file. This can be a lengthy process, and the information in the snapshot cannot be recovered.</p></p>Are you sure you want to delete the selected snapshot <b>%1</b>?</p></source>
+ <translation><p>การลบสแนปช็อตจะทำให้สถานะที่บันทึกไว้หายไป และหน่วยเก็บข้อมูลที่เวอร์ชวลบอกซ์สร้างขึ้นพร้อมกับสแนปช็อตและกระจายอยู่ในหลาย ๆ ไฟล์ จะถูกรวมเข้าเป็นไฟล์เดียว กระบวนการนี้อาจใช้เวลานาน และข้อมูลในสแนปช็อตจะไม่สามารถกู้คืนได้</p></p>แน่ใจหรือไม่ว่าคุณต้องการลบสแนปช็อต <b>%1</b>?</p></translation>
+ </message>
+ <message>
+ <source><p>Deleting the snapshot %1 will temporarily need more storage space. In the worst case the size of image %2 will grow by %3, however on this filesystem there is only %4 free.</p><p>Running out of storage space during the merge operation can result in corruption of the image and the VM configuration, i.e. loss of the VM and its data.</p><p>You may continue with deleting the snapshot at your own risk.</p></source>
+ <translation><p>การลบสแนปช็อต %1 ต้องการใช้พื้นที่เก็บข้อมูลเพิ่มเติมชั่วคราว ในกรณีเลวร้ายที่สุด ขนาดของอิมเมจ %2 จะเพิ่มขึ้นอีก %3 แต่ขณะนี้ระบบไฟล์มีพื้นที่ว่างเพียง %4 เท่านั้น</p><p>การมีพื้นที่ไม่เพียงพอขณะดำเนินการรวมไฟล์อาจส่งผลให้เกิดความเสียหายต่ออิมเมจหรือการตั้งค่า VM ซึ่งอาจเสีย VM หรือข้อมูลไปได้</p><p>คุณอาจดำเนินการลบสแนปช็อตต่อไปหากคุณยอมรับความเสี่ยงนี้ได้</p></translation>
+ </message>
+ <message>
+ <source><p>Are you sure you want to release the disk image file <nobr><b>%1</b></nobr>?</p><p>This will detach it from the following virtual machine(s): <b>%2</b>.</p></source>
+ <translation><p>แน่ใจหรือไม่ว่าคุณต้องการปล่อยไฟล์ดิสก์อิมเมจ <nobr><b>%1</b></nobr>?</p><p>นี่จะเป็นการถอนไฟล์นี้ออกจากเวอร์ชวลแมชชีนต่อไปนี้: <b>%2</b></p></translation>
+ </message>
+ <message>
+ <source><p>Do you want to delete the storage unit of the virtual hard disk <nobr><b>%1</b></nobr>?</p><p>If you select <b>Delete</b> then the specified storage unit will be permanently deleted. This operation <b>cannot be undone</b>.</p><p>If you select <b>Keep</b> then the hard disk will be only removed from the list of known hard disks, but the storage unit will be left untouched which mak [...]
+ <translation><p>คุณต้องการลบหน่วยเก็บข้อมูลของฮาร์ดดิสก์เสมือน <nobr><b>%1</b></nobr> หรือไม่?</p><p>หากคุณเลือก <b>ลบ</b> หน่วยบันทึกข้อมูลที่ระบุจะถูกลบอย่างถาวร กระบวนการนี้<b>ไม่สามารถเลิกทำได้</b></p><p>หากคุณเลือก <b>เก็บไว้</b> ฮาร์ดดิสก์จะถูกนำออกจากรายการฮาร์ดดิสก์ที่รู้จัก แต่หน่วยเก็บข้อมูลจะถูกคงไว้ดังเดิม ทำให้สามารถเพิ่มฮาร์ดดิสก์นี้กลับไปยังรายการได้อีกในภายหลัง</p></tra [...]
+ </message>
+ <message>
+ <source>Failed to open the disk image file <nobr><b>%1</b></nobr>.</source>
+ <translation>ไม่สามารถเปิดไฟล์ดิสก์อิมเมจ <nobr><b>%1</b></nobr> ได้</translation>
+ </message>
+ <message>
+ <source>Failed to close the disk image file <nobr><b>%1</b></nobr>.</source>
+ <translation>ไม่สามารถปิดไฟล์ดิสก์อิมเมจ <nobr><b>%1</b></nobr> ได้</translation>
+ </message>
+ <message>
+ <source>You are about to create a new virtual machine without a hard disk. You will not be able to install an operating system on the machine until you add one. In the mean time you will only be able to start the machine using a virtual optical disk or from the network.</source>
+ <translation>คุณกำลังจะสร้างเวอร์ชวลแมชชีนใหม่ที่ไม่มีฮาร์ดดิสก์ คุณจะไม่สามารถติดตั้งระบบปฏิบัติการลงในเครื่องนี้ได้จนกว่าคุณจะเพิ่มฮาร์ดดิสก์ ขณะนี้คุณจะสามารถเริ่มการทำงานของเครื่องได้โดยใช้ดิสก์ออปติคัลเสมือนหรือเริ่มการทำงานผ่านเครือข่ายเท่านั้น</translation>
+ </message>
+ <message>
+ <source><p>The virtual machine window will be now switched to <b>full-screen</b> mode. You can go back to windowed mode at any time by pressing <b>%1</b>.</p><p>Note that the <i>Host</i> key is currently defined as <b>%2</b>.</p><p>Note that the main menu bar is hidden in full-screen mode. You can access it by pressing <b>Host+Home</b>.</p></source>
+ <translation><p>หน้าต่างเวอร์ชวลแมชชีนกำลังจะสลับไปใช้โหมด<b>เต็มจอ</b> คุณสามารถกลับไปใช้โหมดหน้าต่างได้ทุกเมื่อด้วยการกด <b>%1</b></p><p>โปรดทราบว่าปุ่ม<i>โฮสต์</i>ถูกกำหนดไว้เป็น <b>%2</b></p><p> และแถบเมนูหลักจะถูกซ่อนไว้ขณะอยู่ในโหมดไร้ขอบ คุณสามารถเข้าถึงแถบเมนูได้ด้วยการกดปุ่ม<b>โฮสต์+Home</b></p></translation>
+ </message>
+ <message>
+ <source><p>Could not switch the guest display to full-screen mode due to insufficient guest video memory.</p><p>You should configure the virtual machine to have at least <b>%1</b> of video memory.</p><p>Press <b>Ignore</b> to switch to full-screen mode anyway or press <b>Cancel</b> to cancel the operation.</p></source>
+ <translation><p>ไม่สามารถสลับหน้าจอของเกสต์มาใช้โหมดเต็มจอได้เนื่องจากหน่วยความจำแสดงผลของเกสต์ไม่เพียงพอ</p><p>คุณควรกำหนดให้เวอร์ชวลแมชชีนมีหน่วยความจำแสดงผลอย่างน้อย<b>%1</b></p><p>กด<b>เพิกเฉย</b>เพื่อสลับไปใช้โหมดเต็มจอต่อไป หรือกด<b>ยกเลิก</b>เพื่อยกเลิกการทำงาน</p></translation>
+ </message>
+ <message>
+ <source>Encryption password for <nobr>ID = '%1'</nobr> is invalid.</source>
+ <translation>รหัสผ่านการเข้ารหัสลับสำหรับ <nobr>ID = '%1'</nobr> ไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>The current port forwarding rules are not valid. All of the host or guest address values should be correct or empty.</source>
+ <translation>กฎการส่งต่อพอร์ตที่ใช้อยู่ไม่ถูกต้อง ค่าแอดเดรสของโฮสต์หรือเกสต์ทั้งหมดควรได้รับการแก้ไขหรือปล่อยให้ว่างไว้</translation>
+ </message>
+ <message>
+ <source>The current port forwarding rules are not valid. None of the guest address values may be empty.</source>
+ <translation>กฎการส่งต่อพอร์ตนี้ไม่ถูกต้อง ค่าแอดเดรสของเกสต์ทั้งหมดไม่สามารถเป็นค่าว่างได้</translation>
+ </message>
+ <message>
+ <source><p>Failed to acquire the VirtualBox COM object.</p><p>The application will now terminate.</p></source>
+ <translation><p>ไม่สามารถขอรับอ็อบเจคต์ VirtualBoxClient COM ได้</p><p>แอพพลิเคชันจะยุติการทำงานทันที</p></translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <comment>extension pack</comment>
+ <translation>ลบ</translation>
+ </message>
+ <message>
+ <source>Do you want to delete the downloaded file <nobr><b>%1</b></nobr>?</source>
+ <translation>คุณต้องการลบไฟล์ <nobr><b>%1</b></nobr> ที่ดาวน์โหลดไว้หรือไม่?</translation>
+ </message>
+ <message>
+ <source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
+ <translation>คุณต้องการลบไฟล์ตามรายการต่อไปนี้ <nobr><b>%1</b></nobr> หรือไม่?</translation>
+ </message>
+ <message>
+ <source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
+ <translation><p>สาเหตุของความผิดพลาดนี้อาจเกิดจากการกำหนดสิทธิของดีมอน IPC ไม่ถูกต้องเนื่องจากมีปัญหาในการติดตั้ง โปรดตรวจสอบสิทธิของ <font color=blue>'/tmp'</font> และ <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></translation>
+ </message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>UIMiniToolBar</name>
+ <message>
+ <source>Always show the toolbar</source>
+ <translation>แสดงแถบเครื่องมือเสมอ</translation>
+ </message>
+ <message>
+ <source>Minimize Window</source>
+ <translation>ย่อหน้าต่าง</translation>
+ </message>
+ <message>
+ <source>Exit Full Screen or Seamless Mode</source>
+ <translation>ออกจากโหมดเต็มจอหรือโหมดไร้ขอบ</translation>
+ </message>
+ <message>
+ <source>Close VM</source>
+ <translation>ปิด VM</translation>
+ </message>
+</context>
+<context>
+ <name>UIMultiScreenLayout</name>
+ <message>
+ <source>Virtual Screen %1</source>
+ <translation>หน้าจอเสมือน %1</translation>
+ </message>
+ <message>
+ <source>Use Host Screen %1</source>
+ <translation>ใช้หน้าจอ %1 ของโฮสต์</translation>
+ </message>
+</context>
+<context>
+ <name>UINameAndSystemEditor</name>
+ <message>
+ <source>N&ame:</source>
+ <translation>&ชื่อ:</translation>
+ </message>
+ <message>
+ <source>Holds the name of the virtual machine.</source>
+ <translation>เก็บชื่อของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>&Type:</source>
+ <translation>ช&นิด:</translation>
+ </message>
+ <message>
+ <source>Selects the operating system family that you plan to install into this virtual machine.</source>
+ <translation>เลือกตระกูลของระบบปฏิบัติการที่คุณวางแผนจะติดตั้งในเวอร์ชวลแมชชีนนี้</translation>
+ </message>
+ <message>
+ <source>&Version:</source>
+ <translation>&รุ่น:</translation>
+ </message>
+ <message>
+ <source>Selects the operating system type that you plan to install into this virtual machine (called a guest operating system).</source>
+ <translation>เลือกชนิดของระบบปฏิบัติการที่คุณวางแผนจะติดตั้งในเวอร์ชวลแมชชีนนี้ (เรียกว่าระบบปฏิบัติการเกสต์)</translation>
+ </message>
+ <message>
+ <source>Holds the location of the virtual machine.</source>
+ <translation>เก็บตำแหน่งที่อยู่ของเวอร์ชวลแมชชีน</translation>
+ </message>
+</context>
+<context>
+ <name>UINetworkManagerDialog</name>
+ <message>
+ <source>Network Operations Manager</source>
+ <translation>ตัวจัดการการทำงานของเครือข่าย</translation>
+ </message>
+ <message>
+ <source>There are no active network operations.</source>
+ <translation>ไม่มีกระบวนการทางเครือข่ายที่กำลังทำงานอยู่</translation>
+ </message>
+ <message>
+ <source>&Cancel All</source>
+ <translation>&ยกเลิกทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Cancel all active network operations</source>
+ <translation>ยกเลิกกระบวนการทางเครือข่ายที่กำลังทำงานอยู่ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Network Operation</source>
+ <translation>การทำงานของเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Restart network operation</source>
+ <translation>เริ่มกระบวนการทางเครือข่ายใหม่</translation>
+ </message>
+ <message>
+ <source>Cancel network operation</source>
+ <translation>ยกเลิกกระบวนการทางเครือข่าย</translation>
+ </message>
+ <message>
+ <source>The network operation failed with the following error: %1.</source>
+ <translation>กระบวนการทางเครือข่ายล้มเหลวด้วยความผิดพลาด: %1</translation>
+ </message>
+</context>
+<context>
+ <name>UINetworkManagerIndicator</name>
+ <message>
+ <source>Current network operations:</source>
+ <translation>กระบวนการทางเครือข่ายปัจจุบัน:</translation>
+ </message>
+ <message>
+ <source>failed</source>
+ <comment>network operation</comment>
+ <translation>ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>(%1 of %2)</source>
+ <translation>(%1 จาก %2)</translation>
+ </message>
+ <message>
+ <source>Double-click for more information.</source>
+ <translation>ดับเบิ้ลคลิกเพื่อดูข้อมูลเพิ่มเติม</translation>
+ </message>
+</context>
+<context>
+ <name>UINetworkReplyPrivate</name>
+ <message>
+ <source>Host not found</source>
+ <translation>ไม่พบโฮสต์</translation>
+ </message>
+ <message>
+ <source>Content access denied</source>
+ <translation>ไม่ได้รับอนุญาตให้เข้าถึงเนื้อหา</translation>
+ </message>
+ <message>
+ <source>Protocol failure</source>
+ <translation>โพรโทคอลล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Wrong SSL certificate format</source>
+ <translation>รูปแบบใบรับรอง SSL ไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>SSL authentication failed</source>
+ <translation>การพิสูจน์ตัวตน SSL ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Unknown reason</source>
+ <translation>ไม่ทราบสาเหตุ</translation>
+ </message>
+ <message>
+ <source>%1: %2</source>
+ <comment>Context description: Error description</comment>
+ <translation>%1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to initialize HTTP library</source>
+ <translation>ไม่สามารถเริ่มการทำงานไลบรารี HTTP ได้</translation>
+ </message>
+ <message>
+ <source>Connection refused</source>
+ <translation>ถูกปฏิเสธการเชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>Content moved</source>
+ <translation>เนื้อหาถูกย้ายไปแล้ว</translation>
+ </message>
+ <message>
+ <source>Proxy not found</source>
+ <translation>ไม่พบพรอกซี</translation>
+ </message>
+ <message>
+ <source>Url not found on the server</source>
+ <translation>ไม่พบ Url บนเซอร์ฟเวอร์</translation>
+ </message>
+</context>
+<context>
+ <name>UINetworkReplyPrivateThread</name>
+ <message>
+ <source>During proxy configuration</source>
+ <translation>ระหว่างการตั้งค่าพรอกซี</translation>
+ </message>
+ <message>
+ <source>During certificate downloading</source>
+ <translation>ระหว่างการดาวน์โหลดใบรับรอง</translation>
+ </message>
+ <message>
+ <source>During network request</source>
+ <translation>ระหว่างร้องขอเครือข่าย</translation>
+ </message>
+</context>
+<context>
+ <name>UIPopupCenter</name>
+ <message>
+ <source>Click for full details</source>
+ <translation>คลิกเพื่อแสดงรายละเอียดทั้งหมด</translation>
+ </message>
+</context>
+<context>
+ <name>UIPortForwardingTable</name>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Protocol</source>
+ <translation>โพรโทคอล</translation>
+ </message>
+ <message>
+ <source>Host IP</source>
+ <translation>ไอพีของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Host Port</source>
+ <translation>พอร์ตของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Guest IP</source>
+ <translation>ไอพีของเกสต์</translation>
+ </message>
+ <message>
+ <source>Guest Port</source>
+ <translation>พอร์ตของเกสต์</translation>
+ </message>
+ <message>
+ <source>Contains a list of port forwarding rules.</source>
+ <translation>เก็บรายการของกฎการส่งต่อพอร์ต</translation>
+ </message>
+ <message>
+ <source>Add New Rule</source>
+ <translation>เพิ่มกฎใหม่</translation>
+ </message>
+ <message>
+ <source>Copy Selected Rule</source>
+ <translation>คัดลอกกฎที่เลือก</translation>
+ </message>
+ <message>
+ <source>Remove Selected Rule</source>
+ <translation>นำกฎที่เลือกออก</translation>
+ </message>
+ <message>
+ <source>Adds new port forwarding rule.</source>
+ <translation>เพิ่มกฎการส่งต่อพอร์ต</translation>
+ </message>
+ <message>
+ <source>Copies selected port forwarding rule.</source>
+ <translation>คัดลอกกฎการส่งต่อพอร์ตที่เลือก</translation>
+ </message>
+ <message>
+ <source>Removes selected port forwarding rule.</source>
+ <translation>นำกฎการส่งต่อพอร์ตที่เลือกออก</translation>
+ </message>
+</context>
+<context>
+ <name>UIProgressDialog</name>
+ <message>
+ <source>A few seconds remaining</source>
+ <translation>เหลืออีกไม่กี่วินาที</translation>
+ </message>
+ <message>
+ <source>Canceling...</source>
+ <translation>กำลังยกเลิก...</translation>
+ </message>
+ <message>
+ <source>&Cancel</source>
+ <translation>&ยกเลิก</translation>
+ </message>
+ <message>
+ <source>Cancel the current operation</source>
+ <translation>ยกเลิกกระบวนการปัจจุบัน</translation>
+ </message>
+ <message>
+ <source>%1, %2 remaining</source>
+ <comment>You may wish to translate this more like "Time remaining: %1, %2"</comment>
+ <translation>เหลืออีก: %1, %2</translation>
+ </message>
+ <message>
+ <source>%1 remaining</source>
+ <comment>You may wish to translate this more like "Time remaining: %1"</comment>
+ <translation>เหลืออีก %1</translation>
+ </message>
+</context>
+<context>
+ <name>UISelectorWindow</name>
+ <message>
+ <source>Show Toolbar</source>
+ <translation>แสดงแถบเครื่องมือ</translation>
+ </message>
+ <message>
+ <source>Show Statusbar</source>
+ <translation>แสดงแถบสถานะ</translation>
+ </message>
+ <message>
+ <source>Select a virtual machine file</source>
+ <translation>เลือกไฟล์เวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Virtual machine files (%1)</source>
+ <translation>ไฟล์เวอร์ชวลแมชชีน (%1)</translation>
+ </message>
+ <message>
+ <source>Manager</source>
+ <comment>Note: main window title which is pretended by the product name.</comment>
+ <translation>ส่วนจัดการ</translation>
+ </message>
+ <message>
+ <source><h3>Welcome to VirtualBox!</h3><p>The left part of this window is a list of all virtual machines on your computer. The list is empty now because you haven't created any virtual machines yet.<img src=:/welcome.png align=right/></p><p>In order to create a new virtual machine, press the <b>New</b> button in the main tool bar located at the top of the window.</p><p>You can press the <b>%1</b> key to [...]
+ <translation><h3>ยินดีต้อนรับสู่เวอร์ชวลบอกซ์!</h3><p>ด้านซ้ายของหน้าต่างนี้แสดงรายการเวอร์ชวลแมชชีนบนเครื่องคอมพิวเตอร์ของคุณ ขณะนี้รายการยังว่างอยู่เพราะคุณยังไม่ได้สร้างเวอร์ชวลแมชชีน<img src=:/welcome.png align=right/></p><p>ในการสร้างเวอร์ชวลแมชชีน ให้กดปุ่ม<b>สร้าง</b> บนแถบเครื่องมือหลักที่แสดงอยู่ด้านบนของหน้าต่าง</p><p>คุณสามารถกดปุ่ม <b>%1</b> เพื่อรับความช่วยเหลือได้ทันที, หรือไปที่ <a href=http [...]
+ </message>
+</context>
+<context>
+ <name>UISession</name>
+ <message>
+ <source>Updating Guest Additions</source>
+ <translation>กำลังอัพเดตโปรแกรมเสริมสำหรับเกสต์</translation>
+ </message>
+</context>
+<context>
+ <name>UISettingsDialog</name>
+ <message>
+ <source><i>Select a settings category from the list on the left-hand side and move the mouse over a settings item to get more information.</i></source>
+ <translation><i>เลือกประเภทการตั้งค่าจากรายการทางซ้ายมือ และวางเมาส์เหนือค่าต่าง ๆ เพื่อดูรายละเอียดเพิ่มเติม</i></translation>
+ </message>
+ <message>
+ <source>Invalid settings detected</source>
+ <translation>ตรวจพบการตั้งค่าผิดพลาด</translation>
+ </message>
+ <message>
+ <source><b>%1</b> page:</source>
+ <translation>หน้า <b>%1</b>:</translation>
+ </message>
+ <message>
+ <source><b>%1: %2</b> page:</source>
+ <translation>หน้า <b>%1: %2</b>:</translation>
+ </message>
+</context>
+<context>
+ <name>UISettingsDialogGlobal</name>
+ <message>
+ <source>General</source>
+ <translation>ทั่วไป</translation>
+ </message>
+ <message>
+ <source>Input</source>
+ <translation>อินพุต</translation>
+ </message>
+ <message>
+ <source>Update</source>
+ <translation>อัพเดต</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>ภาษา</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Extensions</source>
+ <translation>ส่วนขยาย</translation>
+ </message>
+ <message>
+ <source>VirtualBox - %1</source>
+ <translation>เวอร์ชวลบอกซ์ - %1</translation>
+ </message>
+ <message>
+ <source>Proxy</source>
+ <translation>พรอกซี</translation>
+ </message>
+ <message>
+ <source>Display</source>
+ <translation>หน่วยแสดงผล</translation>
+ </message>
+ <message>
+ <source>Preferences</source>
+ <translation>ค่าตั้งพึงใจ</translation>
+ </message>
+</context>
+<context>
+ <name>UISettingsDialogMachine</name>
+ <message>
+ <source>General</source>
+ <translation>ทั่วไป</translation>
+ </message>
+ <message>
+ <source>System</source>
+ <translation>ระบบ</translation>
+ </message>
+ <message>
+ <source>Display</source>
+ <translation>หน่วยแสดงผล</translation>
+ </message>
+ <message>
+ <source>Storage</source>
+ <translation>หน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Audio</source>
+ <translation>เสียง</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Ports</source>
+ <translation>พอร์ต</translation>
+ </message>
+ <message>
+ <source>Serial Ports</source>
+ <translation>พอร์ตอนุกรม</translation>
+ </message>
+ <message>
+ <source>Parallel Ports</source>
+ <translation>พอร์ตขนาน</translation>
+ </message>
+ <message>
+ <source>USB</source>
+ <translation>USB</translation>
+ </message>
+ <message>
+ <source>Shared Folders</source>
+ <translation>โฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>%1 - %2</source>
+ <translation>%1 - %2</translation>
+ </message>
+ <message>
+ <source>User Interface</source>
+ <translation>ส่วนติดต่อผู้ใช้</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>การตั้งค่า</translation>
+ </message>
+</context>
+<context>
+ <name>UISettingsSerializerProgress</name>
+ <message>
+ <source>Loading Settings...</source>
+ <translation>กำลังโหลดค่าที่ตั้งไว้...</translation>
+ </message>
+ <message>
+ <source>Saving Settings...</source>
+ <translation>กำลังบันทึกค่าที่ตั้งไว้...</translation>
+ </message>
+</context>
+<context>
+ <name>UIStatusBarEditorWidget</name>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Enable Status Bar</source>
+ <translation>เปิดใช้แถบสถานะ</translation>
+ </message>
+ <message>
+ <source><nobr><b>Click</b> to toggle indicator presence.</nobr><br><nobr><b>Drag&Drop</b> to change indicator position.</nobr></source>
+ <translation><nobr><b>คลิก</b>เพื่อเปิดหรือปิดสถานะตัวบ่งชี้</nobr><br><nobr><b>&ลากแล้วปล่อย</b>เพื่อย้ายตำแหน่งตัวบ่งชี้</nobr></translation>
+ </message>
+</context>
+<context>
+ <name>UITextEditor</name>
+ <message>
+ <source>Edit text</source>
+ <translation>แก้ไขข้อความ</translation>
+ </message>
+ <message>
+ <source>&Replace...</source>
+ <translation>แ&ทนที่...</translation>
+ </message>
+ <message>
+ <source>Replaces the current text with the content of a file.</source>
+ <translation>แทนที่ข้อความปัจจุบันด้วยเนื้อหาของไฟล์</translation>
+ </message>
+ <message>
+ <source>Text (*.txt);;All (*.*)</source>
+ <translation>ข้อความ (*.txt);;ทั้งหมด (*.*)</translation>
+ </message>
+ <message>
+ <source>Select a file to open...</source>
+ <translation>เลือกไฟล์เพื่อเปิด...</translation>
+ </message>
+</context>
+<context>
+ <name>UIUpdateManager</name>
+ <message>
+ <source>1 day</source>
+ <translation>1 วัน</translation>
+ </message>
+ <message>
+ <source>2 days</source>
+ <translation>2 วัน</translation>
+ </message>
+ <message>
+ <source>3 days</source>
+ <translation>3 วัน</translation>
+ </message>
+ <message>
+ <source>4 days</source>
+ <translation>4 วัน</translation>
+ </message>
+ <message>
+ <source>5 days</source>
+ <translation>5 วัน</translation>
+ </message>
+ <message>
+ <source>6 days</source>
+ <translation>6 วัน</translation>
+ </message>
+ <message>
+ <source>1 week</source>
+ <translation>1 สัปดาห์</translation>
+ </message>
+ <message>
+ <source>2 weeks</source>
+ <translation>2 สัปดาห์</translation>
+ </message>
+ <message>
+ <source>3 weeks</source>
+ <translation>3 สัปดาห์</translation>
+ </message>
+ <message>
+ <source>1 month</source>
+ <translation>1 เดือน</translation>
+ </message>
+ <message>
+ <source>Never</source>
+ <translation>ไม่อัพเดต</translation>
+ </message>
+</context>
+<context>
+ <name>UIUpdateStepVirtualBox</name>
+ <message>
+ <source>Checking for a new VirtualBox version...</source>
+ <translation>ตรวจหาเวอร์ชวลบอกซ์รุ่นใหม่...</translation>
+ </message>
+</context>
+<context>
+ <name>UIVMCloseDialog</name>
+ <message>
+ <source>Close Virtual Machine</source>
+ <translation>ปิดเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>You want to:</source>
+ <translation>คุณต้องการ:</translation>
+ </message>
+ <message>
+ <source><p>Saves the current execution state of the virtual machine to the physical hard disk of the host PC.</p><p>Next time this machine is started, it will be restored from the saved state and continue execution from the same place you saved it at, which will let you continue your work immediately.</p><p>Note that saving the machine state may take a long time, depending on the guest operating system type and the amount of memory you assigned to th [...]
+ <translation><p>บันทึกสถานะปัจจุบันของเวอร์ชวลแมชชีนไปยังฮาร์ดดิสก์ของโฮสต์พีซี </p><p>ครั้งต่อไปที่เปิดเครื่อง เวอร์ชวลแมชชีนจะทำงานต่อจากสถานะที่ถูกบันทึกไว้ ทำให้คุณสามารถทำงานต่อได้ทันที</p><p>โปรดทราบว่าการบันทึกสถานะของเครื่องอาจใช้เวลานานขึ้นอยู่กับชนิดของระบบปฏิบัติการเกสต์ และหน่วยความจำที่คุณกำหนดให้เวอร์ชวลแมชชีนนั้น</p></translation>
+ </message>
+ <message>
+ <source>&Save the machine state</source>
+ <translation>&บันทึกสถานะของเครื่อง</translation>
+ </message>
+ <message>
+ <source><p>Sends the ACPI Power Button press event to the virtual machine.</p><p>Normally, the guest operating system running inside the virtual machine will detect this event and perform a clean shutdown procedure. This is a recommended way to turn off the virtual machine because all applications running inside it will get a chance to save their data and state.</p><p>If the machine doesn't respond to this action then the guest operating system [...]
+ <translation><p>ส่งเหตุการณ์กดปุ่มเพาเวอร์ ACPI ไปยังเวอร์ชวลแมชชีน</p><p>โดยทั่วไป ระบบปฏิบัติการเกสต์ที่ทำงานอยู่ใต้เวอร์ชวลแมชชีนจะรับเหตุการณ์นี้ และเริ่มกระบวนการปิดระบบได้อย่างถูกต้อง นี่เป็นวิธีปิดเวอร์ชวลแมชชีนที่แนะนำให้ใช้เนื่องจากแอพพลิเคชันที่ทำงานอยู่มีโอกาสบันทึกข้อมูลและสถานะการทำงาน</p><p>ถ้าเวอร์ชวลแมชชีนไม่ตอบสนองต่อวิธีนี้ แสดงว่าระบบปฏิบัติการของเกสต์อาจได้รับการติดตั้งอย่างไม่ถูกต้องหรือไม่รู้จักเหตุการณ์กดปุ่มเพาเวอร์ ACPI ในกรณ [...]
+ </message>
+ <message>
+ <source>S&end the shutdown signal</source>
+ <translation>&ส่งคำสั่งชัตดาวน์</translation>
+ </message>
+ <message>
+ <source><p>Turns off the virtual machine.</p><p>Note that this action will stop machine execution immediately so that the guest operating system running inside it will not be able to perform a clean shutdown procedure which may result in <i>data loss</i> inside the virtual machine. Selecting this action is recommended only if the virtual machine does not respond to the <b>Send the shutdown signal</b> action.</p></source>
+ <translation><p>ปิดเวอร์ชวลแมชชีน</p><p>โปรดทราบว่าการกระทำนี้จะยุติการทำงานของเครื่องทันทีแม้ระบบปฏิบัติการของเกสต์ยังทำงานอยู่ ระบบจึงไม่สามารถดำเนินการชัตดาวน์ตามขั้นตอนได้ และอาจทำให้เกิด<i>ข้อมูลสูญหาย</i>ในเวอร์ชวลแมชชีนได้ แนะนำให้ใช้ในกรณีที่เวอร์ชวลแมชชีนไม่ตอบสนองต่อการ<b>ส่งคำสั่งชัตดาวน์</b>เท่านั้น</p></translation>
+ </message>
+ <message>
+ <source>&Power off the machine</source>
+ <translation>&ปิดสวิตซ์เวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Restore the machine state stored in the current snapshot</source>
+ <translation>คืนค่าสถานะของเครื่องที่เก็บไว้ในสแนปช็อตปัจจุบัน</translation>
+ </message>
+ <message>
+ <source><p>When checked, the machine will be returned to the state stored in the current snapshot after it is turned off. This is useful if you are sure that you want to discard the results of your last sessions and start again at that snapshot.</p></source>
+ <translation><p>เลือกที่นี่เพื่อให้เครื่องคืนสู่สถานะที่เก็บไว้ในสแนปช็อตปัจจุบันหลังจากปิดเครื่อง ใช้ในกรณีที่คุณต้องการละทิ้งความเปลี่ยนแปลงที่เกิดขึ้นในเซสชันล่าสุด และต้องการเริ่มการทำงานใหม่จากสแนปช็อตปัจจุบัน</p></translation>
+ </message>
+ <message>
+ <source>&Restore current snapshot '%1'</source>
+ <translation>&คืนค่าจากสแนปช็อตปัจจุบัน '%1'</translation>
+ </message>
+ <message>
+ <source>&Continue running in the background</source>
+ <translation>รัน&ต่อไปโดยทำงานอยู่เบื้องหลัง</translation>
+ </message>
+ <message>
+ <source><p>Close the virtual machine windows but keep the virtual machine running.</p><p>You can use the VirtualBox Manager to return to running the virtual machine in a window.</p></source>
+ <translation><p>ปิดหน้าต่างเวอร์ชวลแมชชีนโดยเวอร์ชวลแมชชีนยังทำงานอยู่</p><p>คุณสามารถใช้ส่วนจัดการเวอร์ชวลบอกซ์เพื่อให้เวอร์ชวลแมชชีนกลับมาแสดงในหน้าต่างอีกครั้ง</p></translation>
+ </message>
+</context>
+<context>
+ <name>UIVMDesktop</name>
+ <message>
+ <source>&Details</source>
+ <translation>&รายละเอียด</translation>
+ </message>
+ <message>
+ <source>&Snapshots</source>
+ <translation>&สแนปช็อต</translation>
+ </message>
+</context>
+<context>
+ <name>UIVMInfoDialog</name>
+ <message>
+ <source>%1 - Session Information</source>
+ <translation>ข้อมูลเซสชัน %1</translation>
+ </message>
+ <message>
+ <source>DMA Transfers</source>
+ <translation>รับส่งแบบ DMA</translation>
+ </message>
+ <message>
+ <source>PIO Transfers</source>
+ <translation>รับส่งแบบ PIO</translation>
+ </message>
+ <message>
+ <source>Data Read</source>
+ <translation>ข้อมูลที่อ่าน</translation>
+ </message>
+ <message>
+ <source>Data Written</source>
+ <translation>ข้อมูลที่เขียน</translation>
+ </message>
+ <message>
+ <source>Data Transmitted</source>
+ <translation>ข้อมูลที่ส่งไป</translation>
+ </message>
+ <message>
+ <source>Data Received</source>
+ <translation>ข้อมูลที่ได้รับ</translation>
+ </message>
+ <message>
+ <source>Runtime Attributes</source>
+ <translation>คุณสมบัติเฉพาะของรุ่นที่ใช้</translation>
+ </message>
+ <message>
+ <source>Screen Resolution</source>
+ <translation>ความละเอียดจอภาพ</translation>
+ </message>
+ <message>
+ <source>Not Detected</source>
+ <comment>guest additions</comment>
+ <translation>ไม่พบ</translation>
+ </message>
+ <message>
+ <source>Not Detected</source>
+ <comment>guest os type</comment>
+ <translation>ไม่พบ</translation>
+ </message>
+ <message>
+ <source>Guest Additions</source>
+ <translation>โปรแกรมเสริมสำหรับเกสต์</translation>
+ </message>
+ <message>
+ <source>Guest OS Type</source>
+ <translation>ชนิดของเกสต์โอเอส</translation>
+ </message>
+ <message>
+ <source>No Network Adapters</source>
+ <translation>ไม่มีแผงวงจรเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Storage Statistics</source>
+ <translation>สถิติหน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>No Storage Devices</source>
+ <translation>ไม่มีหน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Network Statistics</source>
+ <translation>สถิติเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Not Available</source>
+ <comment>details report (VRDE server port)</comment>
+ <translation>ไม่พร้อมใช้งาน</translation>
+ </message>
+ <message>
+ <source>Clipboard Mode</source>
+ <translation>โหมดของคลิปบอร์ด</translation>
+ </message>
+ <message>
+ <source>Configuration &Details</source>
+ <translation>&รายละเอียดการตั้งค่า</translation>
+ </message>
+ <message>
+ <source>&Runtime Information</source>
+ <translation>ข้อมูลของ&รุ่นที่ใช้งาน</translation>
+ </message>
+ <message>
+ <source>VM Uptime</source>
+ <translation>เวลาตั้งแต่เปิด VM</translation>
+ </message>
+ <message>
+ <source>Drag and Drop Mode</source>
+ <translation>โหมดลากแล้วปล่อย</translation>
+ </message>
+</context>
+<context>
+ <name>UIVMInformationDialog</name>
+ <message>
+ <source>%1 - Session Information</source>
+ <translation>รายละเอียดของเซสชัน %1</translation>
+ </message>
+ <message>
+ <source>Configuration &Details</source>
+ <translation>&รายละเอียดการตั้งค่า</translation>
+ </message>
+ <message>
+ <source>&Runtime Information</source>
+ <translation>ข้อมูลของ&รุ่นที่ใช้งาน</translation>
+ </message>
+</context>
+<context>
+ <name>UIVMListView</name>
+ <message>
+ <source>Inaccessible</source>
+ <translation>ไม่สามารถเข้าถึงได้</translation>
+ </message>
+ <message>
+ <source><nobr>%1<br></nobr><nobr>%2 since %3</nobr><br><nobr>Session %4</nobr></source>
+ <comment>VM tooltip (name, last state change, session state)</comment>
+ <translation><nobr>%1<br></nobr><nobr>%2 ตั้งแต่ %3</nobr><br><nobr>เซสชัน %4</nobr></translation>
+ </message>
+ <message>
+ <source><nobr><b>%1</b><br></nobr><nobr>Inaccessible since %2</nobr></source>
+ <comment>Inaccessible VM tooltip (name, last state change)</comment>
+ <translation><nobr><b>%1</b><br></nobr><nobr>ไม่สามารถเข้าถึงได้ตั้งแต่ %2</nobr></translation>
+ </message>
+</context>
+<context>
+ <name>UIVMLogViewer</name>
+ <message>
+ <source>Close the search panel</source>
+ <translation>ปิดหน้าต่างค้นหา</translation>
+ </message>
+ <message>
+ <source>&Find</source>
+ <translation>&ค้นหา</translation>
+ </message>
+ <message>
+ <source>Enter a search string here</source>
+ <translation>ป้อนข้อความเพื่อค้นหาที่นี่</translation>
+ </message>
+ <message>
+ <source>&Previous</source>
+ <translation>&ก่อนหน้า</translation>
+ </message>
+ <message>
+ <source>Search for the previous occurrence of the string</source>
+ <translation>ค้นหาจุดที่พบข้อความก่อนหน้านี้</translation>
+ </message>
+ <message>
+ <source>&Next</source>
+ <translation>&ถัดไป</translation>
+ </message>
+ <message>
+ <source>Search for the next occurrence of the string</source>
+ <translation>ค้นหาจุดที่พบข้อความหลังจากนี้</translation>
+ </message>
+ <message>
+ <source>C&ase Sensitive</source>
+ <translation>&ตัวพิมพ์เล็ก/ใหญ่แตกต่างกัน</translation>
+ </message>
+ <message>
+ <source>Perform case sensitive search (when checked)</source>
+ <translation>ทำการค้นหาแบบตัวพิมพ์เล็กและใหญ่มีความแตกต่างกัน (หากเลือกไว้)</translation>
+ </message>
+ <message>
+ <source>String not found</source>
+ <translation>ไม่พบข้อความที่ระบุ</translation>
+ </message>
+ <message>
+ <source><p>No log files found. Press the <b>Refresh</b> button to rescan the log folder <nobr><b>%1</b></nobr>.</p></source>
+ <translation><p>ไม่พบล็อกไฟล์ กดปุ่ม <b>เรียกซ้ำ</b> เพื่อตรวจสอบโฟลเดอร์เก็บล็อก <nobr><b>%1</b></nobr> อีกครั้ง</p></translation>
+ </message>
+ <message>
+ <source>Save VirtualBox Log As</source>
+ <translation>บันทึกล็อกเวอร์ชวลบอกซ์เป็น</translation>
+ </message>
+ <message>
+ <source>%1 - VirtualBox Log Viewer</source>
+ <translation>ดูล็อกเวอร์ชวลบอกซ์ - %1</translation>
+ </message>
+ <message>
+ <source>&Refresh</source>
+ <translation>เรียก&ซ้ำ</translation>
+ </message>
+ <message>
+ <source>&Save</source>
+ <translation>&บันทึก</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation>ฟิลเตอร์</translation>
+ </message>
+ <message>
+ <source>Enter filtering string here</source>
+ <translation>ป้อนข้อความเพื่อการกรองที่นี่</translation>
+ </message>
+ <message>
+ <source>Fil&ter</source>
+ <translation>ฟิลเ&ตอร์</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizard</name>
+ <message>
+ <source>&Expert Mode</source>
+ <translation>โหมด&ผู้เชี่ยวชาญ</translation>
+ </message>
+ <message>
+ <source>Switch to <nobr><b>Expert Mode</b></nobr>, a one-page dialog for experienced users.</source>
+ <translation>สลับไปใช้<nobr><b>โหมดผู้เชี่ยวชาญ</b></nobr>, ไดอะลอกแบบหน้าเดียวสำหรับผู้ใช้ที่มีความเชี่ยวชาญ</translation>
+ </message>
+ <message>
+ <source>&Guided Mode</source>
+ <translation>โหมดแ&นะนำ</translation>
+ </message>
+ <message>
+ <source>Switch to <nobr><b>Guided Mode</b></nobr>, a step-by-step dialog with detailed explanations.</source>
+ <translation>สลับไปใช้<nobr><b>โหมดแนะนำ</b></nobr>, ไดอะลอกแบบเป็นขั้นตอนพร้อมคำอธิบายโดยละเอียด</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizardCloneVD</name>
+ <message>
+ <source>Copy</source>
+ <translation>คัดลอก</translation>
+ </message>
+ <message>
+ <source>&Dynamically allocated</source>
+ <translation>จัดสรรแบบ&พลวัต</translation>
+ </message>
+ <message>
+ <source>&Fixed size</source>
+ <translation>ขนาด&คงที่</translation>
+ </message>
+ <message>
+ <source>&Split into files of less than 2GB</source>
+ <translation>แ&ยกเป็นไฟล์ที่มีขนาดเล็กกว่า 2GB</translation>
+ </message>
+ <message>
+ <source>%1_copy</source>
+ <comment>copied virtual hard drive name</comment>
+ <translation>%1_สำเนา</translation>
+ </message>
+ <message>
+ <source>Copy Virtual Hard Disk</source>
+ <translation>ทำสำเนาฮาร์ดดิสก์เสมือน</translation>
+ </message>
+ <message>
+ <source>Hard disk to copy</source>
+ <translation>ฮาร์ดดิสก์ที่จะทำสำเนา</translation>
+ </message>
+ <message>
+ <source><p>Please select the virtual hard disk file that you would like to copy if it is not already selected. You can either choose one from the list or use the folder icon beside the list to select one.</p></source>
+ <translation><p>กรุณาเลือกไฟล์ฮาร์ดดิสก์เสมือนที่คุณต้องการทำสำเนาหากยังไม่ได้เลือกไว้ คุณสามารถเลือกจากรายการที่แสดงอยู่หรือใช้ไอคอนโฟลเดอร์ด้านข้างรายการเพื่อเลือกขึ้นมาหนึ่งไฟล์</p></translation>
+ </message>
+ <message>
+ <source>Choose a virtual hard disk file to copy...</source>
+ <translation>เลือกไฟล์ฮาร์ดดิสก์เสมือนเพื่อทำสำเนา...</translation>
+ </message>
+ <message>
+ <source>Hard disk file type</source>
+ <translation>ชนิดของไฟล์ฮาร์ดดิสก์</translation>
+ </message>
+ <message>
+ <source>Please choose the type of file that you would like to use for the new virtual hard disk. If you do not need to use it with other virtualization software you can leave this setting unchanged.</source>
+ <translation>โปรดเลือกชนิดของไฟล์ที่คุณต้องการใช้สำหรับฮาร์ดดิสก์เสมือนที่จะสร้างขึ้นมาใหม่ หากคุณไม่ต้องการใช้ไฟล์นี้ร่วมกับซอฟต์แวร์เวอร์ชวลไลเซชันอื่น คุณสามารถใช้ค่านี้ได้โดยไม่ต้องเปลี่ยนแปลง</translation>
+ </message>
+ <message>
+ <source>Storage on physical hard disk</source>
+ <translation>สื่อบันทึกบนฮาร์ดดิสก์จริง</translation>
+ </message>
+ <message>
+ <source>Please choose whether the new virtual hard disk file should grow as it is used (dynamically allocated) or if it should be created at its maximum size (fixed size).</source>
+ <translation>โปรดเลือกว่าไฟล์ฮาร์ดดิสก์เวอร์ชวลบอกซ์ควรขยายขนาดตามการใช้งาน (จัดสรรแบบพลวัต) หรือควรสร้างโดยใช้ขนาดสูงสุด (ขนาดคงที่)</translation>
+ </message>
+ <message>
+ <source><p>A <b>dynamically allocated</b> hard disk file will only use space on your physical hard disk as it fills up (up to a maximum <b>fixed size</b>), although it will not shrink again automatically when space on it is freed.</p></source>
+ <translation><p>ฮาร์ดดิสก์ที่<b>จัดสรรแบบพลวัต</b> จะใช้พื้นที่บนฮาร์ดดิสก์กายภาพของคุณเพิ่มขึ้นตามการใช้งาน (จนถึง <b>ขนาดคงที่</b> ที่ระบุไว้) แต่มันจะไม่ลดขนาดลงโดยอัตโนมัติแม้พื้นที่ภายในจะว่างลง</p></translation>
+ </message>
+ <message>
+ <source><p>A <b>fixed size</b> hard disk file may take longer to create on some systems but is often faster to use.</p></source>
+ <translation><p>ไฟล์ฮาร์ดดิสก์ <b>ขนาดคงที่</b> อาจใช้เวลานานในการสร้างบนบางระบบ แต่มักทำงานได้เร็วกว่า</p></translation>
+ </message>
+ <message>
+ <source><p>You can also choose to <b>split</b> the hard disk file into several files of up to two gigabytes each. This is mainly useful if you wish to store the virtual machine on removable USB devices or old systems, some of which cannot handle very large files.</source>
+ <translation><p>คุณสามารถกำหนดให้<b>แบ่ง</b>ไฟล์ฮาร์ดดิสก์ออกเป็นส่วนย่อย ๆ ส่วนละสองกิกะไบต์ การแบ่งเช่นนี้มีประโยชน์หากคุณต้องการเก็บไฟล์เวอร์ชวลแมชชีนไว้บนสื่อบันทึก USB ที่เคลื่อนย้ายได้หรือในเครื่องรุ่นเก่าที่ไม่สามารถรองรับไฟล์ขนาดใหญ่มาก ๆ ได้</translation>
+ </message>
+ <message>
+ <source>Please choose a location for new virtual hard disk file</source>
+ <translation>โปรดเลือกที่ตั้งไฟล์เวอร์ชวลฮาร์ดดิสก์ที่จะสร้างขึ้นใหม่</translation>
+ </message>
+ <message>
+ <source>New hard disk to create</source>
+ <translation>ฮาร์ดดิสก์ใหม่ที่จะสร้าง</translation>
+ </message>
+ <message>
+ <source>Please type the name of the new virtual hard disk file into the box below or click on the folder icon to select a different folder to create the file in.</source>
+ <translation>โปรดป้อนชื่อไฟล์สำหรับฮาร์ดดิสก์เสมือนที่สร้างขึ้นใหม่ลงในกล่องด้านล่าง หรือคลิกไอคอนโฟลเดอร์เพื่อเลือกโฟลเดอร์อื่นสำหรับการสร้างไฟล์</translation>
+ </message>
+ <message>
+ <source>Choose a location for new virtual hard disk file...</source>
+ <translation>เลือกที่ตั้งสำหรับไฟล์เวอร์ชวลฮาร์ดดิสก์ใหม่...</translation>
+ </message>
+ <message>
+ <source>Hard disk to ©</source>
+ <translation>ฮาร์ดดิสก์ที่จะทำ&สำเนา</translation>
+ </message>
+ <message>
+ <source>&New hard disk to create</source>
+ <translation>ฮาร์ดดิสก์ให&ม่ที่จะสร้าง</translation>
+ </message>
+ <message>
+ <source>Hard disk file &type</source>
+ <translation>&ชนิดของไฟล์ฮาร์ดดิสก์</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizardCloneVM</name>
+ <message>
+ <source>Linked Base for %1 and %2</source>
+ <translation>ฐานเชื่อมโยงสำหรับ %1 และ %2</translation>
+ </message>
+ <message>
+ <source>Clone Virtual Machine</source>
+ <translation>โคลนเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Clone</source>
+ <translation>โคลน</translation>
+ </message>
+ <message>
+ <source>%1 Clone</source>
+ <translation>%1 โคลน</translation>
+ </message>
+ <message>
+ <source>New machine name</source>
+ <translation>ชื่อเครื่องใหม่</translation>
+ </message>
+ <message>
+ <source><p>Please choose a name for the new virtual machine. The new machine will be a clone of the machine <b>%1</b>.</p></source>
+ <translation><p>โปรดเลือกชื่อสำหรับเวอร์ชวลแมชชีนเครื่องใหม่ เครื่องนี้จะเป็นโคลนของเวอร์ชวลแมชชีน <b>%1</b></p></translation>
+ </message>
+ <message>
+ <source>When checked a new unique MAC address will be assigned to all configured network cards.</source>
+ <translation>เลือกที่นี่หากต้องการกำหนดค่าแมคแอดเดรสใหม่ที่ไม่ซ้ำกันให้กับแผงวงจรเครือข่ายทั้งหมด</translation>
+ </message>
+ <message>
+ <source>&Reinitialize the MAC address of all network cards</source>
+ <translation>&กำหนดค่าแมคแอดเดรสใหม่ให้แผงวงจรเครือข่ายทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Clone type</source>
+ <translation>ชนิดของโคลน</translation>
+ </message>
+ <message>
+ <source><p>If you create a <b>Linked clone</b> then a new snapshot will be created in the original virtual machine as part of the cloning process.</p></source>
+ <translation><p>หากคุณสร้าง <b>โคลนแบบเชื่อมโยง<b> สแนปช็อตจะถูกสร้างขึ้นในเวอร์ชวลแมชชีนต้นฉบับซึ่งเป็นส่วนหนึ่งของกระบวนการโคลนนิ่ง</p></translation>
+ </message>
+ <message>
+ <source>&Full clone</source>
+ <translation>โคลน&ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>&Linked clone</source>
+ <translation>โคลนแบบเ&ชื่อมโยง</translation>
+ </message>
+ <message>
+ <source>Snapshots</source>
+ <translation>สแนปช็อต</translation>
+ </message>
+ <message>
+ <source><p>Please choose which parts of the snapshot tree should be cloned with the machine.</p></source>
+ <translation><p>กรุณาเลือกส่วนของสแนปช็อตทรีที่ต้องการให้โคลนไปพร้อมกับเครื่องนี้</p></translation>
+ </message>
+ <message>
+ <source><p>If you choose <b>Current machine state</b>, the new machine will reflect the current state of the original machine and will have no snapshots.</p></source>
+ <translation><p>หากคุณเลือก<b>สถานะปัจจุบันของเครื่อง</b> เครื่องใหม่จะมีสถานะเหมือนกับสถานะปัจจุบันของเครื่องต้นฉบับและจะไม่มีสแนปช็อต</p></translation>
+ </message>
+ <message>
+ <source><p>If you choose <b>Current snapshot tree branch</b>, the new machine will reflect the current state of the original machine and will have matching snapshots for all snapshots in the tree branch starting at the current state in the original machine.</p></source>
+ <translation><p>หากคุณเลือก<b>สาขาปัจจุบันของสแนปช็อตทรี</b> เครื่องใหม่จะมีสถานะเหมือนกับสถานะปัจจุบันของเครื่องต้นฉบับและจะมีสแนปช็อตทั้งหมดในสาขาของทรีโดยเริ่มจากสถานะปัจจุบันของเครื่องต้นฉบับ</p></translation>
+ </message>
+ <message>
+ <source><p>If you choose <b>Everything</b>, the new machine will reflect the current state of the original machine and will have matching snapshots for all snapshots in the original machine.</p></source>
+ <translation><p>หากคุณเลือก<b>ทุกอย่าง</b> เครื่องใหม่จะมีสถานะเหมือนกับสถานะปัจจุบันของเครื่องต้นฉบับและจะมีสแนปช็อตทั้งหมดเหมือนเครื่องต้นฉบับ</p></translation>
+ </message>
+ <message>
+ <source>Current &machine state</source>
+ <translation>สถานะปัจจุบันของเ&ครื่อง</translation>
+ </message>
+ <message>
+ <source>Current &snapshot tree branch</source>
+ <translation>สาขาปัจจุบันของ&สแนปช็อตทรี</translation>
+ </message>
+ <message>
+ <source>&Everything</source>
+ <translation>&ทุกอย่าง</translation>
+ </message>
+ <message>
+ <source>New machine &name</source>
+ <translation>&ชื่อเครื่องใหม่</translation>
+ </message>
+ <message>
+ <source>&Full Clone</source>
+ <translation>โคลน&ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>&Linked Clone</source>
+ <translation>โคลนแบบเ&ชื่อมโยง</translation>
+ </message>
+ <message>
+ <source><p>Please choose the type of clone you wish to create.</p><p>If you choose <b>Full clone</b>, an exact copy (including all virtual hard disk files) of the original virtual machine will be created.</p><p>If you choose <b>Linked clone</b>, a new machine will be created, but the virtual hard disk files will be tied to the virtual hard disk files of original machine and you will not be able to move the new virtual machine [...]
+ <translation><p>โปรดเลือกชนิดของโคลนที่คุณต้องการสร้าง</p><p>ถ้าคุณเลือก <b>โคลนทั้งหมด</b> สำเนาที่เหมือนกัน (รวมทั้งไฟล์ฮาร์ดดิสก์เสมือน) ของเวอร์ชวลแมชชีนต้นฉบับจะถูกสร้างขึ้น</p><p>หากคุณเลือก <b>โคลนแบบเชื่อมโยง</b> เครื่องใหม่จะถูกสร้างขึ้น แต่ไฟล์ฮาร์ดดิสก์เสมือนจะถูกผูกเข้ากับไฟล์ฮาร์ดดิสก์เสมือนของเครื่องต้นฉบับ และคุณจะไม่สามารถย้ายเครื่องเสมือนไปยังคอมพิวเตอร์เครื่องอื่นได้หากไม่ได้ย้ายเครื่องต้นฉบับไปด้วย</p> [...]
+ </message>
+</context>
+<context>
+ <name>UIWizardExportApp</name>
+ <message>
+ <source>Checking files ...</source>
+ <translation>กำลังตรวจสอบไฟล์...</translation>
+ </message>
+ <message>
+ <source>Removing files ...</source>
+ <translation>กำลังลบไฟล์...</translation>
+ </message>
+ <message>
+ <source>Exporting Appliance ...</source>
+ <translation>กำลังส่งออกแอพพลายแอนซ์...</translation>
+ </message>
+ <message>
+ <source>Export Virtual Appliance</source>
+ <translation>ส่งออกเวอร์ชวลแอพพลายแอนซ์</translation>
+ </message>
+ <message>
+ <source>Restore Defaults</source>
+ <translation>คืนค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source>Export</source>
+ <translation>ส่งออก</translation>
+ </message>
+ <message>
+ <source>Virtual machines to export</source>
+ <translation>เวอร์ชวลแมชชีนที่จะส่งออก</translation>
+ </message>
+ <message>
+ <source><p>Please select the virtual machines that should be added to the appliance. You can select more than one. Please note that these machines have to be turned off before they can be exported.</p></source>
+ <translation><p>กรุณาเลือกเวอร์ชวลแมชชีนที่จะเพิ่มเข้าไปในแอพพลายแอนซ์ คุณสามารถเลือกได้พร้อมกันมากกว่าหนึ่งเครื่อง โปรดทราบว่าคุณต้องปิดเครื่องเหล่านี้ก่อนจึงจะสามารถส่งออกได้</p></translation>
+ </message>
+ <message>
+ <source>Appliance settings</source>
+ <translation>ตั้งค่าแอพพลายแอนซ์</translation>
+ </message>
+ <message>
+ <source>Please choose where to create the virtual appliance. You can create it on your own computer, on the Sun Cloud service or on an S3 storage server.</source>
+ <translation>โปรดเลือกว่าจะสร้างแอพพลายแอนซ์เสมือนไว้ที่ใด คุณสามารถสร้างไว้บนเครื่องคอมพิวเตอร์ของคุณ บนบริการ Sun Cloud หรือสร้างเป็นเซอร์ฟเวอร์ S3</translation>
+ </message>
+ <message>
+ <source>Create on</source>
+ <translation>สร้างบน</translation>
+ </message>
+ <message>
+ <source>&This computer</source>
+ <translation>เ&ครื่องนี้</translation>
+ </message>
+ <message>
+ <source>Sun &Cloud</source>
+ <translation>Sun &Cloud</translation>
+ </message>
+ <message>
+ <source>&Simple Storage System (S3)</source>
+ <translation>&Simple Storage System (S3)</translation>
+ </message>
+ <message>
+ <source>Appliance</source>
+ <translation>แอพพลายแอนซ์</translation>
+ </message>
+ <message>
+ <source>&Username:</source>
+ <translation>ชื่อ&ผู้ใช้:</translation>
+ </message>
+ <message>
+ <source>&Password:</source>
+ <translation>&รหัสผ่าน:</translation>
+ </message>
+ <message>
+ <source>&Hostname:</source>
+ <translation>ชื่อโ&ฮสต์:</translation>
+ </message>
+ <message>
+ <source>&Bucket:</source>
+ <translation>ที่&ฝากข้อมูล:</translation>
+ </message>
+ <message>
+ <source>&File:</source>
+ <translation>ไ&ฟล์:</translation>
+ </message>
+ <message>
+ <source>Open Virtualization Format Archive (%1)</source>
+ <translation>Open Virtualization Format Archive (%1)</translation>
+ </message>
+ <message>
+ <source>Open Virtualization Format (%1)</source>
+ <translation>Open Virtualization Format (%1)</translation>
+ </message>
+ <message>
+ <source>Write in legacy OVF 0.9 format for compatibility with other virtualization products.</source>
+ <translation>บันทึกในรูปแบบเก่า OVF 0.9 ที่คงความเข้ากันได้กับผลิตภัณฑ์เวอร์ชวลไลเซชันอื่น</translation>
+ </message>
+ <message>
+ <source>Create a Manifest file for automatic data integrity checks on import.</source>
+ <translation>สร้างไฟล์รายงานเพื่อรตรวจสอบความถูกต้องของข้อมูลโดยอัตโนมัติขณะนำเข้า</translation>
+ </message>
+ <message>
+ <source>Write &Manifest file</source>
+ <translation>เขียนไฟล์&รายงาน</translation>
+ </message>
+ <message>
+ <source>This is the descriptive information which will be added to the virtual appliance. You can change it by double clicking on individual lines.</source>
+ <translation>นี่คือข้อมูลเชิงบรรยายที่จะเพิ่มเข้าไปในแอพพลายแอนซ์เสมือน คุณสามารถแก้ไขได้ด้วยการดับเบิ้ลคลิกที่แต่ละบรรทัด</translation>
+ </message>
+ <message>
+ <source>Virtual &machines to export</source>
+ <translation>เวอร์ชวลแ&มชชีนที่จะส่งออก</translation>
+ </message>
+ <message>
+ <source>Appliance &settings</source>
+ <translation>&ตั้งค่าแอพพลายแอนซ์</translation>
+ </message>
+ <message>
+ <source>&Destination</source>
+ <translation>&ปลายทาง</translation>
+ </message>
+ <message>
+ <source>&Local Filesystem </source>
+ <translation>ระบบไฟล์บนเ&ครื่องนี้</translation>
+ </message>
+ <message>
+ <source>Storage settings</source>
+ <translation>การตั้งค่าหน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Please choose a file to export the virtual appliance to</source>
+ <translation>โปรดเลือกไฟล์สำหรับส่งออกแอพพลายแอนซ์เสมือน</translation>
+ </message>
+ <message>
+ <source>F&ormat:</source>
+ <translation>&รูปแบบ:</translation>
+ </message>
+ <message>
+ <source>OVF 0.9</source>
+ <translation>OVF 0.9</translation>
+ </message>
+ <message>
+ <source>OVF 1.0</source>
+ <translation>OVF 1.0</translation>
+ </message>
+ <message>
+ <source>OVF 2.0</source>
+ <translation>OVF 2.0</translation>
+ </message>
+ <message>
+ <source>Write in standard OVF 1.0 format.</source>
+ <translation>บันทึกในรูปแบบมาตรฐาน OVF 1.0</translation>
+ </message>
+ <message>
+ <source>Write in new experimental OVF 2.0 format.</source>
+ <translation>บันทึกในรูปแบบทดลอง OVF 2.0</translation>
+ </message>
+ <message>
+ <source>&Storage settings</source>
+ <translation>การตั้งค่าหน่วยเ&ก็บข้อมูล</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizardExportAppPageBasic3</name>
+ <message>
+ <source><p>Please choose a filename to export the OVF/OVA to.</p><p>If you use an <i>ova</i> extension, then all the files will be combined into one Open Virtualization Format Archive.</p><p>If you use an <i>ovf</i> extension, several files will be written separately.</p><p>Other extensions are not allowed.</p></source>
+ <translation><p>โปรดเลือกชื่อไฟล์ที่จะส่งออก OVF/OVA</p><p>หากคุณใช้ส่วนขยาย <i>ova</i> ทุก ๆ ไฟล์จะถูกรวมไว้ใน Open Virtualization Format Archive เพียงไฟล์เดียว</p><p>หากคุณใช้ส่วนขยาย <i>ovf</i> แต่ละไฟล์จะถูกเขียนแยกจากกัน</p><p>ไม่อนุญาตให้ใช้ส่วนขยายอื่นนอกจากนี้</p></translation>
+ </message>
+ <message>
+ <source>Please complete the additional fields like the username, password and the bucket, and provide a filename for the OVF target.</source>
+ <translation>โปรดป้อนข้อมูลในฟิลด์เช่นชื่อผู้ใช้ รหัสผ่าน และที่ฝากข้อมูลให้สมบูรณ์ และระบุชื่อไฟล์ OVF ที่ต้องการ</translation>
+ </message>
+ <message>
+ <source>Please complete the additional fields like the username, password, hostname and the bucket, and provide a filename for the OVF target.</source>
+ <translation>โปรดป้อนข้อมูลในฟิลด์เช่นชื่อผู้ใช้ รหัสผ่าน ชื่อโฮสต์ และที่ฝากข้อมูลให้สมบูรณ์ และระบุชื่อไฟล์ OVF ที่ต้องการ</translation>
+ </message>
+ <message>
+ <source>Choose a file to export the virtual appliance to...</source>
+ <translation>เลือกไฟล์สำหรับส่งออกแอพพลายแอนซ์เสมือน...</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizardExportAppPageExpert</name>
+ <message>
+ <source>Choose a file to export the virtual appliance to...</source>
+ <translation>เลือกไฟล์สำหรับส่งออกแอพพลายแอนซ์เสมือน...</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizardFirstRun</name>
+ <message>
+ <source>Select start-up disk</source>
+ <translation>เลือกดิสก์สำหรับเริ่มการทำงาน</translation>
+ </message>
+ <message>
+ <source>Start</source>
+ <translation>เริ่ม</translation>
+ </message>
+ <message>
+ <source><p>Please select a virtual optical disk file or a physical optical drive containing a disk to start your new virtual machine from.</p><p>The disk should be suitable for starting a computer from and should contain the operating system you wish to install on the virtual machine if you want to do that now. The disk will be ejected from the virtual drive automatically next time you switch the virtual machine off, but you can also do this yourself if needed u [...]
+ <translation><p>โปรดเลือกไฟล์ออปติคัลดิสก์เสมือนหรือไดรฟ์ออปติคัลจริงที่มีดิสก์อยู่เพื่อเริ่มการทำงานเครื่องเสมือนเครื่องใหม่ของคุณ</p><p>ดิสก์นี้ควรเป็นดิสก์ที่สามารถเริ่มการทำงานของคอมพิวเตอร์ได้ และมีระบบปฏิบัติการที่คุณต้องการติดตั้งลงในเวอร์ชวลแมชชีนหากคุณต้องการติดตั้งตอนนี้ ดิสก์จะถูกดีดออกจากไดรฟ์เสมือนโดยอัตโนมัติเมื่อคุณปิดสวิทช์เวอร์ชวลแมชชีน แต่คุณสามารถดีดแผ่นออกได้ด้วยตนเองหากคุณต้องการโดยใช้เมนูอุปกรณ์</p></translation>
+ </message>
+ <message>
+ <source><p>Please select a virtual optical disk file or a physical optical drive containing a disk to start your new virtual machine from.</p><p>The disk should be suitable for starting a computer from. As this virtual machine has no hard drive you will not be able to install an operating system on it at the moment.</p></source>
+ <translation><p>โปรดเลือกไฟล์ออปติคัลดิสก์เสมือนหรือไดรฟ์ออปติคัลจริงที่มีดิสก์อยู่เพื่อเริ่มการทำงานเครื่องเสมือนเครื่องใหม่ของคุณ</p><p>ดิสก์นี้ควรเป็นดิสก์ที่สามารถเริ่มการทำงานของคอมพิวเตอร์ได้ แต่เนื่องจากเวอร์ชวลแมชชีนนี้ไม่มีฮาร์ดไดรฟ์คุณจึงไม่สามารถติดตั้งระบบปฏิบัติการลงเครื่องได้ในตอนนี้</p></translation>
+ </message>
+ <message>
+ <source>Choose a virtual optical disk file...</source>
+ <translation>เลือกไฟล์ออปติคัลดิสก์เสมือน...</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizardImportApp</name>
+ <message>
+ <source>Restore Defaults</source>
+ <translation>คืนค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source>Import</source>
+ <translation>นำเข้า</translation>
+ </message>
+ <message>
+ <source>Appliance to import</source>
+ <translation>แอพพลายแอนซ์ที่จะนำเข้า</translation>
+ </message>
+ <message>
+ <source><p>VirtualBox currently supports importing appliances saved in the Open Virtualization Format (OVF). To continue, select the file to import below.</p></source>
+ <translation><p>เวอร์ชวลบอกซ์รองรับการนำเข้าแอพพลายแอนซ์ในรูปแบบ Open Virtualization Format (OVF) โปรดเลือกไฟล์สำหรับนำเข้าจากด้านล่างเพื่อดำเนินการต่อไป</p></translation>
+ </message>
+ <message>
+ <source>Open Virtualization Format (%1)</source>
+ <translation>Open Virtualization Format (%1)</translation>
+ </message>
+ <message>
+ <source>Appliance settings</source>
+ <translation>ตั้งค่าแอพพลายแอนซ์</translation>
+ </message>
+ <message>
+ <source>These are the virtual machines contained in the appliance and the suggested settings of the imported VirtualBox machines. You can change many of the properties shown by double-clicking on the items and disable others using the check boxes below.</source>
+ <translation>นี่คือรายการเวอร์ชวลแมชชีนที่อยู่ในแอพพลายแอนซ์และการตั้งค่าที่แนะนำสำหรับการนำเข้าเวอร์ชวลแมชชีนของเวอร์ชวลบอกซ์ คุณสามารถแก้ไขคุณสมบัติต่าง ๆ ได้ด้วยการดับเบิ้ลคลิกบนรายการที่ต้องการรวมถึงสามารถปิดรายการอื่น ๆ ด้วยกล่องตัวเลือกด้านล่าง</translation>
+ </message>
+ <message>
+ <source>Import Virtual Appliance</source>
+ <translation>นำเข้าเวอร์ชวลแอพพลายแอนซ์</translation>
+ </message>
+ <message>
+ <source>Choose a virtual appliance file to import...</source>
+ <translation>เลือกไฟล์เวอร์ชวลแอพพลายแอนซ์ที่จะนำเข้า...</translation>
+ </message>
+ <message>
+ <source>Please choose a virtual appliance file to import</source>
+ <translation>โปรดเลือกไฟล์เวอร์ชวลแอพพลายแอนซ์ที่จะนำเข้า</translation>
+ </message>
+ <message>
+ <source>Appliance is not signed</source>
+ <translation>แอพพลายแอนซ์ไม่มีลายเซ็น</translation>
+ </message>
+ <message>
+ <source>Appliance signed by %1 (trusted)</source>
+ <translation>แอพพลายแอนซ์มีลายเซ็นของ %1 (เชื่อถือได้)</translation>
+ </message>
+ <message>
+ <source>Appliance signed by %1 (expired!)</source>
+ <translation>แอพพลายแอนซ์มีลายเซ็นของ %1 (หมดอายุ!)</translation>
+ </message>
+ <message>
+ <source>Unverified signature by %1!</source>
+ <translation>มีลายเซ็นที่ไม่ได้ยืนยันของ %1!</translation>
+ </message>
+ <message>
+ <source>Self signed by %1 (trusted)</source>
+ <translation>เซ็นด้วยตนเองโดย %1 (เชื่อถือได้)</translation>
+ </message>
+ <message>
+ <source>Self signed by %1 (expired!)</source>
+ <translation>เซ็นด้วยตนเองโดย %1 (หมดอายุ!)</translation>
+ </message>
+ <message>
+ <source>Unverified self signed signature by %1!</source>
+ <translation>มีลายเซ็นด้วยตนเองที่ไม่ได้ยืนยันของ %1!</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizardNewVD</name>
+ <message>
+ <source>Create</source>
+ <translation>สร้าง</translation>
+ </message>
+ <message>
+ <source>&Dynamically allocated</source>
+ <translation>จัดสรรแบบ&พลวัต</translation>
+ </message>
+ <message>
+ <source>&Fixed size</source>
+ <translation>ขนาด&คงที่</translation>
+ </message>
+ <message>
+ <source>&Split into files of less than 2GB</source>
+ <translation>แ&บ่งเป็นไฟล์มี่มีขนาดเล็กกว่า 2GB</translation>
+ </message>
+ <message>
+ <source><nobr>%1 (%2 B)</nobr></source>
+ <translation><nobr>%1 (%2 B)</nobr></translation>
+ </message>
+ <message>
+ <source>File location and size</source>
+ <translation>ที่ตั้งและขนาดของไฟล์</translation>
+ </message>
+ <message>
+ <source>File &location</source>
+ <translation>&ที่ตั้งไฟล์</translation>
+ </message>
+ <message>
+ <source>File &size</source>
+ <translation>&ขนาดไฟล์</translation>
+ </message>
+ <message>
+ <source>Create Virtual Hard Disk</source>
+ <translation>สร้างฮาร์ดดิสก์เสมือน</translation>
+ </message>
+ <message>
+ <source>Hard disk file type</source>
+ <translation>ชนิดของไฟล์ฮาร์ดดิสก์</translation>
+ </message>
+ <message>
+ <source>Please choose the type of file that you would like to use for the new virtual hard disk. If you do not need to use it with other virtualization software you can leave this setting unchanged.</source>
+ <translation>โปรดเลือกชนิดของไฟล์ที่คุณต้องการใช้สำหรับฮาร์ดดิสก์เสมือนที่จะสร้างขึ้นมาใหม่ หากคุณไม่ต้องการใช้ไฟล์นี้ร่วมกับซอฟต์แวร์เวอร์ชวลไลเซชันอื่น คุณสามารถใช้ค่านี้ได้โดยไม่ต้องเปลี่ยนแปลง</translation>
+ </message>
+ <message>
+ <source>Storage on physical hard disk</source>
+ <translation>สื่อบันทึกบนฮาร์ดดิสก์จริง</translation>
+ </message>
+ <message>
+ <source>Please choose whether the new virtual hard disk file should grow as it is used (dynamically allocated) or if it should be created at its maximum size (fixed size).</source>
+ <translation>โปรดเลือกว่าไฟล์ฮาร์ดดิสก์เวอร์ชวลบอกซ์ควรขยายขนาดตามการใช้งาน (จัดสรรแบบพลวัต) หรือควรสร้างโดยใช้ขนาดสูงสุด (ขนาดคงที่)</translation>
+ </message>
+ <message>
+ <source><p>A <b>dynamically allocated</b> hard disk file will only use space on your physical hard disk as it fills up (up to a maximum <b>fixed size</b>), although it will not shrink again automatically when space on it is freed.</p></source>
+ <translation><p>ฮาร์ดดิสก์ที่<b>จัดสรรแบบพลวัต</b> จะใช้พื้นที่บนฮาร์ดดิสก์กายภาพของคุณเพิ่มขึ้นตามการใช้งาน (จนถึง <b>ขนาดคงที่</b> ที่ระบุไว้) แต่มันจะไม่ลดขนาดลงโดยอัตโนมัติแม้พื้นที่ภายในจะว่างลง</p></translation>
+ </message>
+ <message>
+ <source><p>A <b>fixed size</b> hard disk file may take longer to create on some systems but is often faster to use.</p></source>
+ <translation><p>ไฟล์ฮาร์ดดิสก์ <b>ขนาดคงที่</b> อาจใช้เวลานานในการสร้างบนบางระบบ แต่มักทำงานได้เร็วกว่า</p></translation>
+ </message>
+ <message>
+ <source><p>You can also choose to <b>split</b> the hard disk file into several files of up to two gigabytes each. This is mainly useful if you wish to store the virtual machine on removable USB devices or old systems, some of which cannot handle very large files.</source>
+ <translation><p>คุณสามารถกำหนดให้<b>แบ่ง</b>ไฟล์ฮาร์ดดิสก์ออกเป็นส่วนย่อย ๆ ส่วนละสองกิกะไบต์ การแบ่งเช่นนี้มีประโยชน์หากคุณต้องการเก็บไฟล์เวอร์ชวลแมชชีนไว้บนสื่อบันทึก USB ที่เคลื่อนย้ายได้หรือในเครื่องรุ่นเก่าที่ไม่สามารถรองรับไฟล์ขนาดใหญ่มาก ๆ ได้</translation>
+ </message>
+ <message>
+ <source>Please type the name of the new virtual hard disk file into the box below or click on the folder icon to select a different folder to create the file in.</source>
+ <translation>โปรดป้อนชื่อไฟล์สำหรับฮาร์ดดิสก์เสมือนที่สร้างขึ้นใหม่ลงในกล่องด้านล่าง หรือคลิกไอคอนโฟลเดอร์เพื่อเลือกโฟลเดอร์อื่นสำหรับการสร้างไฟล์</translation>
+ </message>
+ <message>
+ <source>Choose a location for new virtual hard disk file...</source>
+ <translation>เลือกที่ตั้งสำหรับไฟล์เวอร์ชวลฮาร์ดดิสก์ใหม่...</translation>
+ </message>
+ <message>
+ <source>Select the size of the virtual hard disk in megabytes. This size is the limit on the amount of file data that a virtual machine will be able to store on the hard disk.</source>
+ <translation>เลือกขนาดไฟล์เวอร์ชวลฮาร์ดดิสก์มีหน่วยเป็นเมกะไบต์ ขนาดนี้ถูกใช้เพื่อจำกัดขนาดของข้อมูลที่เวอร์ชวลแมชชีนจะสามารถบันทึกลงในฮาร์ดดิสก์ได้</translation>
+ </message>
+ <message>
+ <source>Hard disk file &type</source>
+ <translation>&ชนิดของไฟล์ฮาร์ดดิสก์</translation>
+ </message>
+</context>
+<context>
+ <name>UIWizardNewVM</name>
+ <message>
+ <source>Create Virtual Machine</source>
+ <translation>สร้างเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Create</source>
+ <translation>สร้าง</translation>
+ </message>
+ <message>
+ <source>Name and operating system</source>
+ <translation>ชื่อและระบบปฏิบัติการ</translation>
+ </message>
+ <message>
+ <source>Please choose a descriptive name for the new virtual machine and select the type of operating system you intend to install on it. The name you choose will be used throughout VirtualBox to identify this machine.</source>
+ <translation>กรุณาเลือกชื่อที่สื่อความหมายถึงเวอร์ชวลแมชชีนของคุณ และเลือกชนิดของระบบปฏิบัติการที่คุณต้องการใช้ ชื่อที่คุณเลือกจะถูกใช้อ้างอิงถึงเวอร์ชวลแมชชีนของคุณในโปรแกรม VirtualBox</translation>
+ </message>
+ <message>
+ <source>Memory size</source>
+ <translation>ขนาดของหน่วยความจำ</translation>
+ </message>
+ <message>
+ <source><p>Select the amount of memory (RAM) in megabytes to be allocated to the virtual machine.</p><p>The recommended memory size is <b>%1</b> MB.</p></source>
+ <translation><p>เลือกขนาดของหน่วยความจำ (แรม) หน่วยเป็นเมกะไบต์ที่ต้องการกำหนดให้เวอร์ชวลแมชชีน </p><p>ขนาดของน่วยความจำที่แนะนำคือ <b>%1</b> MB</p></translation>
+ </message>
+ <message>
+ <source>&Memory size</source>
+ <translation>ขนาด&หน่วยความจำ</translation>
+ </message>
+ <message>
+ <source>Hard disk</source>
+ <translation>ฮาร์ดดิสก์</translation>
+ </message>
+ <message>
+ <source><p>If you wish you can add a virtual hard disk to the new machine. You can either create a new hard disk file or select one from the list or from another location using the folder icon.</p><p>If you need a more complex storage set-up you can skip this step and make the changes to the machine settings once the machine is created.</p><p>The recommended size of the hard disk is <b>%1</b>.</p></source>
+ <translation><p>หากต้องการ คุณสามารถเพิ่มฮาร์ดดิสก์เสมือนให้กับเวอร์ชวลแมชชีน คุณสามารถสร้างไฟล์ฮาร์ดดิสก์เสมือนขึ้นมาใหม่ เลือกไฟล์จากรายการหรือจากที่อื่นได้โดยใช้ไอคอนรูปโฟลเดอร์</p><p>หากคุณต้องการกำหนดสื่อบันทึกที่มีความซับซ้อนกว่านี้ คุณสามารถข้ามขั้นตอนนี้แล้วไปปรับแต่งที่การตั้ังค่าของเครื่องหลังจากเวอร์ชวลแมชชีนถูกสร้างขึ้นมาแล้ว</p><p>ขนาดของฮาร์ดดิสก์ที่แนะนำคือ <b>%1</b></p></translation>
+ </message>
+ <message>
+ <source>&Do not add a virtual hard disk</source>
+ <translation>ไ&ม่ต้องเพิ่มฮาร์ดดิสก์เสมือน</translation>
+ </message>
+ <message>
+ <source>&Create a virtual hard disk now</source>
+ <translation>&สร้างฮาร์ดดิสก์เสมือนขึ้นมาใหม่</translation>
+ </message>
+ <message>
+ <source>&Use an existing virtual hard disk file</source>
+ <translation>ใ&ช้ไฟล์ฮาร์ดดิสก์เสมือนที่มีอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>Choose a virtual hard disk file...</source>
+ <translation>เลือกไฟล์ฮาร์ดดิสก์เสมือน...</translation>
+ </message>
+ <message>
+ <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
+ <translation type="vanished"><p><nobr>เก็บชื่อหรือเส้นทางสัมบูรณ์ไปยังโฟลเดอร์ของเวอร์ชวลแมชชีนที่คุณกำลังจะสร้างขึ้น</nobr></p></translation>
+ </message>
+ <message>
+ <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
+ <translation type="vanished"><p><nobr>คุณกำลังจะสร้างเวอร์ชวลแมชชีนขึ้นในโฟลเดอร์นี้:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ </message>
+</context>
+<context>
+ <name>VBoxAboutDlg</name>
+ <message>
+ <source>VirtualBox - About</source>
+ <translation>เกี่ยวกับเวอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>VirtualBox Graphical User Interface</source>
+ <translation>ส่วนติดต่อผู้ใช้แบบกราฟิกของเวอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>Version %1</source>
+ <translation>รุ่น %1</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxGlobal</name>
+ <message>
+ <source>Unknown device %1:%2</source>
+ <comment>USB device details</comment>
+ <translation>อุปกรณ์ที่ไม่รู้จัก %1: %2</translation>
+ </message>
+ <message>
+ <source><nobr>Vendor ID: %1</nobr><br><nobr>Product ID: %2</nobr><br><nobr>Revision: %3</nobr></source>
+ <comment>USB device tooltip</comment>
+ <translation><nobr>รหัสผู้ผลิต: %1</nobr><br><nobr>รหัสผลิตภัณฑ์: %2</nobr><br><nobr>ครั้งที่แก้ไข: %3</nobr></translation>
+ </message>
+ <message>
+ <source><br><nobr>Serial No. %1</nobr></source>
+ <comment>USB device tooltip</comment>
+ <translation><nobr>เลขลำดับ: %1</nobr></translation>
+ </message>
+ <message>
+ <source><br><nobr>State: %1</nobr></source>
+ <comment>USB device tooltip</comment>
+ <translation><br><nobr>สถานะ: %1</nobr></translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <comment>details report</comment>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>OS Type</source>
+ <comment>details report</comment>
+ <translation>ชนิดของโอเอส</translation>
+ </message>
+ <message>
+ <source>Base Memory</source>
+ <comment>details report</comment>
+ <translation>หน่วยความจำพื้นฐาน</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <comment>details report</comment>
+ <translation>ทั่วไป</translation>
+ </message>
+ <message>
+ <source>Video Memory</source>
+ <comment>details report</comment>
+ <translation>หน่วยความจำแสดงผล</translation>
+ </message>
+ <message>
+ <source>Boot Order</source>
+ <comment>details report</comment>
+ <translation>ลำดับการบูต</translation>
+ </message>
+ <message>
+ <source>ACPI</source>
+ <comment>details report</comment>
+ <translation>ACPI</translation>
+ </message>
+ <message>
+ <source>I/O APIC</source>
+ <comment>details report</comment>
+ <translation>I/O APIC</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (ACPI)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (ACPI)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (I/O APIC)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (I/O APIC)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (audio)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Audio</source>
+ <comment>details report</comment>
+ <translation>เสียง</translation>
+ </message>
+ <message>
+ <source>Adapter %1</source>
+ <comment>details report (network)</comment>
+ <translation>แผงวงจร %1</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (network)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <comment>details report</comment>
+ <translation>เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Device Filters</source>
+ <comment>details report (USB)</comment>
+ <translation>ลบไฟล์ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>%1 (%2 active)</source>
+ <comment>details report (USB)</comment>
+ <translation>%1 (%2 ใช้งานอยู่)</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (USB)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Powered Off</source>
+ <comment>MachineState</comment>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Saved</source>
+ <comment>MachineState</comment>
+ <translation>บันทึกไว้</translation>
+ </message>
+ <message>
+ <source>Aborted</source>
+ <comment>MachineState</comment>
+ <translation>ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Running</source>
+ <comment>MachineState</comment>
+ <translation>กำลังรัน</translation>
+ </message>
+ <message>
+ <source>Paused</source>
+ <comment>MachineState</comment>
+ <translation>หยุดชั่วคราว</translation>
+ </message>
+ <message>
+ <source>Starting</source>
+ <comment>MachineState</comment>
+ <translation>กำลังเริ่ม</translation>
+ </message>
+ <message>
+ <source>Stopping</source>
+ <comment>MachineState</comment>
+ <translation>กำลังหยุด</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <comment>MachineState</comment>
+ <translation>กำลังบันทึก</translation>
+ </message>
+ <message>
+ <source>Restoring</source>
+ <comment>MachineState</comment>
+ <translation>กำลังคืนค่า</translation>
+ </message>
+ <message>
+ <source>Spawning</source>
+ <comment>SessionState</comment>
+ <translation>กำลังแตกแขนง</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <comment>DeviceType</comment>
+ <translation>ไม่มี</translation>
+ </message>
+ <message>
+ <source>Floppy</source>
+ <comment>DeviceType</comment>
+ <translation>ฟลอปปี้</translation>
+ </message>
+ <message>
+ <source>Hard Disk</source>
+ <comment>DeviceType</comment>
+ <translation>ฮาร์ดดิสก์</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <comment>DeviceType</comment>
+ <translation>เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Null Audio Driver</source>
+ <comment>AudioDriverType</comment>
+ <translation>ไดร์เวอร์เสียง Null</translation>
+ </message>
+ <message>
+ <source>Windows Multimedia</source>
+ <comment>AudioDriverType</comment>
+ <translation>วินโดวส์มัลติมีเดีย</translation>
+ </message>
+ <message>
+ <source>OSS Audio Driver</source>
+ <comment>AudioDriverType</comment>
+ <translation>ไดร์เวอร์เสียง OSS</translation>
+ </message>
+ <message>
+ <source>ALSA Audio Driver</source>
+ <comment>AudioDriverType</comment>
+ <translation>ไดร์เวอร์เสียง ALSA</translation>
+ </message>
+ <message>
+ <source>Windows DirectSound</source>
+ <comment>AudioDriverType</comment>
+ <translation>วินโดวส์ไดเรกซาวด์</translation>
+ </message>
+ <message>
+ <source>CoreAudio</source>
+ <comment>AudioDriverType</comment>
+ <translation>คอร์ออดิโอ</translation>
+ </message>
+ <message>
+ <source>Not attached</source>
+ <comment>NetworkAttachmentType</comment>
+ <translation>ไม่ได้เชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>NAT</source>
+ <comment>NetworkAttachmentType</comment>
+ <translation>NAT</translation>
+ </message>
+ <message>
+ <source>Internal Network</source>
+ <comment>NetworkAttachmentType</comment>
+ <translation>เครือข่ายภายใน</translation>
+ </message>
+ <message>
+ <source>Not supported</source>
+ <comment>USBDeviceState</comment>
+ <translation>ไม่รองรับ</translation>
+ </message>
+ <message>
+ <source>Unavailable</source>
+ <comment>USBDeviceState</comment>
+ <translation>ไม่พร้อมใช้งาน</translation>
+ </message>
+ <message>
+ <source>Busy</source>
+ <comment>USBDeviceState</comment>
+ <translation>ไม่ว่าง</translation>
+ </message>
+ <message>
+ <source>Available</source>
+ <comment>USBDeviceState</comment>
+ <translation>พร้อมใช้งาน</translation>
+ </message>
+ <message>
+ <source>Held</source>
+ <comment>USBDeviceState</comment>
+ <translation>จับไว้</translation>
+ </message>
+ <message>
+ <source>Captured</source>
+ <comment>USBDeviceState</comment>
+ <translation>ถูกจับไว้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>ClipboardType</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Host To Guest</source>
+ <comment>ClipboardType</comment>
+ <translation>จากโฮสต์ไปเกสต์</translation>
+ </message>
+ <message>
+ <source>Guest To Host</source>
+ <comment>ClipboardType</comment>
+ <translation>จากเกสต์ไปโฮสต์</translation>
+ </message>
+ <message>
+ <source>Bidirectional</source>
+ <comment>ClipboardType</comment>
+ <translation>สองทิศทาง</translation>
+ </message>
+ <message>
+ <source>Port %1</source>
+ <comment>details report (serial ports)</comment>
+ <translation>พอร์ต %1</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (serial ports)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Serial Ports</source>
+ <comment>details report</comment>
+ <translation>พอร์ตอนุกรม</translation>
+ </message>
+ <message>
+ <source>USB</source>
+ <comment>details report</comment>
+ <translation>USB</translation>
+ </message>
+ <message>
+ <source>Shared Folders</source>
+ <comment>details report (shared folders)</comment>
+ <translation>โฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <comment>details report (shared folders)</comment>
+ <translation>ไม่มี</translation>
+ </message>
+ <message>
+ <source>Shared Folders</source>
+ <comment>details report</comment>
+ <translation>โฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>Disconnected</source>
+ <comment>PortMode</comment>
+ <translation>ไม่ได้เชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>Host Pipe</source>
+ <comment>PortMode</comment>
+ <translation>ท่อของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Host Device</source>
+ <comment>PortMode</comment>
+ <translation>อุปกรณ์ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>User-defined</source>
+ <comment>serial port</comment>
+ <translation>กำหนดโดยผู้ใช้</translation>
+ </message>
+ <message>
+ <source>VT-x/AMD-V</source>
+ <comment>details report</comment>
+ <translation>VT-x/AMD-V</translation>
+ </message>
+ <message>
+ <source>PAE/NX</source>
+ <comment>details report</comment>
+ <translation>PAE/NX</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (VT-x/AMD-V)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (VT-x/AMD-V)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (PAE/NX)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (PAE/NX)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Host Driver</source>
+ <comment>details report (audio)</comment>
+ <translation>ไดร์เวอร์ของโฮสต์</translation>
+ </message>
+ <message>
+ <source>Controller</source>
+ <comment>details report (audio)</comment>
+ <translation>ตัวควบคุม</translation>
+ </message>
+ <message>
+ <source>Port %1</source>
+ <comment>details report (parallel ports)</comment>
+ <translation>พอร์ต %1</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (parallel ports)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Parallel Ports</source>
+ <comment>details report</comment>
+ <translation>พอร์ตขนาน</translation>
+ </message>
+ <message>
+ <source>USB</source>
+ <comment>DeviceType</comment>
+ <translation>USB</translation>
+ </message>
+ <message>
+ <source>Shared Folder</source>
+ <comment>DeviceType</comment>
+ <translation>โฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>IDE</source>
+ <comment>StorageBus</comment>
+ <translation>IDE</translation>
+ </message>
+ <message>
+ <source>SATA</source>
+ <comment>StorageBus</comment>
+ <translation>SATA</translation>
+ </message>
+ <message>
+ <source>Solaris Audio</source>
+ <comment>AudioDriverType</comment>
+ <translation>โซลาริสออดิโอ</translation>
+ </message>
+ <message>
+ <source>PulseAudio</source>
+ <comment>AudioDriverType</comment>
+ <translation>พัลส์ออดิโอ</translation>
+ </message>
+ <message>
+ <source>ICH AC97</source>
+ <comment>AudioControllerType</comment>
+ <translation>ICH AC97</translation>
+ </message>
+ <message>
+ <source>SoundBlaster 16</source>
+ <comment>AudioControllerType</comment>
+ <translation>ซาวด์บลาสเตอร์ 16</translation>
+ </message>
+ <message>
+ <source>PCnet-PCI II (Am79C970A)</source>
+ <comment>NetworkAdapterType</comment>
+ <translation>PCnet-PCI II (Am79C970A)</translation>
+ </message>
+ <message>
+ <source>PCnet-FAST III (Am79C973)</source>
+ <comment>NetworkAdapterType</comment>
+ <translation>PCnet-FAST III (Am79C973)</translation>
+ </message>
+ <message>
+ <source>Intel PRO/1000 MT Desktop (82540EM)</source>
+ <comment>NetworkAdapterType</comment>
+ <translation>Intel PRO/1000 MT Desktop (82540EM)</translation>
+ </message>
+ <message>
+ <source>Intel PRO/1000 T Server (82543GC)</source>
+ <comment>NetworkAdapterType</comment>
+ <translation>Intel PRO/1000 T Server (82543GC)</translation>
+ </message>
+ <message>
+ <source><nobr>Vendor ID: %1</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>รหัสผู้ผลิต: %1</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Product ID: %2</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>รหัสผลิตภัณฑ์: %2</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Revision: %3</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>ครั้งที่แก้ไข: %3</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Product: %4</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>ผลิตภัณฑ์: %4</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Manufacturer: %5</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>ผู้ผลิต: %5</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Serial No.: %1</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>เลขลำดับ: %1</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>Port: %1</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>พอร์ต: %1</nobr></translation>
+ </message>
+ <message>
+ <source><nobr>State: %1</nobr></source>
+ <comment>USB filter tooltip</comment>
+ <translation><nobr>สถานะ: %1</nobr></translation>
+ </message>
+ <message>
+ <source>Checking...</source>
+ <comment>medium</comment>
+ <translation>กำลังตรวจสอบ...</translation>
+ </message>
+ <message>
+ <source>Inaccessible</source>
+ <comment>medium</comment>
+ <translation>ไม่สามารถเข้าถึงได้</translation>
+ </message>
+ <message>
+ <source>3D Acceleration</source>
+ <comment>details report</comment>
+ <translation>ตัวเร่งความเร็ว 3D</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (3D Acceleration)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (3D Acceleration)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Setting Up</source>
+ <comment>MachineState</comment>
+ <translation>กำลังตั้งค่า</translation>
+ </message>
+ <message>
+ <source>Differencing</source>
+ <comment>DiskType</comment>
+ <translation>ความแตกต่าง</translation>
+ </message>
+ <message>
+ <source>Nested Paging</source>
+ <comment>details report</comment>
+ <translation>การแบ่งหน้าซ้อนกัน</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (Nested Paging)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (Nested Paging)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Internal network, '%1'</source>
+ <comment>details report (network)</comment>
+ <translation>เครือข่ายภายใน, '%1'</translation>
+ </message>
+ <message>
+ <source>SCSI</source>
+ <comment>StorageBus</comment>
+ <translation>SCSI</translation>
+ </message>
+ <message>
+ <source>PIIX3</source>
+ <comment>StorageControllerType</comment>
+ <translation>PIIX3</translation>
+ </message>
+ <message>
+ <source>PIIX4</source>
+ <comment>StorageControllerType</comment>
+ <translation>PIIX4</translation>
+ </message>
+ <message>
+ <source>ICH6</source>
+ <comment>StorageControllerType</comment>
+ <translation>ICH6</translation>
+ </message>
+ <message>
+ <source>AHCI</source>
+ <comment>StorageControllerType</comment>
+ <translation>AHCI</translation>
+ </message>
+ <message>
+ <source>Lsilogic</source>
+ <comment>StorageControllerType</comment>
+ <translation>Lsilogic</translation>
+ </message>
+ <message>
+ <source>BusLogic</source>
+ <comment>StorageControllerType</comment>
+ <translation>BusLogic</translation>
+ </message>
+ <message>
+ <source>Bridged adapter, %1</source>
+ <comment>details report (network)</comment>
+ <translation>แผงวงจรแบบบริดจ์, %1</translation>
+ </message>
+ <message>
+ <source>Host-only adapter, '%1'</source>
+ <comment>details report (network)</comment>
+ <translation>แผงวงจรเฉพาะโฮสต์, %1</translation>
+ </message>
+ <message>
+ <source>Intel PRO/1000 MT Server (82545EM)</source>
+ <comment>NetworkAdapterType</comment>
+ <translation>Intel PRO/1000 MT Server (82545EM)</translation>
+ </message>
+ <message>
+ <source>Bridged Adapter</source>
+ <comment>NetworkAttachmentType</comment>
+ <translation>แผงวงจรแบบบริดจ์</translation>
+ </message>
+ <message>
+ <source>Host-only Adapter</source>
+ <comment>NetworkAttachmentType</comment>
+ <translation>แผงวงจรเฉพาะโฮสต์</translation>
+ </message>
+ <message>
+ <source><nobr>%1 MB</nobr></source>
+ <comment>details report</comment>
+ <translation><nobr>%1 MB</nobr></translation>
+ </message>
+ <message>
+ <source>Processor(s)</source>
+ <comment>details report</comment>
+ <translation>โปรเซสเซอร์</translation>
+ </message>
+ <message>
+ <source><nobr>%1</nobr></source>
+ <comment>details report</comment>
+ <translation><nobr>%1</nobr></translation>
+ </message>
+ <message>
+ <source>System</source>
+ <comment>details report</comment>
+ <translation>ระบบ</translation>
+ </message>
+ <message>
+ <source>Display</source>
+ <comment>details report</comment>
+ <translation>หน่วยแสดงผล</translation>
+ </message>
+ <message>
+ <source>Raw File</source>
+ <comment>PortMode</comment>
+ <translation>ไฟล์ดิบ</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <comment>details report (2D Video Acceleration)</comment>
+ <translation>ใช้</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (2D Video Acceleration)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>2D Video Acceleration</source>
+ <comment>details report</comment>
+ <translation>ตัวเร่งความเร็วในการแสดงผล 2D</translation>
+ </message>
+ <message>
+ <source>Not Attached</source>
+ <comment>details report (Storage)</comment>
+ <translation>ไม่ได้เชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>Storage</source>
+ <comment>details report</comment>
+ <translation>หน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Teleported</source>
+ <comment>MachineState</comment>
+ <translation>เคลื่อนย้ายแล้ว</translation>
+ </message>
+ <message>
+ <source>Guru Meditation</source>
+ <comment>MachineState</comment>
+ <translation>กูรูเข้าฌาน</translation>
+ </message>
+ <message>
+ <source>Teleporting</source>
+ <comment>MachineState</comment>
+ <translation>กำลังเคลื่อนย้าย</translation>
+ </message>
+ <message>
+ <source>Taking Live Snapshot</source>
+ <comment>MachineState</comment>
+ <translation>กำลังเก็บไลฟ์สแนปช็อต</translation>
+ </message>
+ <message>
+ <source>Teleporting Paused VM</source>
+ <comment>MachineState</comment>
+ <translation>กำลังเคลื่อนย้าย VM ที่หยุดการทำงานไว้</translation>
+ </message>
+ <message>
+ <source>Restoring Snapshot</source>
+ <comment>MachineState</comment>
+ <translation>กำลังคืนค่าสแนปช็อต</translation>
+ </message>
+ <message>
+ <source>Deleting Snapshot</source>
+ <comment>MachineState</comment>
+ <translation>กำลังลบสแนปช็อต</translation>
+ </message>
+ <message>
+ <source>Floppy</source>
+ <comment>StorageBus</comment>
+ <translation>ฟลอปปี้</translation>
+ </message>
+ <message>
+ <source>Paravirtualized Network (virtio-net)</source>
+ <comment>NetworkAdapterType</comment>
+ <translation>เครือข่ายพาราเวอร์ชวลไลซ์ (virtio-net)</translation>
+ </message>
+ <message>
+ <source>I82078</source>
+ <comment>StorageControllerType</comment>
+ <translation>I82078</translation>
+ </message>
+ <message>
+ <source>Empty</source>
+ <comment>medium</comment>
+ <translation>ว่าง</translation>
+ </message>
+ <message>
+ <source>Host Drive '%1'</source>
+ <comment>medium</comment>
+ <translation>ไดรฟ์ของโฮสต์ '%1'</translation>
+ </message>
+ <message>
+ <source>Host Drive %1 (%2)</source>
+ <comment>medium</comment>
+ <translation>ไดรฟ์ของโฮสต์ %1 (%2)</translation>
+ </message>
+ <message>
+ <source><p style=white-space:pre>Type (Format): %1 (%2)</p></source>
+ <comment>medium</comment>
+ <translation><p style=white-space:pre>ชนิด (รูปแบบ) %1 (%2)</p></translation>
+ </message>
+ <message>
+ <source><p>Attached to: %1</p></source>
+ <comment>image</comment>
+ <translation><p>เชื่อมต่อกับ: %1</p></translation>
+ </message>
+ <message>
+ <source><i>Not Attached</i></source>
+ <comment>image</comment>
+ <translation><i>ไม่ได้เชื่อมต่อ</i></translation>
+ </message>
+ <message>
+ <source><i>Checking accessibility...</i></source>
+ <comment>medium</comment>
+ <translation><i>กำลังตรวจสอบการเข้าถึง...</i></translation>
+ </message>
+ <message>
+ <source>Failed to check accessibility of disk image files.</source>
+ <comment>medium</comment>
+ <translation>ไม่สามารถตรวจสอบสถานะการเข้าถึงไฟล์ดิสก์อิมเมจได้</translation>
+ </message>
+ <message>
+ <source><b>No disk image file selected</b></source>
+ <comment>medium</comment>
+ <translation><b>ไม่ได้เลือกไฟล์ดิสก์อิมเมจ</b></translation>
+ </message>
+ <message>
+ <source>You can also change this while the machine is running.</source>
+ <translation>คุณสามารถเปลี่ยนแปลงค่านี้ได้ขณะเครื่องกำลังทำงานอยู่</translation>
+ </message>
+ <message>
+ <source><b>No disk image files available</b></source>
+ <comment>medium</comment>
+ <translation><b>ไม่มีไฟล์ดิสก์อิมเมจที่พร้อมใช้งาน</b></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation>
+ <numerusform>%n ปี</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n month(s)</source>
+ <translation>
+ <numerusform>%n เดือน</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation>
+ <numerusform>%n วัน</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation>
+ <numerusform>%n ชั่วโมง</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n minute(s)</source>
+ <translation>
+ <numerusform>%n นาที</numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%n second(s)</source>
+ <translation>
+ <numerusform>%n วินาที</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>Screens</source>
+ <comment>details report</comment>
+ <translation>หน้าจอ</translation>
+ </message>
+ <message>
+ <source>SAS</source>
+ <comment>StorageBus</comment>
+ <translation>SAS</translation>
+ </message>
+ <message>
+ <source>LsiLogic SAS</source>
+ <comment>StorageControllerType</comment>
+ <translation>LsiLogic SAS</translation>
+ </message>
+ <message>
+ <source>B</source>
+ <comment>size suffix Bytes</comment>
+ <translation>B</translation>
+ </message>
+ <message>
+ <source>KB</source>
+ <comment>size suffix KBytes=1024 Bytes</comment>
+ <translation>KB</translation>
+ </message>
+ <message>
+ <source>MB</source>
+ <comment>size suffix MBytes=1024 KBytes</comment>
+ <translation>MB</translation>
+ </message>
+ <message>
+ <source>GB</source>
+ <comment>size suffix GBytes=1024 MBytes</comment>
+ <translation>GB</translation>
+ </message>
+ <message>
+ <source>TB</source>
+ <comment>size suffix TBytes=1024 GBytes</comment>
+ <translation>TB</translation>
+ </message>
+ <message>
+ <source>PB</source>
+ <comment>size suffix PBytes=1024 TBytes</comment>
+ <translation>PB</translation>
+ </message>
+ <message>
+ <source>Nested Paging</source>
+ <translation>การแบ่งหน้าซ้อนกัน</translation>
+ </message>
+ <message>
+ <source>Unknown device</source>
+ <comment>USB device details</comment>
+ <translation>อุปกรณ์ที่ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source>Remote Desktop Server Port</source>
+ <comment>details report (VRDE Server)</comment>
+ <translation>พอร์ตเซอร์ฟเวอร์รีโมตเดสก์ทอป</translation>
+ </message>
+ <message>
+ <source>Remote Desktop Server</source>
+ <comment>details report (VRDE Server)</comment>
+ <translation>เซอร์ฟเวอร์รีโมตเดสก์ทอป</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>details report (VRDE Server)</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>All files (*)</source>
+ <translation>ไฟล์ทั้งหมด (*)</translation>
+ </message>
+ <message>
+ <source>Fault Tolerant Syncing</source>
+ <comment>MachineState</comment>
+ <translation>กำลังประสานเพื่อทนต่อความผิดพร่อง</translation>
+ </message>
+ <message>
+ <source>Unlocked</source>
+ <comment>SessionState</comment>
+ <translation>ไม่ล็อค</translation>
+ </message>
+ <message>
+ <source>Locked</source>
+ <comment>SessionState</comment>
+ <translation>ล็อค</translation>
+ </message>
+ <message>
+ <source>Unlocking</source>
+ <comment>SessionState</comment>
+ <translation>กำลังปลดล็อค</translation>
+ </message>
+ <message>
+ <source>Null</source>
+ <comment>AuthType</comment>
+ <translation>ว่าง</translation>
+ </message>
+ <message>
+ <source>External</source>
+ <comment>AuthType</comment>
+ <translation>ภายนอก</translation>
+ </message>
+ <message>
+ <source>Guest</source>
+ <comment>AuthType</comment>
+ <translation>เกสต์</translation>
+ </message>
+ <message>
+ <source>Intel HD Audio</source>
+ <comment>AudioControllerType</comment>
+ <translation>อินเทล HD ออดิโอ</translation>
+ </message>
+ <message>
+ <source>PIIX3</source>
+ <comment>ChipsetType</comment>
+ <translation>PIIX3</translation>
+ </message>
+ <message>
+ <source>ICH9</source>
+ <comment>ChipsetType</comment>
+ <translation>ICH9</translation>
+ </message>
+ <message>
+ <source>Execution Cap</source>
+ <comment>details report</comment>
+ <translation>จำกัดการประมวลผล</translation>
+ </message>
+ <message>
+ <source><nobr>%1%</nobr></source>
+ <comment>details report</comment>
+ <translation><nobr>%1%</nobr></translation>
+ </message>
+ <message>
+ <source>Generic, '%1'</source>
+ <comment>details report (network)</comment>
+ <translation>ทั่วไป, '%1'</translation>
+ </message>
+ <message>
+ <source>Generic Driver</source>
+ <comment>NetworkAttachmentType</comment>
+ <translation>ไดร์เวอร์ทั่วไป</translation>
+ </message>
+ <message>
+ <source>Adapter %1</source>
+ <translation>แผงวงจร %1</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <comment>DragAndDropType</comment>
+ <translation>ไม่ใช้</translation>
+ </message>
+ <message>
+ <source>Host To Guest</source>
+ <comment>DragAndDropType</comment>
+ <translation>จากโฮสต์ไปเกสต์</translation>
+ </message>
+ <message>
+ <source>Guest To Host</source>
+ <comment>DragAndDropType</comment>
+ <translation>จากเกสต์ไปโฮสต์</translation>
+ </message>
+ <message>
+ <source>Bidirectional</source>
+ <comment>DragAndDropType</comment>
+ <translation>สองทิศทาง</translation>
+ </message>
+ <message>
+ <source>Normal</source>
+ <comment>MediumType</comment>
+ <translation>ปกติ</translation>
+ </message>
+ <message>
+ <source>Immutable</source>
+ <comment>MediumType</comment>
+ <translation>ไม่เปลี่ยนแปลง</translation>
+ </message>
+ <message>
+ <source>Writethrough</source>
+ <comment>MediumType</comment>
+ <translation>เขียนทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Shareable</source>
+ <comment>MediumType</comment>
+ <translation>แชร์ได้</translation>
+ </message>
+ <message>
+ <source>Readonly</source>
+ <comment>MediumType</comment>
+ <translation>อ่านอย่างเดียว</translation>
+ </message>
+ <message>
+ <source>Multi-attach</source>
+ <comment>MediumType</comment>
+ <translation>เชื่อมต่อหลายทาง</translation>
+ </message>
+ <message>
+ <source>Dynamically allocated storage</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลจัดสรรแบบพลวัต</translation>
+ </message>
+ <message>
+ <source>Dynamically allocated differencing storage</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลจัดสรรแบบพลวัตในส่วนที่แตกต่าง</translation>
+ </message>
+ <message>
+ <source>Fixed size storage</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลขนาดคงที่</translation>
+ </message>
+ <message>
+ <source>Dynamically allocated storage split into files of less than 2GB</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลจัดสรรแบบพลวัตแบ่งขนาดไฟล์ให้เล็กกว่า 2GB</translation>
+ </message>
+ <message>
+ <source>Dynamically allocated differencing storage split into files of less than 2GB</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลจัดสรรแบบพลวัตในส่วนที่แตกต่างแบ่งขนาดไฟล์ให้เล็กกว่า 2GB</translation>
+ </message>
+ <message>
+ <source>Fixed size storage split into files of less than 2GB</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลขนาดคงที่แบ่งขนาดไฟล์ให้เล็กกว่า 2GB</translation>
+ </message>
+ <message>
+ <source>Dynamically allocated compressed storage</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลจัดสรรแบบพลวัตและบีบอัดข้อมูล</translation>
+ </message>
+ <message>
+ <source>Dynamically allocated differencing compressed storage</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลจัดสรรแบบพลวัตในส่วนที่แตกต่างและบีบอัดข้อมูล</translation>
+ </message>
+ <message>
+ <source>Fixed size ESX storage</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูล ESX ขนาดคงที่</translation>
+ </message>
+ <message>
+ <source>Fixed size storage on raw disk</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลขนาดคงที่แบบเก็บบนดิสก์โดยตรง</translation>
+ </message>
+ <message>
+ <source>Deny</source>
+ <comment>NetworkAdapterPromiscModePolicy</comment>
+ <translation>ปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>Allow VMs</source>
+ <comment>NetworkAdapterPromiscModePolicy</comment>
+ <translation>อนุญาต VM</translation>
+ </message>
+ <message>
+ <source>Allow All</source>
+ <comment>NetworkAdapterPromiscModePolicy</comment>
+ <translation>อนุญาตทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Ignore</source>
+ <comment>USBDeviceFilterAction</comment>
+ <translation>เพิกเฉย</translation>
+ </message>
+ <message>
+ <source>Hold</source>
+ <comment>USBDeviceFilterAction</comment>
+ <translation>จับ</translation>
+ </message>
+ <message>
+ <source>UDP</source>
+ <comment>NATProtocol</comment>
+ <translation>UDP</translation>
+ </message>
+ <message>
+ <source>TCP</source>
+ <comment>NATProtocol</comment>
+ <translation>TCP</translation>
+ </message>
+ <message>
+ <source>IDE Primary Master</source>
+ <comment>StorageSlot</comment>
+ <translation>IDE ปฐมภูมิหลัก</translation>
+ </message>
+ <message>
+ <source>IDE Primary Slave</source>
+ <comment>StorageSlot</comment>
+ <translation>IDE ปฐมภูมิรอง</translation>
+ </message>
+ <message>
+ <source>IDE Secondary Master</source>
+ <comment>StorageSlot</comment>
+ <translation>IDE ทุติยภูมิหลัก</translation>
+ </message>
+ <message>
+ <source>IDE Secondary Slave</source>
+ <comment>StorageSlot</comment>
+ <translation>IDE ทุติยภูมิรอง</translation>
+ </message>
+ <message>
+ <source>SATA Port %1</source>
+ <comment>StorageSlot</comment>
+ <translation>พอร์ต SATA %1</translation>
+ </message>
+ <message>
+ <source>SCSI Port %1</source>
+ <comment>StorageSlot</comment>
+ <translation>พอร์ต SCSI %1</translation>
+ </message>
+ <message>
+ <source>SAS Port %1</source>
+ <comment>StorageSlot</comment>
+ <translation>พอร์ต SAS %1</translation>
+ </message>
+ <message>
+ <source>Floppy Device %1</source>
+ <comment>StorageSlot</comment>
+ <translation>อุปกรณ์ฟลอปปี้ %1</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <comment>DetailsElementType</comment>
+ <translation>ทั่วไป</translation>
+ </message>
+ <message>
+ <source>Preview</source>
+ <comment>DetailsElementType</comment>
+ <translation>แสดงตัวอย่าง</translation>
+ </message>
+ <message>
+ <source>System</source>
+ <comment>DetailsElementType</comment>
+ <translation>ระบบ</translation>
+ </message>
+ <message>
+ <source>Display</source>
+ <comment>DetailsElementType</comment>
+ <translation>หน่วยแสดงผล</translation>
+ </message>
+ <message>
+ <source>Storage</source>
+ <comment>DetailsElementType</comment>
+ <translation>หน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Audio</source>
+ <comment>DetailsElementType</comment>
+ <translation>เสียง</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <comment>DetailsElementType</comment>
+ <translation>เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Serial ports</source>
+ <comment>DetailsElementType</comment>
+ <translation>พอร์ตอนุกรม</translation>
+ </message>
+ <message>
+ <source>Parallel ports</source>
+ <comment>DetailsElementType</comment>
+ <translation>พอร์ตขนาน</translation>
+ </message>
+ <message>
+ <source>USB</source>
+ <comment>DetailsElementType</comment>
+ <translation>USB</translation>
+ </message>
+ <message>
+ <source>Shared folders</source>
+ <comment>DetailsElementType</comment>
+ <translation>โฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>Description</source>
+ <comment>DetailsElementType</comment>
+ <translation>คำอธิบาย</translation>
+ </message>
+ <message>
+ <source>Please choose a virtual optical disk file</source>
+ <translation>โปรดเลือกไฟล์ออปติคัลดิสก์เสมือน</translation>
+ </message>
+ <message>
+ <source>All virtual optical disk files (%1)</source>
+ <translation>ไฟล์ออปติคัลดิสก์เสมือนทั้งหมด (%1)</translation>
+ </message>
+ <message>
+ <source>Please choose a virtual floppy disk file</source>
+ <translation>โปรดเลือกไฟล์ฟลอปปี้ดิสก์เสมือน</translation>
+ </message>
+ <message>
+ <source>All virtual floppy disk files (%1)</source>
+ <translation>ไฟล์ฟลอปปี้ดิสก์เสมือนทั้งหมด (%1)</translation>
+ </message>
+ <message>
+ <source>VDI (VirtualBox Disk Image)</source>
+ <translation>VDI (VirtualBox Disk Image)</translation>
+ </message>
+ <message>
+ <source>VMDK (Virtual Machine Disk)</source>
+ <translation>VMDK (Virtual Machine Disk)</translation>
+ </message>
+ <message>
+ <source>VHD (Virtual Hard Disk)</source>
+ <translation>VHD (Virtual Hard Disk)</translation>
+ </message>
+ <message>
+ <source>HDD (Parallels Hard Disk)</source>
+ <translation>HDD (Parallels Hard Disk)</translation>
+ </message>
+ <message>
+ <source>QED (QEMU enhanced disk)</source>
+ <translation>QED (QEMU enhanced disk)</translation>
+ </message>
+ <message>
+ <source>QCOW (QEMU Copy-On-Write)</source>
+ <translation>QCOW (QEMU Copy-On-Write)</translation>
+ </message>
+ <message>
+ <source>Unrestricted Execution</source>
+ <comment>details report</comment>
+ <translation>ประมวลผลโดยไม่มีข้อจำกัด</translation>
+ </message>
+ <message>
+ <source>PS/2 Mouse</source>
+ <comment>PointingHIDType</comment>
+ <translation>เมาส์ PS/2</translation>
+ </message>
+ <message>
+ <source>USB Mouse</source>
+ <comment>PointingHIDType</comment>
+ <translation>เมาส์ USB</translation>
+ </message>
+ <message>
+ <source>PS/2 and USB Mouse</source>
+ <comment>PointingHIDType</comment>
+ <translation>เมาส์ PS/2 และ USB</translation>
+ </message>
+ <message>
+ <source>Unrestricted Execution</source>
+ <translation>ประมวลผลโดยไม่มีข้อจำกัด</translation>
+ </message>
+ <message>
+ <source>USB Tablet</source>
+ <comment>PointingHIDType</comment>
+ <translation>แท็บเล็ต USB</translation>
+ </message>
+ <message>
+ <source>USB Multi-Touch Tablet</source>
+ <comment>PointingHIDType</comment>
+ <translation>แท็บเล็ต USB แบบมีหลายจุดสัมผัส</translation>
+ </message>
+ <message>
+ <source>NAT Network</source>
+ <comment>NetworkAttachmentType</comment>
+ <translation>เครือข่าย NAT</translation>
+ </message>
+ <message>
+ <source>NAT network, '%1'</source>
+ <comment>details report (network)</comment>
+ <translation>เครือข่าย NAT %1</translation>
+ </message>
+ <message>
+ <source>You can create or add disk image files in the virtual machine settings.</source>
+ <translation>คุณสามารถสร้างหรือเพิ่มไฟล์ดิสก์อิมเมจได้ในการตั้งค่าเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>USB</source>
+ <comment>StorageControllerType</comment>
+ <translation>USB</translation>
+ </message>
+ <message>
+ <source>USB Port %1</source>
+ <comment>StorageSlot</comment>
+ <translation>พอร์ต USB %1</translation>
+ </message>
+ <message>
+ <source>off</source>
+ <comment>guest monitor status</comment>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Paravirtualization Interface</source>
+ <comment>details report</comment>
+ <translation>ส่วนเชื่อมต่อพาราเวอร์ชวลไลเซชัน</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <comment>ParavirtProvider</comment>
+ <translation>ไม่มี</translation>
+ </message>
+ <message>
+ <source>Default</source>
+ <comment>ParavirtProvider</comment>
+ <translation>ค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source>Legacy</source>
+ <comment>ParavirtProvider</comment>
+ <translation>รุ่นเก่า</translation>
+ </message>
+ <message>
+ <source>Minimal</source>
+ <comment>ParavirtProvider</comment>
+ <translation>ขั้นต่ำ</translation>
+ </message>
+ <message>
+ <source>Hyper-V</source>
+ <comment>ParavirtProvider</comment>
+ <translation>Hyper-V</translation>
+ </message>
+ <message>
+ <source>New dynamically allocated storage</source>
+ <comment>MediumVariant</comment>
+ <translation>หน่วยเก็บข้อมูลจัดสรรแบบพลวัตแบบใหม่</translation>
+ </message>
+ <message>
+ <source>Active</source>
+ <comment>details report (VT-x/AMD-V)</comment>
+ <translation>ใช้งานอยู่</translation>
+ </message>
+ <message>
+ <source>Inactive</source>
+ <comment>details report (VT-x/AMD-V)</comment>
+ <translation>ไม่ได้ใช้งาน</translation>
+ </message>
+ <message>
+ <source>Active</source>
+ <comment>details report (Nested Paging)</comment>
+ <translation>ใช้งานอยู่</translation>
+ </message>
+ <message>
+ <source>Inactive</source>
+ <comment>details report (Nested Paging)</comment>
+ <translation>ไม่ได้ใช้งาน</translation>
+ </message>
+ <message>
+ <source>Active</source>
+ <comment>details report (Unrestricted Execution)</comment>
+ <translation>ใช้งานอยู่</translation>
+ </message>
+ <message>
+ <source>Inactive</source>
+ <comment>details report (Unrestricted Execution)</comment>
+ <translation>ไม่ได้ใช้งาน</translation>
+ </message>
+ <message>
+ <source>Taking Snapshot</source>
+ <comment>MachineState</comment>
+ <translation>กำลังเก็บสแนปช็อต</translation>
+ </message>
+ <message>
+ <source>Taking Online Snapshot</source>
+ <comment>MachineState</comment>
+ <translation>กำลังเก็บสแนปช็อตออนไลน์</translation>
+ </message>
+ <message>
+ <source>KVM</source>
+ <comment>ParavirtProvider</comment>
+ <translation>KVM</translation>
+ </message>
+ <message>
+ <source>Optical</source>
+ <comment>DeviceType</comment>
+ <translation>ออปติคัล</translation>
+ </message>
+ <message>
+ <source>TCP</source>
+ <comment>PortMode</comment>
+ <translation>TCP</translation>
+ </message>
+ <message>
+ <source>OHCI</source>
+ <comment>USBControllerType</comment>
+ <translation>AHCI</translation>
+ </message>
+ <message>
+ <source>EHCI</source>
+ <comment>USBControllerType</comment>
+ <translation>AHCI</translation>
+ </message>
+ <message>
+ <source>xHCI</source>
+ <comment>USBControllerType</comment>
+ <translation>AHCI</translation>
+ </message>
+ <message>
+ <source>User interface</source>
+ <comment>DetailsElementType</comment>
+ <translation>ส่วนติดต่อผู้ใช้</translation>
+ </message>
+ <message>
+ <source>(Optical Drive)</source>
+ <translation>(ไดรฟ์ออปติคัล)</translation>
+ </message>
+ <message>
+ <source>Encrypted</source>
+ <comment>medium</comment>
+ <translation>เข้ารหัสลับไว้</translation>
+ </message>
+ <message>
+ <source>Please choose a virtual hard disk file</source>
+ <translation>โปรดเลือกไฟล์ฮาร์ดดิสก์เสมือน</translation>
+ </message>
+ <message>
+ <source>All virtual hard disk files (%1)</source>
+ <translation>ไฟล์ฮาร์ดดิสก์เสมือนทั้งหมด (%1)</translation>
+ </message>
+ <message>
+ <source>Attaching this hard disk will be performed indirectly using a newly created differencing hard disk.</source>
+ <comment>medium</comment>
+ <translation>ฮาร์ดดิสก์นี้จะถูกเชื่อมต่อโดยอ้อมโดยใช้ฮาร์ดดิสก์แบบเก็บส่วนต่างที่ถูกสร้างขึ้นมาใหม่</translation>
+ </message>
+ <message>
+ <source>Some of the files in this hard disk chain are inaccessible. Please use the Virtual Medium Manager to inspect these files.</source>
+ <comment>medium</comment>
+ <translation>มีบางไฟล์ในห่วงโซ่ของฮาร์ดดิสก์นี้ที่ไม่สามารถเข้าถึงได้ โปรดใช้ส่วนจัดการมีเดียเสมือนเพื่อตรวจสอบไฟล์เหล่านี้</translation>
+ </message>
+ <message>
+ <source>This base hard disk is indirectly attached using the following differencing hard disk:</source>
+ <comment>medium</comment>
+ <translation>ฮาร์ดดิสก์พื้นฐานนี้ถูกเชื่อมต่อโดยอ้อมจากฮาร์ดดิสก์แบบเก็บผลต่างต่อไปนี้:</translation>
+ </message>
+ <message>
+ <source>Please choose a location for new virtual hard disk file</source>
+ <translation>โปรดเลือกที่ตั้งไฟล์เวอร์ชวลฮาร์ดดิสก์ที่จะสร้างขึ้นใหม่</translation>
+ </message>
+ <message>
+ <source>USB</source>
+ <comment>StorageBus</comment>
+ <translation>USB</translation>
+ </message>
+ <message>
+ <source>PCIe</source>
+ <comment>StorageBus</comment>
+ <translation>PCIe</translation>
+ </message>
+ <message>
+ <source>NVMe</source>
+ <comment>StorageControllerType</comment>
+ <translation>NVMe</translation>
+ </message>
+ <message>
+ <source>NVMe Port %1</source>
+ <comment>StorageSlot</comment>
+ <translation>พอร์ต NVMe %1</translation>
+ </message>
+ <message>
+ <source>General</source>
+ <comment>InformationElementType</comment>
+ <translation>ทั่วไป</translation>
+ </message>
+ <message>
+ <source>Preview</source>
+ <comment>InformationElementType</comment>
+ <translation>แสดงตัวอย่าง</translation>
+ </message>
+ <message>
+ <source>System</source>
+ <comment>InformationElementType</comment>
+ <translation>ระบบ</translation>
+ </message>
+ <message>
+ <source>Display</source>
+ <comment>InformationElementType</comment>
+ <translation>หน่วยแสดงผล</translation>
+ </message>
+ <message>
+ <source>Storage</source>
+ <comment>InformationElementType</comment>
+ <translation>หน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Audio</source>
+ <comment>InformationElementType</comment>
+ <translation>เสียง</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <comment>InformationElementType</comment>
+ <translation>เครือข่าย</translation>
+ </message>
+ <message>
+ <source>Serial ports</source>
+ <comment>InformationElementType</comment>
+ <translation>พอร์ตอนุกรม</translation>
+ </message>
+ <message>
+ <source>Parallel ports</source>
+ <comment>InformationElementType</comment>
+ <translation>พอร์ตขนาน</translation>
+ </message>
+ <message>
+ <source>USB</source>
+ <comment>InformationElementType</comment>
+ <translation>USB</translation>
+ </message>
+ <message>
+ <source>Shared folders</source>
+ <comment>InformationElementType</comment>
+ <translation>โฟลเดอร์ใช้ร่วมกัน</translation>
+ </message>
+ <message>
+ <source>User interface</source>
+ <comment>InformationElementType</comment>
+ <translation>ส่วนติดต่อผู้ใช้</translation>
+ </message>
+ <message>
+ <source>Description</source>
+ <comment>InformationElementType</comment>
+ <translation>คำอธิบาย</translation>
+ </message>
+ <message>
+ <source>Runtime attributes</source>
+ <comment>InformationElementType</comment>
+ <translation>คุณสมบัติเฉพาะของรุ่นที่ใช้</translation>
+ </message>
+ <message>
+ <source>Storage statistics</source>
+ <comment>InformationElementType</comment>
+ <translation>สถิติหน่วยเก็บข้อมูล</translation>
+ </message>
+ <message>
+ <source>Network statistics</source>
+ <comment>InformationElementType</comment>
+ <translation>สถิติเครือข่าย</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxGlobalSettings</name>
+ <message>
+ <source>The value '%1' of the key '%2' doesn't match the regexp constraint '%3'.</source>
+ <translation>ค่า '%1' ของคีย์ '%2' ไม่ตรงกับ regexp ตามเงื่อนไข '%3'.</translation>
+ </message>
+ <message>
+ <source>Cannot delete the key '%1'.</source>
+ <translation>ไม่สามารถลบคีย์ '%1'</translation>
+ </message>
+ <message>
+ <source>'%1' is an invalid host-combination code-sequence.</source>
+ <translation>'%1' ไม่ใช่ลำดับที่ใช้ร่วมกับปุ่มโฮสต์ที่ถูกต้อง</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxLicenseViewer</name>
+ <message>
+ <source>VirtualBox License</source>
+ <translation>ไลเซนส์เวอร์ชวลบอกซ์</translation>
+ </message>
+ <message>
+ <source>I &Agree</source>
+ <translation>ฉัน&ยอมรับ</translation>
+ </message>
+ <message>
+ <source>I &Disagree</source>
+ <translation>ฉันไ&ม่ยอมรับ</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxMediaManagerDlg</name>
+ <message>
+ <source>&Actions</source>
+ <translation>&การกระทำ</translation>
+ </message>
+ <message>
+ <source>R&emove</source>
+ <translation>&นำออก</translation>
+ </message>
+ <message>
+ <source>Re&lease</source>
+ <translation>&ปล่อย</translation>
+ </message>
+ <message>
+ <source>Re&fresh</source>
+ <translation>เรียก&ซ้ำ</translation>
+ </message>
+ <message>
+ <source>Remove the selected disk image file</source>
+ <translation>นำไฟล์ดิสก์อิมเมจที่เลือกไว้ออก</translation>
+ </message>
+ <message>
+ <source>Release the selected disk image file by detaching it from the machines</source>
+ <translation>ปล่อยไฟล์ดิสก์อิมเมจที่เลือกด้วยการถอดออกจากเครื่อง</translation>
+ </message>
+ <message>
+ <source>Refresh the list of disk image files</source>
+ <translation>เรียกรายการไฟล์ดิสก์อิมเมจซ้ำอีกครั้ง</translation>
+ </message>
+ <message>
+ <source>Checking accessibility</source>
+ <translation>กำลังตรวจสอบการเข้าถึง</translation>
+ </message>
+ <message>
+ <source><i>Not Attached</i></source>
+ <translation><i>ไม่ได้เชื่อมต่อไว้</i></translation>
+ </message>
+ <message>
+ <source>--</source>
+ <comment>no info</comment>
+ <translation>--</translation>
+ </message>
+ <message>
+ <source>Virtual Media Manager</source>
+ <translation>ส่วนจัดการมีเดียเสมือน</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Virtual Size</source>
+ <translation>ขนาดเสมือน</translation>
+ </message>
+ <message>
+ <source>Actual Size</source>
+ <translation>ขนาดจริง</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>ขนาด</translation>
+ </message>
+ <message>
+ <source>Type:</source>
+ <translation>ชนิด:</translation>
+ </message>
+ <message>
+ <source>Location:</source>
+ <translation>ที่ตั้ง:</translation>
+ </message>
+ <message>
+ <source>Format:</source>
+ <translation>รูปแบบ:</translation>
+ </message>
+ <message>
+ <source>Storage details:</source>
+ <translation>รายละเอียดหน่วยเก็บข้อมูล:</translation>
+ </message>
+ <message>
+ <source>Attached to:</source>
+ <translation>เชื่อมต่อกับ:</translation>
+ </message>
+ <message>
+ <source>&Copy...</source>
+ <translation>&คัดลอก...</translation>
+ </message>
+ <message>
+ <source>&Modify...</source>
+ <translation>แ&ก้ไข...</translation>
+ </message>
+ <message>
+ <source>Copy an existing disk image file</source>
+ <translation>ทำสำเนาไฟล์ดิสอิมเมจที่มีอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>Modify the attributes of the selected disk image file</source>
+ <translation>แก้ไขลักษณะเฉพาะของไฟล์ดิสก์อิมเมจ</translation>
+ </message>
+ <message>
+ <source>UUID:</source>
+ <translation>UUID:</translation>
+ </message>
+ <message>
+ <source><i>Not Encrypted</i></source>
+ <translation><i>ไม่ได้เข้ารหัสลับไว้</i></translation>
+ </message>
+ <message>
+ <source>Encrypted with key:</source>
+ <translation>เข้ารหัสลับด้วยกุญแจ:</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxScreenshotViewer</name>
+ <message>
+ <source>Screenshot of %1 (%2)</source>
+ <translation>ภาพหน้าจอของ %1 (%2)</translation>
+ </message>
+ <message>
+ <source>Click to view non-scaled screenshot.</source>
+ <translation>คลิกเพื่อแสดงภาพหน้าจอแบบไม่สเกล</translation>
+ </message>
+ <message>
+ <source>Click to view scaled screenshot.</source>
+ <translation>คลิกเพื่อแสดงภาพหน้าจอแบบสเกล</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxSnapshotDetailsDlg</name>
+ <message>
+ <source>Details of %1 (%2)</source>
+ <translation>รายละเอียดของ %1 (%2)</translation>
+ </message>
+ <message>
+ <source>Click to enlarge the screenshot.</source>
+ <translation>คลิกเพื่อขยายภาพหน้าจอ</translation>
+ </message>
+ <message>
+ <source>&Name:</source>
+ <translation>&ชื่อ:</translation>
+ </message>
+ <message>
+ <source>Taken:</source>
+ <translation>จับภาพเมื่อ:</translation>
+ </message>
+ <message>
+ <source>&Description:</source>
+ <translation>&คำอธิบาย:</translation>
+ </message>
+ <message>
+ <source>D&etails:</source>
+ <translation>&รายละเอียด:</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxSnapshotsWgt</name>
+ <message>
+ <source>VBoxSnapshotsWgt</source>
+ <translation>VBoxSnapshotsWgt</translation>
+ </message>
+ <message>
+ <source>Current State (changed)</source>
+ <comment>Current State (Modified)</comment>
+ <translation>สถานะปัจจุบัน (มีการเปลี่ยนแปลง)</translation>
+ </message>
+ <message>
+ <source>Current State</source>
+ <comment>Current State (Unmodified)</comment>
+ <translation>สถานะปัจจุบัน</translation>
+ </message>
+ <message>
+ <source>The current state differs from the state stored in the current snapshot</source>
+ <translation>สถานะปัจจุบันมีความแตกต่างจากสถานะที่ถูกจัดเก็บไว้ในสแนปช็อต</translation>
+ </message>
+ <message>
+ <source>The current state is identical to the state stored in the current snapshot</source>
+ <translation>สถานะปัจจุบันตรงกับสถานะที่ถูกจัดเก็บไว้ในสแนปช็อต</translation>
+ </message>
+ <message>
+ <source> (current, </source>
+ <comment>Snapshot details</comment>
+ <translation>(ปัจจุบัน, </translation>
+ </message>
+ <message>
+ <source>online)</source>
+ <comment>Snapshot details</comment>
+ <translation>ออนไลน์)</translation>
+ </message>
+ <message>
+ <source>offline)</source>
+ <comment>Snapshot details</comment>
+ <translation>ออฟไลน์)</translation>
+ </message>
+ <message>
+ <source>Taken at %1</source>
+ <comment>Snapshot (time)</comment>
+ <translation>เก็บไว้เมื่อ %1</translation>
+ </message>
+ <message>
+ <source>Taken on %1</source>
+ <comment>Snapshot (date + time)</comment>
+ <translation>เก็บไว้เมื่อ %1</translation>
+ </message>
+ <message>
+ <source>%1 since %2</source>
+ <comment>Current State (time or date + time)</comment>
+ <translation>%1 ตั้งแต่ %2</translation>
+ </message>
+ <message>
+ <source>Snapshot %1</source>
+ <translation>สแนปช็อต %1</translation>
+ </message>
+ <message>
+ <source>Take &Snapshot</source>
+ <translation>เก็บ&สแนปช็อต</translation>
+ </message>
+ <message>
+ <source>S&how Details</source>
+ <translation>แ&สดงรายละเอียด</translation>
+ </message>
+ <message>
+ <source>Take a snapshot of the current virtual machine state</source>
+ <translation>เก็บสแนปช็อตของสถานะปัจจุบันของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source> (%1)</source>
+ <translation> (%1)</translation>
+ </message>
+ <message>
+ <source>&Restore Snapshot</source>
+ <translation>&คืนค่าสแนปช็อต</translation>
+ </message>
+ <message>
+ <source>&Delete Snapshot</source>
+ <translation>&ลบสแนปช็อต</translation>
+ </message>
+ <message>
+ <source> (%1 ago)</source>
+ <translation> (%1 ที่แล้ว)</translation>
+ </message>
+ <message>
+ <source>&Clone...</source>
+ <translation>โ&คลน...</translation>
+ </message>
+ <message>
+ <source>Restore selected snapshot of the virtual machine</source>
+ <translation>คืนค่าของสแนปช็อตที่เลือกให้เวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Delete selected snapshot of the virtual machine</source>
+ <translation>ลบสแนปช็อตที่เลือกของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Display a window with selected snapshot details</source>
+ <translation>แสดงหน้าต่างรายละเอียดของสแนปช็อตที่เลือก</translation>
+ </message>
+ <message>
+ <source>Clone selected virtual machine</source>
+ <translation>โคลนเวอร์ชวลแมชชีนที่เลือก</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxTakeSnapshotDlg</name>
+ <message>
+ <source>Take Snapshot of Virtual Machine</source>
+ <translation>เก็บสแนปช็อตของเวอร์ชวลแมชชีน</translation>
+ </message>
+ <message>
+ <source>Snapshot &Name</source>
+ <translation>&ชื่อสแนปช็อต</translation>
+ </message>
+ <message>
+ <source>Snapshot &Description</source>
+ <translation>&คำอธิบายสแนปช็อต</translation>
+ </message>
+ <message numerus="yes">
+ <source>Warning: You are taking a snapshot of a running machine which has %n immutable image(s) attached to it. As long as you are working from this snapshot the immutable image(s) will not be reset to avoid loss of data.</source>
+ <translation>
+ <numerusform>คำเตือน: คุณกำลังเก็บสแนปช็อตของเครื่องที่มีอิมเมจที่ไม่เปลี่ยนแปลงจำนวน %n หน่วยเชื่อมต่ออยู่ ตราบใดที่คุณยังทำงานกับสแนปช็อตนี้ อิมเมจที่ไม่เปลี่ยนแปลงดังกล่าวจะไม่ถูกรีเซ็ตเพื่อหลีกเลี่ยงการสูญเสียข้อมูล</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>Snapshot %1</source>
+ <translation>สแนปช็อต %1</translation>
+ </message>
+</context>
+<context>
+ <name>VBoxUSBMenu</name>
+ <message>
+ <source><no devices available></source>
+ <comment>USB devices</comment>
+ <translation><ไม่มีอุปกรณ์ที่พร้อมใช้งาน></translation>
+ </message>
+ <message>
+ <source>No supported devices connected to the host PC</source>
+ <comment>USB device tooltip</comment>
+ <translation>ไม่มีอุปกรณ์ที่รองรับเชื่อมต่ออยู่กับโฮสต์พีซี</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts
index 6e5d47e..dd92c01 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_tr.ts
@@ -2345,6 +2345,10 @@
<source>Downloading %1...</source>
<translation>%1 indiriliyor...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9909,6 +9913,14 @@
<source>Do you want to delete following list of files <nobr><b>%1</b></nobr>?</source>
<translation>Aşağıda listelenen <nobr><b>%1</b></nobr> dosyalarını silmek istiyor musunuz?</translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -12402,11 +12414,11 @@ bu basamağı atlayarak sabit diskleri Sanal Makine Ayarları penceresinden ekle
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>Oluşturmak üzere olduğunuz sanal makine klasörü için adı veya tam yolu tutar.</nobr></p></translation>
+ <translation type="vanished"><p><nobr>Oluşturmak üzere olduğunuz sanal makine klasörü için adı veya tam yolu tutar.</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>Aşağıdaki klasörde sanal makineyi oluşturmak üzeresiniz:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>Aşağıdaki klasörde sanal makineyi oluşturmak üzeresiniz:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts
index a0c4893..1d0e72f 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_uk.ts
@@ -2430,6 +2430,10 @@
<source>Downloading %1...</source>
<translation>Звантаження %1…</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -10169,6 +10173,14 @@ p, li { white-space: pre-wrap; }
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetAdditions</name>
@@ -12737,14 +12749,6 @@ p, li { white-space: pre-wrap; }
<source>Choose a virtual hard disk file...</source>
<translation>Вибрати файл віртуального жорсткого диска...</translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts
index 50d2825..394188d 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_xx_YY.ts
@@ -1191,6 +1191,10 @@
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -5867,6 +5871,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniToolBar</name>
@@ -7306,14 +7318,6 @@
<source>Choose a virtual hard disk file...</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation type="unfinished"></translation>
- </message>
</context>
<context>
<name>VBoxAboutDlg</name>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts
index c8e2c60..da53f89 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_CN.ts
@@ -2391,6 +2391,10 @@
<source>Downloading %1...</source>
<translation>正在下载 %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -9411,6 +9415,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniProcessWidgetUserManual</name>
@@ -11560,11 +11572,11 @@
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>拟创建的虚拟机的存储文件夹的名称或路径。</nobr></p></translation>
+ <translation type="vanished"><p><nobr>拟创建的虚拟机的存储文件夹的名称或路径。</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>拟创建的虚拟机位于:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>拟创建的虚拟机位于:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts
index a73800d..2b31bf9 100644
--- a/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts
+++ b/src/VBox/Frontends/VirtualBox/nls/VirtualBox_zh_TW.ts
@@ -1191,6 +1191,10 @@
<source>Downloading %1...</source>
<translation>正在下載 %1...</translation>
</message>
+ <message>
+ <source>Verifying %1...</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIDownloaderAdditions</name>
@@ -5867,6 +5871,14 @@
<source><p>The reason for this error are most likely wrong permissions of the IPC daemon socket due to an installation problem. Please check the permissions of <font color=blue>'/tmp'</font> and <font color=blue>'/tmp/.vbox-*-ipc/'</font></p></source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source><p>The <b>VirtualBox Guest Additions</b> disk image file has been successfully downloaded from <nobr><a href="%1">%1</a></nobr> and saved locally as <nobr><b>%2</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><p>The <b><nobr>%1</nobr></b> has been successfully downloaded from <nobr><a href="%2">%2</a></nobr> and saved locally as <nobr><b>%3</b>, </nobr>but the SHA-256 checksum verification failed.</p><p>Please do the download, installation and verification manually.</p></source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UIMiniToolBar</name>
@@ -7308,11 +7320,11 @@
</message>
<message>
<source><p><nobr>Holds the name or full path to the virtual machine folder you are about to create.</nobr></p></source>
- <translation><p><nobr>保留您能建立到虛擬機器資料夾的名稱或完整路徑。</nobr></p></translation>
+ <translation type="vanished"><p><nobr>保留您能建立到虛擬機器資料夾的名稱或完整路徑。</nobr></p></translation>
</message>
<message>
<source><p><nobr>You are about to create the virtual machine in the following folder:</nobr><br><nobr><b>%1</b></nobr></p></source>
- <translation><p><nobr>您即將在以下資料夾建立虛擬機器:</nobr><br><nobr><b>%1</b></nobr></p></translation>
+ <translation type="vanished"><p><nobr>您即將在以下資料夾建立虛擬機器:</nobr><br><nobr><b>%1</b></nobr></p></translation>
</message>
</context>
<context>
diff --git a/src/VBox/Frontends/VirtualBox/nls/qt_th.ts b/src/VBox/Frontends/VirtualBox/nls/qt_th.ts
new file mode 100644
index 0000000..3b5290e
--- /dev/null
+++ b/src/VBox/Frontends/VirtualBox/nls/qt_th.ts
@@ -0,0 +1,5321 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="th_TH">
+<context>
+ <name>MAC_APPLICATION_MENU</name>
+ <message>
+ <source>Services</source>
+ <translation>บริการ</translation>
+ </message>
+ <message>
+ <source>Hide %1</source>
+ <translation>ซ่อน %1</translation>
+ </message>
+ <message>
+ <source>Hide Others</source>
+ <translation>ซ่อนอื่น ๆ</translation>
+ </message>
+ <message>
+ <source>Show All</source>
+ <translation>แสดงทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Preferences...</source>
+ <translation>ค่าตั้งพึงใจ...</translation>
+ </message>
+ <message>
+ <source>Quit %1</source>
+ <translation>ออกจาก %1</translation>
+ </message>
+ <message>
+ <source>About %1</source>
+ <translation>เกี่ยวกับ %1</translation>
+ </message>
+</context>
+<context>
+ <name>AudioOutput</name>
+ <message>
+ <source><html>The audio playback device <b>%1</b> does not work.<br/>Falling back to <b>%2</b>.</html></source>
+ <translation><html>อุปกรณ์สำหรับเล่นเสียง <b>%1</b> ไม่ทำงาน<br/>กำลังกลับไปใช้ <b>%2</b></html></translation>
+ </message>
+ <message>
+ <source><html>Switching to the audio playback device <b>%1</b><br/>which just became available and has higher preference.</html></source>
+ <translation><html>กำลังสลับไปใช้อุปกรณ์สำหรับเล่นเสียง <b>%1</b><br/>ซึ่งเพิ่งพร้อมใช้งานและมีค่าความพอใจที่ตั้งไว้สูงกว่า</html></translation>
+ </message>
+ <message>
+ <source>Revert back to device '%1'</source>
+ <translation>กลับไปใช้อุปกรณ์ '%1'</translation>
+ </message>
+</context>
+<context>
+ <name>Phonon::</name>
+ <message>
+ <source>Notifications</source>
+ <translation>การเตือน</translation>
+ </message>
+ <message>
+ <source>Music</source>
+ <translation>ดนตรี</translation>
+ </message>
+ <message>
+ <source>Video</source>
+ <translation>วิดีโอ</translation>
+ </message>
+ <message>
+ <source>Communication</source>
+ <translation>การสื่อสาร</translation>
+ </message>
+ <message>
+ <source>Games</source>
+ <translation>เกม</translation>
+ </message>
+ <message>
+ <source>Accessibility</source>
+ <translation>การเข้าถึง</translation>
+ </message>
+</context>
+<context>
+ <name>Phonon::Gstreamer::Backend</name>
+ <message>
+ <source>Warning: You do not seem to have the package gstreamer0.10-plugins-good installed.
+ Some video features have been disabled.</source>
+ <translation>คำเตือน: ดูเหมือนว่าคุณไม่ได้ติดตั้งแพคเกจ gstreamer0.10-plugins-good ไว้
+ คุณสมบัติด้านวิดีโอบางส่วนจะถูกปิดไว้</translation>
+ </message>
+ <message>
+ <source>Warning: You do not seem to have the base GStreamer plugins installed.
+ All audio and video support has been disabled</source>
+ <translation>คำเตือน: ดูเหมือนว่าคุณไม่ได้ติดตั้งปลั๊กอินพื้นฐาน GStreamer ไว้
+ การทำงานด้านเสียงและวิดีโอทั้งหมดจะถูกปิดไว้</translation>
+ </message>
+</context>
+<context>
+ <name>Phonon::Gstreamer::MediaObject</name>
+ <message>
+ <source>Cannot start playback.
+
+Check your Gstreamer installation and make sure you
+have libgstreamer-plugins-base installed.</source>
+ <translation>ไม่สามารถเริ่มเล่นได้
+
+โปรดตรวจสอบการติดตั้ง Gstreamer ของคุณให้แน่ใจว่า
+มีปลั๊กอิน libgstreamer-plugins-base ติดตั้งไว้</translation>
+ </message>
+ <message numerus="yes">
+ <source>A required codec is missing. You need to install the following codec(s) to play this content: %0</source>
+ <translation>
+ <numerusform>โคเดกที่จำเป็นขาดหายไป คุณจำเป็นต้องติดตั้งโคเดกต่อไปนี้เพื่อเล่นสื่อนี้: %0</numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>Could not open media source.</source>
+ <translation>ไม่สามารถเปิดต้นฉบับของมีเดียได้</translation>
+ </message>
+ <message>
+ <source>Invalid source type.</source>
+ <translation>ชนิดของต้นฉบับไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Could not locate media source.</source>
+ <translation>ไม่พบต้นฉบับของมีเดีย</translation>
+ </message>
+ <message>
+ <source>Could not open audio device. The device is already in use.</source>
+ <translation>ไม่สามารถเปิดอุปกรณ์เสียงได้เนื่องจากอุปกรณ์กำลังถูกใช้งานอยู่</translation>
+ </message>
+ <message>
+ <source>Could not decode media source.</source>
+ <translation>ไม่สามารถถอดรหัสต้นฉบับมีเดียได้</translation>
+ </message>
+</context>
+<context>
+ <name>Phonon::VolumeSlider</name>
+ <message>
+ <source>Volume: %1%</source>
+ <translation>เสียง: %1%</translation>
+ </message>
+ <message>
+ <source>Use this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1%</source>
+ <translation>ใช้ตัวเลื่อนนี้เพื่อปรับระดับเสียง ตำแหน่งซ้ายสุดคือ 0% และทางด้านขวาสุดคือ %1%</translation>
+ </message>
+</context>
+<context>
+ <name>Q3Accel</name>
+ <message>
+ <source>%1, %2 not defined</source>
+ <translation>%1, %2 ไม่ได้กำหนดไว้</translation>
+ </message>
+ <message>
+ <source>Ambiguous %1 not handled</source>
+ <translation>ค่ากำกวม %1 ไม่ได้ถูกจัดการไว้</translation>
+ </message>
+</context>
+<context>
+ <name>Q3DataTable</name>
+ <message>
+ <source>True</source>
+ <translation>จริง</translation>
+ </message>
+ <message>
+ <source>False</source>
+ <translation>เท็จ</translation>
+ </message>
+ <message>
+ <source>Insert</source>
+ <translation>แทรก</translation>
+ </message>
+ <message>
+ <source>Update</source>
+ <translation>อัพเดต</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>ลบ</translation>
+ </message>
+</context>
+<context>
+ <name>Q3FileDialog</name>
+ <message>
+ <source>Copy or Move a File</source>
+ <translation>ทำสำเนาหรือย้ายไฟล์</translation>
+ </message>
+ <message>
+ <source>Read: %1</source>
+ <translation>อ่าน: %1</translation>
+ </message>
+ <message>
+ <source>Write: %1</source>
+ <translation>เขียน: %1</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+ <message>
+ <source>All Files (*)</source>
+ <translation>ไฟล์ทั้งหมด (*)</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>ขนาด</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <translation>ชนิด</translation>
+ </message>
+ <message>
+ <source>Date</source>
+ <translation>วันที่</translation>
+ </message>
+ <message>
+ <source>Attributes</source>
+ <translation>ลักษณะเฉพาะ</translation>
+ </message>
+ <message>
+ <source>&OK</source>
+ <translation>&ตกลง</translation>
+ </message>
+ <message>
+ <source>Look &in:</source>
+ <translation>ดูใ&น:</translation>
+ </message>
+ <message>
+ <source>File &name:</source>
+ <translation>&ชื่อไฟล์:</translation>
+ </message>
+ <message>
+ <source>File &type:</source>
+ <translation>ช&นิดของไฟล์:</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>ย้อนกลับ</translation>
+ </message>
+ <message>
+ <source>One directory up</source>
+ <translation>ขึ้นไปหนึ่งไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Create New Folder</source>
+ <translation>สร้างโฟลเดอร์ใหม่</translation>
+ </message>
+ <message>
+ <source>List View</source>
+ <translation>มุมมองรายการ</translation>
+ </message>
+ <message>
+ <source>Detail View</source>
+ <translation>มุมมองรายละเอียด</translation>
+ </message>
+ <message>
+ <source>Preview File Info</source>
+ <translation>แสดงตัวอย่างข้อมูลไฟล์</translation>
+ </message>
+ <message>
+ <source>Preview File Contents</source>
+ <translation>แสดงตัวอย่างเนื้อหาของไฟล์</translation>
+ </message>
+ <message>
+ <source>Read-write</source>
+ <translation>อ่าน-เขียน</translation>
+ </message>
+ <message>
+ <source>Read-only</source>
+ <translation>อ่านอย่างเดียว</translation>
+ </message>
+ <message>
+ <source>Write-only</source>
+ <translation>เขียนอย่างเดียว</translation>
+ </message>
+ <message>
+ <source>Inaccessible</source>
+ <translation>ไม่สามารถเข้าถึงได้</translation>
+ </message>
+ <message>
+ <source>Symlink to File</source>
+ <translation>สัญลักษณ์เชื่อมโยงไปยังไฟล์</translation>
+ </message>
+ <message>
+ <source>Symlink to Directory</source>
+ <translation>สัญลักษณ์เชื่อมโยงไปไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Symlink to Special</source>
+ <translation>สัญลักษณ์เชื่อมโยงไปไฟล์พิเศษ</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>ไฟล์</translation>
+ </message>
+ <message>
+ <source>Dir</source>
+ <translation>ไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Special</source>
+ <translation>ไฟล์พิเศษ</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>เปิด</translation>
+ </message>
+ <message>
+ <source>Save As</source>
+ <translation>บันทึกเป็น</translation>
+ </message>
+ <message>
+ <source>&Open</source>
+ <translation>เ&ปิด</translation>
+ </message>
+ <message>
+ <source>&Save</source>
+ <translation>&บันทึก</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>เ&ปลี่ยนชื่อ</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&ลบ</translation>
+ </message>
+ <message>
+ <source>R&eload</source>
+ <translation>เรียก&ซ้ำ</translation>
+ </message>
+ <message>
+ <source>Sort by &Name</source>
+ <translation>เรียงลำดับตาม&ชื่อ</translation>
+ </message>
+ <message>
+ <source>Sort by &Size</source>
+ <translation>เรียงลำดับตาม&ขนาด</translation>
+ </message>
+ <message>
+ <source>Sort by &Date</source>
+ <translation>เรียงลำดับตาม&วันที่</translation>
+ </message>
+ <message>
+ <source>&Unsorted</source>
+ <translation>ไ&ม่เรียงลำดับ</translation>
+ </message>
+ <message>
+ <source>Sort</source>
+ <translation>เรียงลำดับ</translation>
+ </message>
+ <message>
+ <source>Show &hidden files</source>
+ <translation>แสดงไฟล์&ซ่อน</translation>
+ </message>
+ <message>
+ <source>the file</source>
+ <translation>ไฟล์</translation>
+ </message>
+ <message>
+ <source>the directory</source>
+ <translation>ไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>the symlink</source>
+ <translation>สัญลักษณ์เชื่อมโยง</translation>
+ </message>
+ <message>
+ <source>Delete %1</source>
+ <translation>ลบ %1</translation>
+ </message>
+ <message>
+ <source><qt>Are you sure you wish to delete %1 "%2"?</qt></source>
+ <translation><qt>แน่ใจหรือไม่ว่าคุณต้องการลบ %1 "%2"?</qt></translation>
+ </message>
+ <message>
+ <source>&Yes</source>
+ <translation>ใ&ช่</translation>
+ </message>
+ <message>
+ <source>&No</source>
+ <translation>ไ&ม่ใช่</translation>
+ </message>
+ <message>
+ <source>New Folder 1</source>
+ <translation>โฟลเดอร์ใหม่ 1</translation>
+ </message>
+ <message>
+ <source>New Folder</source>
+ <translation>โฟลเดอร์ใหม่</translation>
+ </message>
+ <message>
+ <source>New Folder %1</source>
+ <translation>โฟลเดอร์ใหม่ %1</translation>
+ </message>
+ <message>
+ <source>Find Directory</source>
+ <translation>ค้นหาไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Directories</source>
+ <translation>ไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Directory:</source>
+ <translation>ไดเรกทอรี:</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>ข้อผิดพลาด</translation>
+ </message>
+ <message>
+ <source>%1
+File not found.
+Check path and filename.</source>
+ <translation>%1
+ไม่พบไฟล์
+ตรวจสอบเส้นทางและชื่อไฟล์</translation>
+ </message>
+</context>
+<context>
+ <name>Q3LocalFs</name>
+ <message>
+ <source>Could not read directory
+%1</source>
+ <translation>ไม่สามารถอ่านไดเรกทอรี
+%1</translation>
+ </message>
+ <message>
+ <source>Could not create directory
+%1</source>
+ <translation>ไม่สามารถสร้างไดเรกทอรี
+%1</translation>
+ </message>
+ <message>
+ <source>Could not remove file or directory
+%1</source>
+ <translation>ไม่สามารถลบไฟล์หรือไดเรกทอรี
+%1</translation>
+ </message>
+ <message>
+ <source>Could not rename
+%1
+to
+%2</source>
+ <translation>ไม่สามารถเปลี่ยนชื่อ
+%1
+เป็น
+%2</translation>
+ </message>
+ <message>
+ <source>Could not open
+%1</source>
+ <translation>ไม่สามารถเปิด
+%1</translation>
+ </message>
+ <message>
+ <source>Could not write
+%1</source>
+ <translation>ไม่สามารถเขียน
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>Q3MainWindow</name>
+ <message>
+ <source>Line up</source>
+ <translation>จัดเรียง</translation>
+ </message>
+ <message>
+ <source>Customize...</source>
+ <translation>ปรับแต่ง...</translation>
+ </message>
+</context>
+<context>
+ <name>Q3NetworkProtocol</name>
+ <message>
+ <source>Operation stopped by the user</source>
+ <translation>หยุดดำเนินการโดยผู้ใช้</translation>
+ </message>
+</context>
+<context>
+ <name>Q3ProgressDialog</name>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+</context>
+<context>
+ <name>Q3TabDialog</name>
+ <message>
+ <source>OK</source>
+ <translation>ตกลง</translation>
+ </message>
+ <message>
+ <source>Apply</source>
+ <translation>นำไปใช้</translation>
+ </message>
+ <message>
+ <source>Help</source>
+ <translation>ช่วยเหลือ</translation>
+ </message>
+ <message>
+ <source>Defaults</source>
+ <translation>ค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+</context>
+<context>
+ <name>Q3TextEdit</name>
+ <message>
+ <source>&Undo</source>
+ <translation>เ&ลิกทำ</translation>
+ </message>
+ <message>
+ <source>&Redo</source>
+ <translation>ทำ&ซ้ำ</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>&ตัด</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&คัดลอก</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&วาง</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>ล้าง</translation>
+ </message>
+ <message>
+ <source>Select All</source>
+ <translation>เลือกทั้งหมด</translation>
+ </message>
+</context>
+<context>
+ <name>Q3TitleBar</name>
+ <message>
+ <source>System</source>
+ <translation>ระบบ</translation>
+ </message>
+ <message>
+ <source>Restore up</source>
+ <translation>คืนขนาดขึ้น</translation>
+ </message>
+ <message>
+ <source>Minimize</source>
+ <translation>ย่อให้เล็กสุด</translation>
+ </message>
+ <message>
+ <source>Restore down</source>
+ <translation>คืนขนาดลง</translation>
+ </message>
+ <message>
+ <source>Maximize</source>
+ <translation>ขยายให้ใหญ่สุด</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Contains commands to manipulate the window</source>
+ <translation>เก็บคำสั่งเพื่อจัดการกับหน้าต่าง</translation>
+ </message>
+ <message>
+ <source>Puts a minimized back to normal</source>
+ <translation>ทำให้หน้าต่างที่ย่อเล็กสุดกลับเป็นปกติ</translation>
+ </message>
+ <message>
+ <source>Moves the window out of the way</source>
+ <translation>ย้ายหน้าต่างออกให้พ้นทาง</translation>
+ </message>
+ <message>
+ <source>Puts a maximized window back to normal</source>
+ <translation>ทำให้หน้าต่างที่ขยายใหญ่สุดกลับเป็นปกติ</translation>
+ </message>
+ <message>
+ <source>Makes the window full screen</source>
+ <translation>ทำให้หน้าต่างเป็นขนาดเต็มจอ</translation>
+ </message>
+ <message>
+ <source>Closes the window</source>
+ <translation>ปิดหน้าต่าง</translation>
+ </message>
+ <message>
+ <source>Holds the name of the window and contains controls to manipulate it</source>
+ <translation>เก็บชื่อของหน้าต่างและส่วนควบคุมเพื่อจัดการหน้าต่าง</translation>
+ </message>
+</context>
+<context>
+ <name>Q3ToolBar</name>
+ <message>
+ <source>More...</source>
+ <translation>เพิ่มเติม...</translation>
+ </message>
+</context>
+<context>
+ <name>Q3UrlOperator</name>
+ <message>
+ <source>The protocol `%1' is not supported</source>
+ <translation>ไม่รองรับโพรโทคอล `%1'</translation>
+ </message>
+ <message>
+ <source>The protocol `%1' does not support listing directories</source>
+ <translation>โพรโทคอล `%1' ไม่รองรับการแสดงรายการไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>The protocol `%1' does not support creating new directories</source>
+ <translation>โพรโทคอล `%1' ไม่รองรับการสร้างไดเรกทอรีใหม่</translation>
+ </message>
+ <message>
+ <source>The protocol `%1' does not support removing files or directories</source>
+ <translation>โพรโทคอล `%1' ไม่รองรับการลบไฟล์หรือไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>The protocol `%1' does not support renaming files or directories</source>
+ <translation>โพรโทคอล `%1' ไม่รองรับการเปลี่ยนชื่อไฟล์หรือไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>The protocol `%1' does not support getting files</source>
+ <translation>โพรโทคอล `%1' ไม่รองรับการรับไฟล์</translation>
+ </message>
+ <message>
+ <source>The protocol `%1' does not support putting files</source>
+ <translation>โพรโทคอล `%1' ไม่รองรับการส่งไฟล์</translation>
+ </message>
+ <message>
+ <source>The protocol `%1' does not support copying or moving files or directories</source>
+ <translation>โพรโทคอล `%1' ไม่รองรับการทำสำเนาหรือย้ายไฟล์หรือไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>(unknown)</source>
+ <translation>(ไม่รู้จัก)</translation>
+ </message>
+</context>
+<context>
+ <name>Q3Wizard</name>
+ <message>
+ <source>&Cancel</source>
+ <translation>&ยกเลิก</translation>
+ </message>
+ <message>
+ <source>< &Back</source>
+ <translation>< &ย้อนกลับ</translation>
+ </message>
+ <message>
+ <source>&Next ></source>
+ <translation>&ถัดไป ></translation>
+ </message>
+ <message>
+ <source>&Finish</source>
+ <translation>เ&สร็จสิ้น</translation>
+ </message>
+ <message>
+ <source>&Help</source>
+ <translation>&ช่วยเหลือ</translation>
+ </message>
+</context>
+<context>
+ <name>QAbstractSocket</name>
+ <message>
+ <source>Host not found</source>
+ <translation>ไม่พบโฮสต์</translation>
+ </message>
+ <message>
+ <source>Connection refused</source>
+ <translation>การเชื่อมต่อถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>Socket operation timed out</source>
+ <translation>หมดเวลากระบวนการซ็อคเก็ต</translation>
+ </message>
+ <message>
+ <source>Socket is not connected</source>
+ <translation>ไม่ได้เชื่อมต่อซ็อคเก็ตไว้</translation>
+ </message>
+</context>
+<context>
+ <name>QAbstractSpinBox</name>
+ <message>
+ <source>&Step up</source>
+ <translation>เพิ่ม&ขึ้น</translation>
+ </message>
+ <message>
+ <source>Step &down</source>
+ <translation>&ลดลง</translation>
+ </message>
+ <message>
+ <source>&Select All</source>
+ <translation>&เลือกทั้งหมด</translation>
+ </message>
+</context>
+<context>
+ <name>QApplication</name>
+ <message>
+ <source>Activate</source>
+ <translation>เรียกใช้</translation>
+ </message>
+ <message>
+ <source>Executable '%1' requires Qt %2, found Qt %3.</source>
+ <translation>โปรแกรม '%1' ต้องการ Qt %2 แต่พบ Qt %3</translation>
+ </message>
+ <message>
+ <source>Incompatible Qt Library Error</source>
+ <translation>เกิดความผิดพลาดไลบรารี Qt เข้ากันไม่ได้</translation>
+ </message>
+ <message>
+ <source>QT_LAYOUT_DIRECTION</source>
+ <comment>Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout.</comment>
+ <translation>QT_LAYOUT_DIRECTION</translation>
+ </message>
+ <message>
+ <source>Activates the program's main window</source>
+ <translation>เรียกใช้หน้าต่างหลักของโปรแกรม</translation>
+ </message>
+</context>
+<context>
+ <name>QCheckBox</name>
+ <message>
+ <source>Uncheck</source>
+ <translation>ไม่เลือก</translation>
+ </message>
+ <message>
+ <source>Check</source>
+ <translation>เลือก</translation>
+ </message>
+ <message>
+ <source>Toggle</source>
+ <translation>สลับค่า</translation>
+ </message>
+</context>
+<context>
+ <name>QColorDialog</name>
+ <message>
+ <source>Hu&e:</source>
+ <translation>&สี:</translation>
+ </message>
+ <message>
+ <source>&Sat:</source>
+ <translation>ความ&อิ่มตัว:</translation>
+ </message>
+ <message>
+ <source>&Val:</source>
+ <translation>&ค่าสี:</translation>
+ </message>
+ <message>
+ <source>&Red:</source>
+ <translation>แ&ดง:</translation>
+ </message>
+ <message>
+ <source>&Green:</source>
+ <translation>เ&ขียว:</translation>
+ </message>
+ <message>
+ <source>Bl&ue:</source>
+ <translation>&น้ำเงิน:</translation>
+ </message>
+ <message>
+ <source>A&lpha channel:</source>
+ <translation>ช่องสี&อัลฟ่า:</translation>
+ </message>
+ <message>
+ <source>&Basic colors</source>
+ <translation>สี&พื้นฐาน</translation>
+ </message>
+ <message>
+ <source>&Custom colors</source>
+ <translation>สีที่&กำหนดเอง</translation>
+ </message>
+ <message>
+ <source>&Add to Custom Colors</source>
+ <translation>เ&พิ่มไปยังสีที่กำหนดเอง</translation>
+ </message>
+ <message>
+ <source>Select color</source>
+ <translation>เลือกสี</translation>
+ </message>
+</context>
+<context>
+ <name>QComboBox</name>
+ <message>
+ <source>Open</source>
+ <translation>เปิด</translation>
+ </message>
+ <message>
+ <source>False</source>
+ <translation>เท็จ</translation>
+ </message>
+ <message>
+ <source>True</source>
+ <translation>จริง</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+</context>
+<context>
+ <name>QCoreApplication</name>
+ <message>
+ <source>%1: permission denied</source>
+ <comment>QSystemSemaphore</comment>
+ <translation>%1: คำขออนุญาตถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>%1: already exists</source>
+ <comment>QSystemSemaphore</comment>
+ <translation>%1: มีอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>%1: doesn't exists</source>
+ <comment>QSystemSemaphore</comment>
+ <translation>%1: ไม่พบ</translation>
+ </message>
+ <message>
+ <source>%1: out of resources</source>
+ <comment>QSystemSemaphore</comment>
+ <translation>%1: ทรัพยากรไม่พอ</translation>
+ </message>
+ <message>
+ <source>%1: unknown error %2</source>
+ <comment>QSystemSemaphore</comment>
+ <translation>%1: ข้อผิดพลาดที่ไม่รู้จัก %2</translation>
+ </message>
+ <message>
+ <source>%1: key is empty</source>
+ <comment>QSystemSemaphore</comment>
+ <translation>%1: คีย์ว่างอยู่</translation>
+ </message>
+ <message>
+ <source>%1: unable to make key</source>
+ <comment>QSystemSemaphore</comment>
+ <translation>%1: ไม่สามารถสร้างคีย์</translation>
+ </message>
+ <message>
+ <source>%1: ftok failed</source>
+ <comment>QSystemSemaphore</comment>
+ <translation>%1: ftok ล้มเหลว</translation>
+ </message>
+</context>
+<context>
+ <name>QDB2Driver</name>
+ <message>
+ <source>Unable to connect</source>
+ <translation>ไม่สามารถเชื่อมต่อได้</translation>
+ </message>
+ <message>
+ <source>Unable to commit transaction</source>
+ <translation>ไม่สามารถคอมมิทรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to rollback transaction</source>
+ <translation>ไม่สามารถย้อนรายการกลับได้</translation>
+ </message>
+ <message>
+ <source>Unable to set autocommit</source>
+ <translation>ไม่สามารถกำหนดให้คอมมิทอัตโนมัติได้</translation>
+ </message>
+</context>
+<context>
+ <name>QDB2Result</name>
+ <message>
+ <source>Unable to execute statement</source>
+ <translation>ไม่สามารถประมวลผลข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to prepare statement</source>
+ <translation>ไม่สามารถเตรียมข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to bind variable</source>
+ <translation>ไม่สามารถเชื่อมโยงตัวแปรได้</translation>
+ </message>
+ <message>
+ <source>Unable to fetch record %1</source>
+ <translation>ไม่สามารถเรียกระเบียน %1 ได้</translation>
+ </message>
+ <message>
+ <source>Unable to fetch next</source>
+ <translation>ไม่สามารถเรียกระเบียนถัดไปได้</translation>
+ </message>
+ <message>
+ <source>Unable to fetch first</source>
+ <translation>ไม่สามารถเรียกระเบียนแรกได้</translation>
+ </message>
+</context>
+<context>
+ <name>QDateTimeEdit</name>
+ <message>
+ <source>AM</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>am</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>PM</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>pm</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QDial</name>
+ <message>
+ <source>QDial</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>SpeedoMeter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>SliderHandle</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QDialog</name>
+ <message>
+ <source>What's This?</source>
+ <translation>นี่คืออะไร?</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>เสร็จสิ้น</translation>
+ </message>
+</context>
+<context>
+ <name>QDialogButtonBox</name>
+ <message>
+ <source>OK</source>
+ <translation>ตกลง</translation>
+ </message>
+ <message>
+ <source>Save</source>
+ <translation>บันทึก</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>เปิด</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Apply</source>
+ <translation>นำไปใช้</translation>
+ </message>
+ <message>
+ <source>Reset</source>
+ <translation>รีเซ็ต</translation>
+ </message>
+ <message>
+ <source>Help</source>
+ <translation>ช่วยเหลือ</translation>
+ </message>
+ <message>
+ <source>Don't Save</source>
+ <translation>ไม่บันทึก</translation>
+ </message>
+ <message>
+ <source>Discard</source>
+ <translation>ละทิ้ง</translation>
+ </message>
+ <message>
+ <source>&Yes</source>
+ <translation>ใ&ช่</translation>
+ </message>
+ <message>
+ <source>Yes to &All</source>
+ <translation>ใช่&ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>&No</source>
+ <translation>ไ&ม่ใช่</translation>
+ </message>
+ <message>
+ <source>N&o to All</source>
+ <translation>ไม่ใช่ทั้ง&หมด</translation>
+ </message>
+ <message>
+ <source>Save All</source>
+ <translation>บันทึกทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>ยกเลิก</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>ลองใหม่</translation>
+ </message>
+ <message>
+ <source>Ignore</source>
+ <translation>ละเว้น</translation>
+ </message>
+ <message>
+ <source>Restore Defaults</source>
+ <translation>คืนค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source>Close without Saving</source>
+ <translation>ปิดโดยไม่บันทึก</translation>
+ </message>
+ <message>
+ <source>&OK</source>
+ <translation>&ตกลง</translation>
+ </message>
+</context>
+<context>
+ <name>QDirModel</name>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>ขนาด</translation>
+ </message>
+ <message>
+ <source>Kind</source>
+ <comment>Match OS X Finder</comment>
+ <translation>ชนิด</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <comment>All other platforms</comment>
+ <translation>ชนิด</translation>
+ </message>
+ <message>
+ <source>Date Modified</source>
+ <translation>วันที่แก้ไข</translation>
+ </message>
+</context>
+<context>
+ <name>QDockWidget</name>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Dock</source>
+ <translation>ด็อค</translation>
+ </message>
+ <message>
+ <source>Float</source>
+ <translation>ลอย</translation>
+ </message>
+</context>
+<context>
+ <name>QDoubleSpinBox</name>
+ <message>
+ <source>More</source>
+ <translation>เพิ่มขึ้น</translation>
+ </message>
+ <message>
+ <source>Less</source>
+ <translation>ลดลง</translation>
+ </message>
+</context>
+<context>
+ <name>QErrorMessage</name>
+ <message>
+ <source>Debug Message:</source>
+ <translation>ข้อความดีบัก:</translation>
+ </message>
+ <message>
+ <source>Warning:</source>
+ <translation>คำเตือน:</translation>
+ </message>
+ <message>
+ <source>Fatal Error:</source>
+ <translation>ข้อผิดพลาดร้ายแรง:</translation>
+ </message>
+ <message>
+ <source>&Show this message again</source>
+ <translation>แ&สดงข้อความนี้อีกครั้ง</translation>
+ </message>
+ <message>
+ <source>&OK</source>
+ <translation>&ตกลง</translation>
+ </message>
+</context>
+<context>
+ <name>QFileDialog</name>
+ <message>
+ <source>All Files (*)</source>
+ <translation>ไฟล์ทั้งหมด (*)</translation>
+ </message>
+ <message>
+ <source>Directories</source>
+ <translation>ไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>&Open</source>
+ <translation>เ&ปิด</translation>
+ </message>
+ <message>
+ <source>&Save</source>
+ <translation>&บันทึก</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>เปิด</translation>
+ </message>
+ <message>
+ <source>%1 already exists.
+Do you want to replace it?</source>
+ <translation>%1 มีอยู่แล้ว
+คุณต้องการแทนที่หรือไม่?</translation>
+ </message>
+ <message>
+ <source>%1
+File not found.
+Please verify the correct file name was given.</source>
+ <translation>%1
+ไม่พบไฟล์
+โปรดตรวจสอบว่าชื่อไฟล์ที่ให้ไว้ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>My Computer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>เ&ปลี่ยนชื่อ</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&ลบ</translation>
+ </message>
+ <message>
+ <source>Show &hidden files</source>
+ <translation>แสดงไฟล์&ซ่อน</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>ย้อนกลับ</translation>
+ </message>
+ <message>
+ <source>Parent Directory</source>
+ <translation>ไดเรกทอรีชั้นก่อนหน้า</translation>
+ </message>
+ <message>
+ <source>List View</source>
+ <translation>มุมมองรายการ</translation>
+ </message>
+ <message>
+ <source>Detail View</source>
+ <translation>มุมมองรายละเอียด</translation>
+ </message>
+ <message>
+ <source>Files of type:</source>
+ <translation>ชนิดของไฟล์:</translation>
+ </message>
+ <message>
+ <source>Directory:</source>
+ <translation>ไดเรกทอรี:</translation>
+ </message>
+ <message>
+ <source>%1
+Directory not found.
+Please verify the correct directory name was given.</source>
+ <translation>%1
+ไม่พบไดเรกทอรี
+โปรดตรวจสอบว่าชื่อไดเรกทอรีที่ให้ไว้ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>'%1' is write protected.
+Do you want to delete it anyway?</source>
+ <translation>'%1' ถูกป้องกันการเขียนไว้
+คุณยังต้องการลบอยู่หรือไม่?</translation>
+ </message>
+ <message>
+ <source>Are sure you want to delete '%1'?</source>
+ <translation>แน่ใจหรือไม่ว่าคุณต้องการลบ '%1'?</translation>
+ </message>
+ <message>
+ <source>Could not delete directory.</source>
+ <translation>ไม่สามารถลบไดเรกทอรีได้</translation>
+ </message>
+ <message>
+ <source>Save As</source>
+ <translation>บันทึกเป็น</translation>
+ </message>
+ <message>
+ <source>Drive</source>
+ <translation>ไดรฟ์</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>ไฟล์</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation>ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source>Find Directory</source>
+ <translation>ค้นหาไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Show </source>
+ <translation>แสดง</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>ถัดไป</translation>
+ </message>
+ <message>
+ <source>New Folder</source>
+ <translation>โฟลเดอร์ใหม่</translation>
+ </message>
+ <message>
+ <source>&New Folder</source>
+ <translation>โฟลเดอร์ให&ม่</translation>
+ </message>
+ <message>
+ <source>&Choose</source>
+ <translation>เ&ลือก</translation>
+ </message>
+ <message>
+ <source>Remove</source>
+ <translation>ลบ</translation>
+ </message>
+ <message>
+ <source>File &name:</source>
+ <translation>&ชื่อไฟล์:</translation>
+ </message>
+ <message>
+ <source>Look in:</source>
+ <translation>ดูใน:</translation>
+ </message>
+ <message>
+ <source>Create New Folder</source>
+ <translation>สร้างโฟลเดอร์ใหม่</translation>
+ </message>
+</context>
+<context>
+ <name>QFileSystemModel</name>
+ <message>
+ <source>Invalid filename</source>
+ <translation>ชื่อไฟล์ไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source><b>The name "%1" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.</source>
+ <translation><b>ไม่สามาถใช้ชื่อ "%1" ได้</b><p>โปรดลองใช้ชื่ออื่นที่มีตัวอักษรน้อยลงหรืองดใช้เครื่องหมายวรรคตอน</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>ขนาด</translation>
+ </message>
+ <message>
+ <source>Kind</source>
+ <comment>Match OS X Finder</comment>
+ <translation>ชนิด</translation>
+ </message>
+ <message>
+ <source>Type</source>
+ <comment>All other platforms</comment>
+ <translation>ชนิด</translation>
+ </message>
+ <message>
+ <source>Date Modified</source>
+ <translation>วันที่แก้ไข</translation>
+ </message>
+ <message>
+ <source>My Computer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Computer</source>
+ <translation>คอมพิวเตอร์</translation>
+ </message>
+ <message>
+ <source>%1 TB</source>
+ <translation>%1 TB</translation>
+ </message>
+ <message>
+ <source>%1 GB</source>
+ <translation>%1 GB</translation>
+ </message>
+ <message>
+ <source>%1 MB</source>
+ <translation>%1 MB</translation>
+ </message>
+ <message>
+ <source>%1 KB</source>
+ <translation>%1 KB</translation>
+ </message>
+ <message>
+ <source>%1 bytes</source>
+ <translation>%1 ไบต์</translation>
+ </message>
+</context>
+<context>
+ <name>QFontDatabase</name>
+ <message>
+ <source>Normal</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Bold</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Demi Bold</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Black</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Demi</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Light</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Italic</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Oblique</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Any</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Latin</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Greek</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cyrillic</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Armenian</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Hebrew</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Arabic</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Syriac</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Thaana</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Devanagari</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Bengali</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Gurmukhi</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Gujarati</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Oriya</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Tamil</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Telugu</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Kannada</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Malayalam</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sinhala</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Thai</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Lao</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Tibetan</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Myanmar</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Georgian</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Khmer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Simplified Chinese</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Traditional Chinese</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Japanese</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Korean</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Vietnamese</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Symbol</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ogham</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Runic</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QFontDialog</name>
+ <message>
+ <source>&Font</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Font st&yle</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Size</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Effects</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Stri&keout</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Underline</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sample</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Wr&iting System</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Select Font</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QFtp</name>
+ <message>
+ <source>Not connected</source>
+ <translation>ไม่ได้เชื่อมต่อไว้</translation>
+ </message>
+ <message>
+ <source>Host %1 not found</source>
+ <translation>ไม่พบโฮสต์ %1</translation>
+ </message>
+ <message>
+ <source>Connection refused to host %1</source>
+ <translation>ถูกปฏิเสธการเชื่อมต่อไปยังโฮสต์ %1</translation>
+ </message>
+ <message>
+ <source>Connected to host %1</source>
+ <translation>เชื่อมต่อกับโฮสต์ %1</translation>
+ </message>
+ <message>
+ <source>Connection refused for data connection</source>
+ <translation>การเชื่อมต่อเพื่อส่งข้อมูลถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>ข้อผิดพลาดที่ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source>Connecting to host failed:
+%1</source>
+ <translation>การเชื่อมต่อไปยังโฮสต์ %1 ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Login failed:
+%1</source>
+ <translation>การล็อกอินล้มเหลว:
+%1</translation>
+ </message>
+ <message>
+ <source>Listing directory failed:
+%1</source>
+ <translation>การแสดงไดเรกทอรีล้มเหลว:
+%1</translation>
+ </message>
+ <message>
+ <source>Changing directory failed:
+%1</source>
+ <translation>การเปลี่ยนไดเรกทอรีล้มเหลว:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading file failed:
+%1</source>
+ <translation>การดาวน์โหลดไฟล์ล้มเหลว:
+%1</translation>
+ </message>
+ <message>
+ <source>Uploading file failed:
+%1</source>
+ <translation>การอัพโหลดไฟล์ล้มเหลว:
+%1</translation>
+ </message>
+ <message>
+ <source>Removing file failed:
+%1</source>
+ <translation>การลบไฟล์ล้มเหลว:
+%1</translation>
+ </message>
+ <message>
+ <source>Creating directory failed:
+%1</source>
+ <translation>การสร้างไดเรกทอรีล้มเหลว:
+%1</translation>
+ </message>
+ <message>
+ <source>Removing directory failed:
+%1</source>
+ <translation>การลบไดเรกทอรีล้มเหลว:
+%1</translation>
+ </message>
+ <message>
+ <source>Connection closed</source>
+ <translation>การเชื่อมต่อถูกปิดแล้ว</translation>
+ </message>
+ <message>
+ <source>Host %1 found</source>
+ <translation>พบโฮสต์ %1</translation>
+ </message>
+ <message>
+ <source>Connection to %1 closed</source>
+ <translation>การเชื่อมต่อไปยัง %1 ถูกปิดแล้ว</translation>
+ </message>
+ <message>
+ <source>Host found</source>
+ <translation>พบโฮสต์</translation>
+ </message>
+ <message>
+ <source>Connected to host</source>
+ <translation>เชื่อมต่อกับโฮสต์แล้ว</translation>
+ </message>
+</context>
+<context>
+ <name>QHostInfo</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>ข้อผิดพลาดที่ไม่รู้จัก</translation>
+ </message>
+</context>
+<context>
+ <name>QHostInfoAgent</name>
+ <message>
+ <source>Host not found</source>
+ <translation>ไม่พบโฮสต์</translation>
+ </message>
+ <message>
+ <source>Unknown address type</source>
+ <translation>ไม่รู้จักชนิดของแอดเดรส</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>ข้อผิดพลาดที่ไม่รู้จัก</translation>
+ </message>
+</context>
+<context>
+ <name>QHttp</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>ข้อผิดพลาดที่ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source>Request aborted</source>
+ <translation>คำขอถูกยกเลิก</translation>
+ </message>
+ <message>
+ <source>No server set to connect to</source>
+ <translation>ไม่ได้กำหนดเซอร์ฟเวอร์เพื่อเชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>Wrong content length</source>
+ <translation>ความยาวเนื้อหาไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Server closed connection unexpectedly</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Connection refused</source>
+ <translation>การเชื่อมต่อถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>Host %1 not found</source>
+ <translation>ไม่พบโฮสต์ %1</translation>
+ </message>
+ <message>
+ <source>HTTP request failed</source>
+ <translation>คำขอ HTTP ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>Invalid HTTP response header</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Invalid HTTP chunked body</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Host %1 found</source>
+ <translation>พบโฮสต์ %1</translation>
+ </message>
+ <message>
+ <source>Connected to host %1</source>
+ <translation>เชื่อมต่อกับโฮสต์ %1</translation>
+ </message>
+ <message>
+ <source>Connection to %1 closed</source>
+ <translation>การเชื่อมต่อไปยัง %1 ถูกปิดแล้ว</translation>
+ </message>
+ <message>
+ <source>Host found</source>
+ <translation>พบโฮสต์</translation>
+ </message>
+ <message>
+ <source>Connected to host</source>
+ <translation>เชื่อมต่อกับโฮสต์แล้ว</translation>
+ </message>
+ <message>
+ <source>Connection closed</source>
+ <translation>การเชื่อมต่อถูกปิดแล้ว</translation>
+ </message>
+ <message>
+ <source>Proxy authentication required</source>
+ <translation>จำเป็นต้องพิสูจน์ตัวจริงสำหรับพรอกซี</translation>
+ </message>
+ <message>
+ <source>Authentication required</source>
+ <translation>จำเป็นต้องพิสูจน์ตัวจริง</translation>
+ </message>
+ <message>
+ <source>Connection refused (or timed out)</source>
+ <translation>การเชื่อมต่อถูกปฏิเสธ (หรือหมดเวลา)</translation>
+ </message>
+ <message>
+ <source>Proxy requires authentication</source>
+ <translation>พรอกซีต้องใช้การพิสูจน์ตัวจริง</translation>
+ </message>
+ <message>
+ <source>Host requires authentication</source>
+ <translation>โฮสต์ต้องใช้การพิสูจน์ตัวจริง</translation>
+ </message>
+ <message>
+ <source>Data corrupted</source>
+ <translation>ข้อมูลผิดพลาด</translation>
+ </message>
+ <message>
+ <source>Unknown protocol specified</source>
+ <translation>ไม่รู้จักโพรโทคอลที่ระบุ</translation>
+ </message>
+ <message>
+ <source>SSL handshake failed</source>
+ <translation>การเชื่อมต่อ SSL ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>HTTPS connection requested but SSL support not compiled in</source>
+ <translation>เกิดการขอเชื่อมต่อ HTTPS แต่การรองรับ SSL ไม่ได้ถูกคอมไพล์ไว้</translation>
+ </message>
+</context>
+<context>
+ <name>QHttpSocketEngine</name>
+ <message>
+ <source>Authentication required</source>
+ <translation>จำเป็นต้องพิสูจน์ตัวจริง</translation>
+ </message>
+</context>
+<context>
+ <name>QIBaseDriver</name>
+ <message>
+ <source>Error opening database</source>
+ <translation>ไม่สามารถเปิดฐานข้อมูลได้</translation>
+ </message>
+ <message>
+ <source>Could not start transaction</source>
+ <translation>ไม่สามารถเริ่มรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to commit transaction</source>
+ <translation>ไม่สามารถคอมมิทรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to rollback transaction</source>
+ <translation>ไม่สามารถย้อนรายการกลับได้</translation>
+ </message>
+</context>
+<context>
+ <name>QIBaseResult</name>
+ <message>
+ <source>Unable to create BLOB</source>
+ <translation>ไม่สามารถสร้างบล็อบได้</translation>
+ </message>
+ <message>
+ <source>Unable to write BLOB</source>
+ <translation>ไม่สามารถเขียนบล็อบได้</translation>
+ </message>
+ <message>
+ <source>Unable to open BLOB</source>
+ <translation>ไม่สามารถเปิดบล็อบได้</translation>
+ </message>
+ <message>
+ <source>Unable to read BLOB</source>
+ <translation>ไม่สามารถอ่านบล็อบได้</translation>
+ </message>
+ <message>
+ <source>Could not find array</source>
+ <translation>ไม่พบแถวลำดับ</translation>
+ </message>
+ <message>
+ <source>Could not get array data</source>
+ <translation>ไม่สามารถรับข้อมูลแถวลำดับได้</translation>
+ </message>
+ <message>
+ <source>Could not get query info</source>
+ <translation>ไม่สามารถรับข้อมูลคิวรีได้</translation>
+ </message>
+ <message>
+ <source>Could not start transaction</source>
+ <translation>ไม่สามารถเริ่มรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to commit transaction</source>
+ <translation>ไม่สามารถคอมมิทรายการได้</translation>
+ </message>
+ <message>
+ <source>Could not allocate statement</source>
+ <translation>ไม่สามารถจองข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Could not prepare statement</source>
+ <translation>ไม่สามารถเตรียมข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Could not describe input statement</source>
+ <translation>ไม่สามารถอธิบายข้อความสั่งการรับเข้าได้</translation>
+ </message>
+ <message>
+ <source>Could not describe statement</source>
+ <translation>ไม่สามารถอธิบายข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to close statement</source>
+ <translation>ไม่สามารถปิดข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to execute query</source>
+ <translation>ไม่สามารถประมวลผลคิวรีได้</translation>
+ </message>
+ <message>
+ <source>Could not fetch next item</source>
+ <translation>ไม่สามารถเรียกรายการถัดไปได้</translation>
+ </message>
+ <message>
+ <source>Could not get statement info</source>
+ <translation>ไม่สามารถรับข้อมูลข้อความสั่งการได้</translation>
+ </message>
+</context>
+<context>
+ <name>QIODevice</name>
+ <message>
+ <source>Permission denied</source>
+ <translation>คำขออนุญาตถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>Too many open files</source>
+ <translation>มีไฟล์ถูกเปิดมากเกินไป</translation>
+ </message>
+ <message>
+ <source>No such file or directory</source>
+ <translation>ไม่พบไฟล์หรือไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>No space left on device</source>
+ <translation>ไม่มีพื้นที่เหลือบนอุปกรณ์</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>ข้อผิดพลาดที่ไม่รู้จัก</translation>
+ </message>
+</context>
+<context>
+ <name>QInputContext</name>
+ <message>
+ <source>XIM</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>XIM input method</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Windows input method</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Mac OS X input method</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QLibrary</name>
+ <message>
+ <source>QLibrary::load_sys: Cannot load %1 (%2)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>QLibrary::unload_sys: Cannot unload %1 (%2)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>QLibrary::resolve_sys: Symbol "%1" undefined in %2 (%3)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Could not mmap '%1': %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Plugin verification data mismatch in '%1'</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Could not unmap '%1': %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The plugin '%1' uses incompatible Qt library. Expected build key "%2", got "%3"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>ข้อผิดพลาดที่ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source>The shared library was not found.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The file '%1' is not a valid Qt plugin.</source>
+ <translation>ไฟล์ '%1' ไม่ใช่ปลั๊กอิน Qt</translation>
+ </message>
+ <message>
+ <source>The plugin '%1' uses incompatible Qt library. (Cannot mix debug and release libraries.)</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QLineEdit</name>
+ <message>
+ <source>&Undo</source>
+ <translation>เ&ลิกทำ</translation>
+ </message>
+ <message>
+ <source>&Redo</source>
+ <translation>ทำ&ซ้ำ</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>&ตัด</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&คัดลอก</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&วาง</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>ลบ</translation>
+ </message>
+ <message>
+ <source>Select All</source>
+ <translation>เลือกทั้งหมด</translation>
+ </message>
+</context>
+<context>
+ <name>QLocalServer</name>
+ <message>
+ <source>%1: Name error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: Permission denied</source>
+ <translation>%1: คำขออนุญาตถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>%1: Address in use</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: Unknown error %2</source>
+ <translation>%1: ข้อผิดพลาดที่ไม่รู้จัก %2</translation>
+ </message>
+</context>
+<context>
+ <name>QLocalSocket</name>
+ <message>
+ <source>%1: Connection refused</source>
+ <translation>%1: การเชื่อมต่อถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>%1: Remote closed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: Invalid name</source>
+ <translation>%1: ชื่อไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>%1: Socket access error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: Socket resource error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: Socket operation timed out</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: Datagram too large</source>
+ <translation>%1: เดทาแกรมใหญ่เกินไป</translation>
+ </message>
+ <message>
+ <source>%1: Connection error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: The socket operation is not supported</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: Unknown error %2</source>
+ <translation>%1: ข้อผิดพลาดที่ไม่รู้จัก %2</translation>
+ </message>
+</context>
+<context>
+ <name>QMYSQLDriver</name>
+ <message>
+ <source>Unable to open database '</source>
+ <translation>ไม่สามารถเปิดฐานข้อมูล '</translation>
+ </message>
+ <message>
+ <source>Unable to connect</source>
+ <translation>ไม่สามารถเชื่อมต่อได้</translation>
+ </message>
+ <message>
+ <source>Unable to begin transaction</source>
+ <translation>ไม่สามารถเริ่มรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to commit transaction</source>
+ <translation>ไม่สามารถคอมมิทรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to rollback transaction</source>
+ <translation>ไม่สามารถย้อนรายการกลับได้</translation>
+ </message>
+</context>
+<context>
+ <name>QMYSQLResult</name>
+ <message>
+ <source>Unable to fetch data</source>
+ <translation>ไม่สามารถเรียกข้อมูลได้</translation>
+ </message>
+ <message>
+ <source>Unable to execute query</source>
+ <translation>ไม่สามารถประมวลผลคิวรีได้</translation>
+ </message>
+ <message>
+ <source>Unable to store result</source>
+ <translation>ไม่สามารถเก็บผลลัพธ์ได้</translation>
+ </message>
+ <message>
+ <source>Unable to prepare statement</source>
+ <translation>ไม่สามารถเตรียมข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to reset statement</source>
+ <translation>ไม่สามารถรีเซ็ตข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to bind value</source>
+ <translation>ไม่สามารถเชื่อมโยงค่าได้</translation>
+ </message>
+ <message>
+ <source>Unable to execute statement</source>
+ <translation>ไม่สามารถประมวลผลข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to bind outvalues</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to store statement results</source>
+ <translation>ไม่สามารถเก็บผลลัพธ์ของข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to execute next query</source>
+ <translation>ไม่สามารถประมวลผลคิวรีถัดไปได้</translation>
+ </message>
+ <message>
+ <source>Unable to store next result</source>
+ <translation>ไม่สามารถเก็บผลลัพธ์ถัดไปได้</translation>
+ </message>
+</context>
+<context>
+ <name>QMdiArea</name>
+ <message>
+ <source>(Untitled)</source>
+ <translation>(ไม่มีชื่อ)</translation>
+ </message>
+</context>
+<context>
+ <name>QMdiSubWindow</name>
+ <message>
+ <source>%1 - [%2]</source>
+ <translation>%1 - [%2]</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Minimize</source>
+ <translation>ย่อให้เล็กสุด</translation>
+ </message>
+ <message>
+ <source>Restore Down</source>
+ <translation>คืนขนาดลง</translation>
+ </message>
+ <message>
+ <source>&Restore</source>
+ <translation>&คืนค่า</translation>
+ </message>
+ <message>
+ <source>&Move</source>
+ <translation>&ย้าย</translation>
+ </message>
+ <message>
+ <source>&Size</source>
+ <translation>&ขนาด</translation>
+ </message>
+ <message>
+ <source>Mi&nimize</source>
+ <translation>ย่อให้เ&ล็กสุด</translation>
+ </message>
+ <message>
+ <source>Ma&ximize</source>
+ <translation>ขยายให้ให&ญ่สุด</translation>
+ </message>
+ <message>
+ <source>Stay on &Top</source>
+ <translation>แสดงไว้&บนสุด</translation>
+ </message>
+ <message>
+ <source>&Close</source>
+ <translation>&ปิด</translation>
+ </message>
+ <message>
+ <source>- [%1]</source>
+ <translation>- [%1]</translation>
+ </message>
+ <message>
+ <source>Maximize</source>
+ <translation>ขยายให้ใหญ่สุด</translation>
+ </message>
+ <message>
+ <source>Unshade</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Shade</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Restore</source>
+ <translation>คืนค่า</translation>
+ </message>
+ <message>
+ <source>Help</source>
+ <translation>ช่วยเหลือ</translation>
+ </message>
+ <message>
+ <source>Menu</source>
+ <translation>เมนู</translation>
+ </message>
+</context>
+<context>
+ <name>QMenu</name>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>เปิด</translation>
+ </message>
+ <message>
+ <source>Execute</source>
+ <translation>ประมวลผล</translation>
+ </message>
+</context>
+<context>
+ <name>QMessageBox</name>
+ <message>
+ <source>Help</source>
+ <translation>ช่วยเหลือ</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ตกลง</translation>
+ </message>
+ <message>
+ <source>About Qt</source>
+ <translation>เกี่ยวกับ Qt</translation>
+ </message>
+ <message>
+ <source><p>This program uses Qt version %1.</p></source>
+ <translation><p>โปรแกรมนี้ใช้ Qt รุ่น %1</p></translation>
+ </message>
+ <message>
+ <source>Show Details...</source>
+ <translation>แสดงรายละเอียด...</translation>
+ </message>
+ <message>
+ <source>Hide Details...</source>
+ <translation>ซ่อนรายละเอียด...</translation>
+ </message>
+ <message>
+ <source><p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <a href="http://www.trolltech.com/company/model/">www.trolltech.com/company/model/</a> for an overview of Qt licensing.</p></source>
+ <translation><p>โปรแกรมนี้ใช้ Qt แบบโอเพนซอร์สรุ่น %1.</p><p>Qt แบบโอเพนซอร์สมีวัตถุประสงค์เพื่อใช้สำหรับการพัฒนาแอพพลิเคชันแบบโอเพนซอร์ส คุณต้องการไลเซนส์ Qt เชิงพาณิชย์สำหรับการพัฒนาแอพพลิเคชันแบบมีกรรมสิทธิ (โคลสซอร์ส)</p><p>โปรดดูรายละเอียดเพิ่มเติมเกี่ยวกับการใช้ไลเซนส์ Qt ได้ที่ <a href="http://www.trolltech.com/company/model/">www.trolltech.com/company/model/</a></p></translation>
+ </message>
+ <message>
+ <source><h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS Windows, Mac OS X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt for Embedded Linux and Qt for Windows CE.</p><p>Qt is a Nokia product. See <a href="http://www.trolltech.com/qt/">www.trolltech.com/qt/&l [...]
+ <translation><h3>เกี่ยวกับ Qt</h3>%1<p>Qt เป็นชุดเครื่องมือสำหรับการพัฒนาแอพพลิเคชัน C++ แบบข้ามแพลตฟอร์ม</p><p>Qt ช่วยให้สามารถใช้ซอร์สโค๊ดร่วมกันข้ามแพลตฟอร์มตั้งแต่ไมโครซอฟต์วินโดวส์, แมคโอเอส X, ลินุกซ์ และระบบปฏิบัติการในกลุ่มยูนิกส์เชิงพาณิชย์ที่ใช้อย่างแพร่หลาย และ Qt ยังมีรุ่นสำหรับใช้กับระบบคอมพิวเตอร์ฝังตัวได้แก่ Qt สำหรับลินุกส์แบบฝังตัว และ Qt สำหรับวินโดวส์ CE</p><p>Qt เป็นผลิตภัณฑ์ของโนเกีย โปรดดูรายละเอียดเพิ่มเติม [...]
+ </message>
+</context>
+<context>
+ <name>QMultiInputContext</name>
+ <message>
+ <source>Select IM</source>
+ <translation>เลือก IM</translation>
+ </message>
+</context>
+<context>
+ <name>QMultiInputContextPlugin</name>
+ <message>
+ <source>Multiple input method switcher</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Multiple input method switcher that uses the context menu of the text widgets</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QNativeSocketEngine</name>
+ <message>
+ <source>The remote host closed the connection</source>
+ <translation>โฮสต์ปลายทางปิดการเชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>Network operation timed out</source>
+ <translation>หมดเวลากระบวนการทางเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Out of resources</source>
+ <translation>ทรัพยากรไม่พอ</translation>
+ </message>
+ <message>
+ <source>Unsupported socket operation</source>
+ <translation>ไม่รองรับกระบวนการซ็อคเก็ตนี้</translation>
+ </message>
+ <message>
+ <source>Protocol type not supported</source>
+ <translation>ไม่รองรับโพรโทคอลชนิดนี้</translation>
+ </message>
+ <message>
+ <source>Invalid socket descriptor</source>
+ <translation>ตัวอธิบายซ็อคเก็ตไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Network unreachable</source>
+ <translation>ไม่สามารถเข้าถึงเครือข่ายได้</translation>
+ </message>
+ <message>
+ <source>Permission denied</source>
+ <translation>คำขออนุญาตถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>Connection timed out</source>
+ <translation>หมดเวลาการเชื่อมต่อ</translation>
+ </message>
+ <message>
+ <source>Connection refused</source>
+ <translation>การเชื่อมต่อถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>The bound address is already in use</source>
+ <translation>แอดเดรสที่ผูกไว้ถูกใช้งานอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>The address is not available</source>
+ <translation>ไม่สามารถใช้งานแอดเดรสได้</translation>
+ </message>
+ <message>
+ <source>The address is protected</source>
+ <translation>แอดเดรสถูกป้องกันไว้</translation>
+ </message>
+ <message>
+ <source>Unable to send a message</source>
+ <translation>ไม่สามารถส่งข้อความได้</translation>
+ </message>
+ <message>
+ <source>Unable to receive a message</source>
+ <translation>ไม่สามารถรับข้อความได้</translation>
+ </message>
+ <message>
+ <source>Unable to write</source>
+ <translation>ไม่สามารถเขียนได้</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>เครือข่ายผิดพลาด</translation>
+ </message>
+ <message>
+ <source>Another socket is already listening on the same port</source>
+ <translation>มีซ็อคเก็ตอื่นกำลังใช้งานพอร์ตเดียวกันอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>Unable to initialize non-blocking socket</source>
+ <translation>ไม่สามารถเริ่มซ็อคเก็ตแบบไม่บล็อกได้</translation>
+ </message>
+ <message>
+ <source>Unable to initialize broadcast socket</source>
+ <translation>ไม่สามารถเริ่มซ็อคเก็ตบรอดคาสต์ได้</translation>
+ </message>
+ <message>
+ <source>Attempt to use IPv6 socket on a platform with no IPv6 support</source>
+ <translation>พยายามใช้ซ็อคเก็ต IPv6 บนแพลตฟอร์มที่ไม่รองรับ IPv6</translation>
+ </message>
+ <message>
+ <source>Host unreachable</source>
+ <translation>ไม่สามารถเข้าถึงโฮสต์ได้</translation>
+ </message>
+ <message>
+ <source>Datagram was too large to send</source>
+ <translation>เดทาแกรมใหญ่เกินกว่าจะส่งได้</translation>
+ </message>
+ <message>
+ <source>Operation on non-socket</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>ข้อผิดพลาดที่ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source>The proxy type is invalid for this operation</source>
+ <translation>ชนิดของพรอกซีใช้ไม่ได้สำหรับกระบวนการนี้</translation>
+ </message>
+</context>
+<context>
+ <name>QNetworkAccessFileBackend</name>
+ <message>
+ <source>Request for opening non-local file %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error opening %1: %2</source>
+ <translation>ความผิดพลาดขณะเปิด %1: %2</translation>
+ </message>
+ <message>
+ <source>Write error writing to %1: %2</source>
+ <translation>เกิดความผิดพลาดขณะเขียนไปยัง %1: %2</translation>
+ </message>
+ <message>
+ <source>Cannot open %1: Path is a directory</source>
+ <translation>ไม่สามารถเปิด %1: เส้นทางเป็นไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Read error reading from %1: %2</source>
+ <translation>เกิดความผิดพลาดขณะอ่านจาก %1: %2</translation>
+ </message>
+</context>
+<context>
+ <name>QNetworkAccessFtpBackend</name>
+ <message>
+ <source>Cannot open %1: is a directory</source>
+ <translation>ไม่สามารถเปิด %1: เป็นไดเรกทอรี</translation>
+ </message>
+ <message>
+ <source>Logging in to %1 failed: authentication required</source>
+ <translation>การลงชื่อเข้า %1 ล้มเหลว: จำเป็นต้องพิสูจน์ตัวจริง</translation>
+ </message>
+ <message>
+ <source>Error while downloading %1: %2</source>
+ <translation>เกิดความผิดพลาดขณะดาวน์โหลด %1: %2</translation>
+ </message>
+ <message>
+ <source>Error while uploading %1: %2</source>
+ <translation>เกิดความผิดพลาดขณะอัพโหลด %1: %2</translation>
+ </message>
+</context>
+<context>
+ <name>QNetworkReply</name>
+ <message>
+ <source>Error downloading %1 - server replied: %2</source>
+ <translation>การดาวน์โหลด %1 ผิดพลาด - เซอร์ฟเวอร์ตอบว่า: %2</translation>
+ </message>
+ <message>
+ <source>Protocol "%1" is unknown</source>
+ <translation>ไม่รู้จักโพรโทคอล `%1'</translation>
+ </message>
+</context>
+<context>
+ <name>QNetworkReplyImpl</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>การดำเนินการถูกยกเลิก</translation>
+ </message>
+</context>
+<context>
+ <name>QOCIDriver</name>
+ <message>
+ <source>Unable to logon</source>
+ <translation>ไม่สามารถลงบันทึกเปิดได้</translation>
+ </message>
+ <message>
+ <source>Unable to initialize</source>
+ <comment>QOCIDriver</comment>
+ <translation>ไม่สามารถเริ่มได้</translation>
+ </message>
+ <message>
+ <source>Unable to begin transaction</source>
+ <translation>ไม่สามารถเริ่มรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to commit transaction</source>
+ <translation>ไม่สามารถคอมมิทรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to rollback transaction</source>
+ <translation>ไม่สามารถย้อนรายการกลับได้</translation>
+ </message>
+</context>
+<context>
+ <name>QOCIResult</name>
+ <message>
+ <source>Unable to bind column for batch execute</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to execute batch statement</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to goto next</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to alloc statement</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to prepare statement</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to bind value</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to execute select statement</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to execute statement</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QODBCDriver</name>
+ <message>
+ <source>Unable to connect</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to connect - Driver doesn't support all needed functionality</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to disable autocommit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to commit transaction</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to rollback transaction</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to enable autocommit</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QODBCResult</name>
+ <message>
+ <source>QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to execute statement</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to fetch next</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to prepare statement</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to bind variable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to fetch last</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to fetch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to fetch first</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to fetch previous</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>Operation not supported on %1</source>
+ <translation>กระบวนการที่ไม่รองรับบน %1</translation>
+ </message>
+ <message>
+ <source>Invalid URI: %1</source>
+ <translation>URI ไม่ถูกต้อง: %1</translation>
+ </message>
+ <message>
+ <source>Write error writing to %1: %2</source>
+ <translation>เกิดความผิดพลาดขณะเขียนไปยัง %1: %2</translation>
+ </message>
+ <message>
+ <source>Read error reading from %1: %2</source>
+ <translation>เกิดความผิดพลาดขณะอ่านจาก %1: %2</translation>
+ </message>
+ <message>
+ <source>Socket error on %1: %2</source>
+ <translation>เกิดความผิดพลาดซ็อคเก็ตบน %1: %2</translation>
+ </message>
+ <message>
+ <source>Remote host closed the connection prematurely on %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Protocol error: packet of size 0 received</source>
+ <translation>ข้อผิดพลาดโพรโทคอล: ได้รับแพคเก็ตขนาดเป็น 0</translation>
+ </message>
+</context>
+<context>
+ <name>QPPDOptionsModel</name>
+ <message>
+ <source>Name</source>
+ <translation>ชื่อ</translation>
+ </message>
+ <message>
+ <source>Value</source>
+ <translation>ค่า</translation>
+ </message>
+</context>
+<context>
+ <name>QPSQLDriver</name>
+ <message>
+ <source>Unable to connect</source>
+ <translation>ไม่สามารถเชื่อมต่อได้</translation>
+ </message>
+ <message>
+ <source>Could not begin transaction</source>
+ <translation>ไม่สามารถเริ่มรายการได้</translation>
+ </message>
+ <message>
+ <source>Could not commit transaction</source>
+ <translation>ไม่สามารถคอมมิทรายการได้</translation>
+ </message>
+ <message>
+ <source>Could not rollback transaction</source>
+ <translation>ไม่สามารถย้อนรายการกลับได้</translation>
+ </message>
+ <message>
+ <source>Unable to subscribe</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to unsubscribe</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QPSQLResult</name>
+ <message>
+ <source>Unable to create query</source>
+ <translation>ไม่สามารถสร้างคิวรีได้</translation>
+ </message>
+ <message>
+ <source>Unable to prepare statement</source>
+ <translation>ไม่สามารถเตรียมข้อความสั่งการได้</translation>
+ </message>
+</context>
+<context>
+ <name>QPageSetupWidget</name>
+ <message>
+ <source>Centimeters (cm)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Millimeters (mm)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Inches (in)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Points (pt)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Paper</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Page size:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Width:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Height:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Paper source:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Orientation</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Portrait</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Landscape</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Reverse landscape</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Reverse portrait</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Margins</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>top margin</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>left margin</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>right margin</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>bottom margin</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QPluginLoader</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>ข้อผิดพลาดที่ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source>The plugin was not loaded.</source>
+ <translation>ไม่ได้โหลดปลั๊กอิน</translation>
+ </message>
+</context>
+<context>
+ <name>QPrintDialog</name>
+ <message>
+ <source>locally connected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Aliases: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Print To File ...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File %1 is not writable.
+Please choose a different file name.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 already exists.
+Do you want to overwrite it?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is a directory.
+Please choose a different file name.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A0</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A3</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A4</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A5</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A6</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A7</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A8</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A9</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B0</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B3</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B4</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B5</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B6</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B7</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B8</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B9</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>B10</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>C5E</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>DLE</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Executive</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Folio</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ledger</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Legal</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Letter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Tabloid</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>US Common #10 Envelope</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Custom</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Options >></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Print</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Options <<</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Print to File (PDF)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Print to File (Postscript)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Local file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Write %1 file</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QPrintPreviewDialog</name>
+ <message>
+ <source>Page Setup</source>
+ <translation>ตั้งค่าหน้ากระดาษ</translation>
+ </message>
+ <message>
+ <source>Print Preview</source>
+ <translation>ตัวอย่างก่อนพิมพ์</translation>
+ </message>
+ <message>
+ <source>Next page</source>
+ <translation>หน้าถัดไป</translation>
+ </message>
+ <message>
+ <source>Previous page</source>
+ <translation>หน้าก่อน</translation>
+ </message>
+ <message>
+ <source>First page</source>
+ <translation>หน้าแรก</translation>
+ </message>
+ <message>
+ <source>Last page</source>
+ <translation>หน้าสุดท้าย</translation>
+ </message>
+ <message>
+ <source>Fit width</source>
+ <translation>เต็มความกว้าง</translation>
+ </message>
+ <message>
+ <source>Fit page</source>
+ <translation>เต็มหน้า</translation>
+ </message>
+ <message>
+ <source>Zoom in</source>
+ <translation>ซูมเข้า</translation>
+ </message>
+ <message>
+ <source>Zoom out</source>
+ <translation>ซูมออก</translation>
+ </message>
+ <message>
+ <source>Portrait</source>
+ <translation>แนวตั้ง</translation>
+ </message>
+ <message>
+ <source>Landscape</source>
+ <translation>แนวนอน</translation>
+ </message>
+ <message>
+ <source>Show single page</source>
+ <translation>แสดงหน้าเดียว</translation>
+ </message>
+ <message>
+ <source>Show facing pages</source>
+ <translation>แสดงหน้าคู่กัน</translation>
+ </message>
+ <message>
+ <source>Show overview of all pages</source>
+ <translation>แสดงภาพรวมของทุกหน้า</translation>
+ </message>
+ <message>
+ <source>Print</source>
+ <translation>พิมพ์</translation>
+ </message>
+ <message>
+ <source>Page setup</source>
+ <translation>ตั้งค่าหน้ากระดาษ</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+</context>
+<context>
+ <name>QPrintPropertiesWidget</name>
+ <message>
+ <source>Form</source>
+ <translation>ฟอร์ม</translation>
+ </message>
+ <message>
+ <source>Page</source>
+ <translation>หน้า</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>ขั้นสูง</translation>
+ </message>
+</context>
+<context>
+ <name>QPrintSettingsOutput</name>
+ <message>
+ <source>Form</source>
+ <translation>ฟอร์ม</translation>
+ </message>
+ <message>
+ <source>Copies</source>
+ <translation>สำเนา</translation>
+ </message>
+ <message>
+ <source>Print range</source>
+ <translation>ช่วงที่พิมพ์</translation>
+ </message>
+ <message>
+ <source>Print all</source>
+ <translation>พิมพ์ทั้งหมด</translation>
+ </message>
+ <message>
+ <source>Pages from</source>
+ <translation>ตั้งแต่หน้า</translation>
+ </message>
+ <message>
+ <source>to</source>
+ <translation>ถึง</translation>
+ </message>
+ <message>
+ <source>Selection</source>
+ <translation>ส่วนที่เลือก</translation>
+ </message>
+ <message>
+ <source>Output Settings</source>
+ <translation>ตั้งค่าการพิมพ์</translation>
+ </message>
+ <message>
+ <source>Copies:</source>
+ <translation>สำเนา:</translation>
+ </message>
+ <message>
+ <source>Collate</source>
+ <translation>ทีละชุด</translation>
+ </message>
+ <message>
+ <source>Reverse</source>
+ <translation>หลังไปหน้า</translation>
+ </message>
+ <message>
+ <source>Options</source>
+ <translation>ตัวเลือก</translation>
+ </message>
+ <message>
+ <source>Color Mode</source>
+ <translation>โหมดสี</translation>
+ </message>
+ <message>
+ <source>Color</source>
+ <translation>สี</translation>
+ </message>
+ <message>
+ <source>Grayscale</source>
+ <translation>ระดับสีเทา</translation>
+ </message>
+ <message>
+ <source>Duplex Printing</source>
+ <translation>กลับด้านพิมพ์</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>ไม่มี</translation>
+ </message>
+ <message>
+ <source>Long side</source>
+ <translation>ด้านยาว</translation>
+ </message>
+ <message>
+ <source>Short side</source>
+ <translation>ด้านกว้าง</translation>
+ </message>
+</context>
+<context>
+ <name>QPrintWidget</name>
+ <message>
+ <source>Form</source>
+ <translation>ฟอร์ม</translation>
+ </message>
+ <message>
+ <source>Printer</source>
+ <translation>เครื่องพิมพ์</translation>
+ </message>
+ <message>
+ <source>&Name:</source>
+ <translation>&ชื่อ:</translation>
+ </message>
+ <message>
+ <source>P&roperties</source>
+ <translation>&คุณสมบัติ</translation>
+ </message>
+ <message>
+ <source>Location:</source>
+ <translation>ที่ตั้ง:</translation>
+ </message>
+ <message>
+ <source>Preview</source>
+ <translation>แสดงตัวอย่าง</translation>
+ </message>
+ <message>
+ <source>Type:</source>
+ <translation>ชนิด:</translation>
+ </message>
+ <message>
+ <source>Output &file:</source>
+ <translation>ไ&ฟล์ที่ส่งออก:</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+</context>
+<context>
+ <name>QProgressDialog</name>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+</context>
+<context>
+ <name>QPushButton</name>
+ <message>
+ <source>Open</source>
+ <translation>เปิด</translation>
+ </message>
+</context>
+<context>
+ <name>QRadioButton</name>
+ <message>
+ <source>Check</source>
+ <translation>ตรวจสอบ</translation>
+ </message>
+</context>
+<context>
+ <name>QRegExp</name>
+ <message>
+ <source>no error occurred</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>disabled feature used</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>bad char class syntax</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>bad lookahead syntax</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>bad repetition syntax</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>invalid octal value</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>missing left delim</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>unexpected end</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>met internal limit</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QSQLite2Driver</name>
+ <message>
+ <source>Error to open database</source>
+ <translation>ไม่สามารถเปิดฐานข้อมูลได้</translation>
+ </message>
+ <message>
+ <source>Unable to begin transaction</source>
+ <translation>ไม่สามารถเริ่มรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to commit transaction</source>
+ <translation>ไม่สามารถคอมมิทรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to rollback Transaction</source>
+ <translation>ไม่สามารถย้อนรายการกลับได้</translation>
+ </message>
+</context>
+<context>
+ <name>QSQLite2Result</name>
+ <message>
+ <source>Unable to fetch results</source>
+ <translation>ไม่สามารถเรียกผลลัพธ์ได้</translation>
+ </message>
+ <message>
+ <source>Unable to execute statement</source>
+ <translation>ไม่สามารถประมวลผลข้อความสั่งการได้</translation>
+ </message>
+</context>
+<context>
+ <name>QSQLiteDriver</name>
+ <message>
+ <source>Error opening database</source>
+ <translation>ไม่สามารถเปิดฐานข้อมูลได้</translation>
+ </message>
+ <message>
+ <source>Error closing database</source>
+ <translation>ไม่สามารถปิดฐานข้อมูลได้</translation>
+ </message>
+ <message>
+ <source>Unable to begin transaction</source>
+ <translation>ไม่สามารถเริ่มรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to commit transaction</source>
+ <translation>ไม่สามารถคอมมิทรายการได้</translation>
+ </message>
+ <message>
+ <source>Unable to rollback transaction</source>
+ <translation>ไม่สามารถย้อนรายการกลับได้</translation>
+ </message>
+</context>
+<context>
+ <name>QSQLiteResult</name>
+ <message>
+ <source>Unable to fetch row</source>
+ <translation>ไม่สามารถเรียกแถวได้</translation>
+ </message>
+ <message>
+ <source>Unable to execute statement</source>
+ <translation>ไม่สามารถประมวลผลข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to reset statement</source>
+ <translation>ไม่สามารถรีเซ็ตข้อความสั่งการได้</translation>
+ </message>
+ <message>
+ <source>Unable to bind parameters</source>
+ <translation>ไม่สามารถเชื่อมโยงพารามิเตอร์ได้</translation>
+ </message>
+ <message>
+ <source>Parameter count mismatch</source>
+ <translation>จำนวนพารามิเตอร์ไม่เข้ากัน</translation>
+ </message>
+ <message>
+ <source>No query</source>
+ <translation>ไม่มีคิวรี</translation>
+ </message>
+</context>
+<context>
+ <name>QScrollBar</name>
+ <message>
+ <source>Scroll here</source>
+ <translation>เลื่อนมาที่นี่</translation>
+ </message>
+ <message>
+ <source>Left edge</source>
+ <translation>ขอบซ้าย</translation>
+ </message>
+ <message>
+ <source>Top</source>
+ <translation>ด้านบน</translation>
+ </message>
+ <message>
+ <source>Right edge</source>
+ <translation>ขอบขวา</translation>
+ </message>
+ <message>
+ <source>Bottom</source>
+ <translation>ด้านล่าง</translation>
+ </message>
+ <message>
+ <source>Page left</source>
+ <translation>เลื่อนหน้าซ้าย</translation>
+ </message>
+ <message>
+ <source>Page up</source>
+ <translation>เลื่อนหน้าขึ้น</translation>
+ </message>
+ <message>
+ <source>Page right</source>
+ <translation>เลื่อนหน้าขวา</translation>
+ </message>
+ <message>
+ <source>Page down</source>
+ <translation>เลื่อนหน้าลง</translation>
+ </message>
+ <message>
+ <source>Scroll left</source>
+ <translation>เลื่อนซ้าย</translation>
+ </message>
+ <message>
+ <source>Scroll up</source>
+ <translation>เลื่อนขึ้น</translation>
+ </message>
+ <message>
+ <source>Scroll right</source>
+ <translation>เลื่อนขวา</translation>
+ </message>
+ <message>
+ <source>Scroll down</source>
+ <translation>เลื่อนลง</translation>
+ </message>
+ <message>
+ <source>Line up</source>
+ <translation>เลื่อนบรรทัดขึ้น</translation>
+ </message>
+ <message>
+ <source>Position</source>
+ <translation>ตำแหน่ง</translation>
+ </message>
+ <message>
+ <source>Line down</source>
+ <translation>เลื่อนบรรทัดลง</translation>
+ </message>
+</context>
+<context>
+ <name>QSharedMemory</name>
+ <message>
+ <source>%1: unable to set key on lock</source>
+ <translation>%1: ไม่สามารถตั้งคีย์ขณะล็อค</translation>
+ </message>
+ <message>
+ <source>%1: create size is less then 0</source>
+ <translation>%1: ขนาดที่สร้างขึ้นมีค่าน้อยกว่า 0</translation>
+ </message>
+ <message>
+ <source>%1: unable to lock</source>
+ <translation>%1: ไม่สามารถล็อคได้</translation>
+ </message>
+ <message>
+ <source>%1: unable to unlock</source>
+ <translation>%1: ไม่สามารถปลดล็อคได้</translation>
+ </message>
+ <message>
+ <source>%1: permission denied</source>
+ <translation>%1: คำขออนุญาตถูกปฏิเสธ</translation>
+ </message>
+ <message>
+ <source>%1: already exists</source>
+ <translation>%1: มีอยู่แล้ว</translation>
+ </message>
+ <message>
+ <source>%1: doesn't exists</source>
+ <translation>%1: ไม่พบ</translation>
+ </message>
+ <message>
+ <source>%1: out of resources</source>
+ <translation>%1: ทรัพยากรไม่พอ</translation>
+ </message>
+ <message>
+ <source>%1: unknown error %2</source>
+ <translation>%1: ข้อผิดพลาดที่ไม่รู้จัก %2</translation>
+ </message>
+ <message>
+ <source>%1: key is empty</source>
+ <translation>%1: คีย์ว่างอยู่</translation>
+ </message>
+ <message>
+ <source>%1: unix key file doesn't exists</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: ftok failed</source>
+ <translation>%1: ftok ล้มเหลว</translation>
+ </message>
+ <message>
+ <source>%1: unable to make key</source>
+ <translation>%1: ไม่สามารถสร้างคีย์</translation>
+ </message>
+ <message>
+ <source>%1: system-imposed size restrictions</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1: not attached</source>
+ <translation>%1: ไม่ได้เชื่อมต่อไว้</translation>
+ </message>
+</context>
+<context>
+ <name>QShortcut</name>
+ <message>
+ <source>Space</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Esc</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Tab</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Backtab</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Backspace</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Return</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enter</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ins</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Del</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Pause</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Print</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>SysReq</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>End</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Left</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Up</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Right</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Down</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>PgUp</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>PgDown</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>CapsLock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>NumLock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>ScrollLock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Menu</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Help</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>ย้อนกลับ</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>ถัดไป</translation>
+ </message>
+ <message>
+ <source>Stop</source>
+ <translation>หยุด</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>เรียกซ้ำ</translation>
+ </message>
+ <message>
+ <source>Volume Down</source>
+ <translation>ลดเสียง</translation>
+ </message>
+ <message>
+ <source>Volume Mute</source>
+ <translation>ปิดเสียง</translation>
+ </message>
+ <message>
+ <source>Volume Up</source>
+ <translation>เพิ่มเสียง</translation>
+ </message>
+ <message>
+ <source>Bass Boost</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Bass Up</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Bass Down</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Treble Up</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Treble Down</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Media Play</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Media Stop</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Media Previous</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Media Next</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Media Record</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Favorites</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>ค้นหา</translation>
+ </message>
+ <message>
+ <source>Standby</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Open URL</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch Mail</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch Media</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (0)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (1)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (2)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (3)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (4)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (5)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (6)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (7)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (8)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (9)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (A)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (B)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (C)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (D)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (E)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Launch (F)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Print Screen</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Page Up</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Page Down</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Caps Lock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Num Lock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Number Lock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Scroll Lock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Insert</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Escape</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>System Request</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Context1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Context2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Context3</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Context4</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Call</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Hangup</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Flip</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ctrl</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Shift</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Alt</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Meta</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>+</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>F%1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Home Page</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QSlider</name>
+ <message>
+ <source>Page left</source>
+ <translation>เลื่อนหน้าซ้าย</translation>
+ </message>
+ <message>
+ <source>Page up</source>
+ <translation>เลื่อนหน้าขึ้น</translation>
+ </message>
+ <message>
+ <source>Position</source>
+ <translation>ตำแหน่ง</translation>
+ </message>
+ <message>
+ <source>Page right</source>
+ <translation>เลื่อนหน้าขวา</translation>
+ </message>
+ <message>
+ <source>Page down</source>
+ <translation>เลื่อนหน้าลง</translation>
+ </message>
+</context>
+<context>
+ <name>QSocks5SocketEngine</name>
+ <message>
+ <source>Socks5 timeout error connecting to socks server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Network operation timed out</source>
+ <translation>หมดเวลากระบวนการทางเครือข่าย</translation>
+ </message>
+</context>
+<context>
+ <name>QSpinBox</name>
+ <message>
+ <source>More</source>
+ <translation>เพิ่มขึ้น</translation>
+ </message>
+ <message>
+ <source>Less</source>
+ <translation>ลดลง</translation>
+ </message>
+</context>
+<context>
+ <name>QSql</name>
+ <message>
+ <source>Delete</source>
+ <translation>ลบ</translation>
+ </message>
+ <message>
+ <source>Delete this record?</source>
+ <translation>ลบระเบียนนี้?</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>ใช่</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>ไม่ใช่</translation>
+ </message>
+ <message>
+ <source>Insert</source>
+ <translation>แทรก</translation>
+ </message>
+ <message>
+ <source>Update</source>
+ <translation>อัพเดต</translation>
+ </message>
+ <message>
+ <source>Save edits?</source>
+ <translation>บันทึกการแก้ไข?</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+ <message>
+ <source>Confirm</source>
+ <translation>ยืนยัน</translation>
+ </message>
+ <message>
+ <source>Cancel your edits?</source>
+ <translation>ยกเลิกการแก้ไขของคุณ?</translation>
+ </message>
+</context>
+<context>
+ <name>QSslSocket</name>
+ <message>
+ <source>Unable to write data: %1</source>
+ <translation>ไม่สามารถเขียนข้อมูล: %1</translation>
+ </message>
+ <message>
+ <source>Error while reading: %1</source>
+ <translation>เกิดความผิดพลาดขณะอ่าน: %1</translation>
+ </message>
+ <message>
+ <source>Error during SSL handshake: %1</source>
+ <translation>เกิดความผิดพลาดขณะเชื่อมต่อ SSL: %1</translation>
+ </message>
+ <message>
+ <source>Error creating SSL context (%1)</source>
+ <translation>เกิดความผิดพลาดขณะสร้างบริบท SSL (%1)</translation>
+ </message>
+ <message>
+ <source>Invalid or empty cipher list (%1)</source>
+ <translation>รายการไซเฟอร์ว่างอยู่หรือไม่ถูกต้อง (%1)</translation>
+ </message>
+ <message>
+ <source>Error creating SSL session, %1</source>
+ <translation>เกิดความผิดพลาดขณะสร้างเซสชั่น SSL, %1</translation>
+ </message>
+ <message>
+ <source>Error creating SSL session: %1</source>
+ <translation>เกิดความผิดพลาดขณะสร้างเซสชั่น SSL: %1</translation>
+ </message>
+ <message>
+ <source>Cannot provide a certificate with no key, %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error loading local certificate, %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error loading private key, %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Private key does not certificate public key, %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QTDSDriver</name>
+ <message>
+ <source>Unable to open connection</source>
+ <translation>ไม่สามารถเปิดการเชื่อมต่อได้</translation>
+ </message>
+ <message>
+ <source>Unable to use database</source>
+ <translation>ไม่สามารถใช้ฐานข้อมูลได้</translation>
+ </message>
+</context>
+<context>
+ <name>QTabBar</name>
+ <message>
+ <source>Scroll Left</source>
+ <translation>เลื่อนซ้าย</translation>
+ </message>
+ <message>
+ <source>Scroll Right</source>
+ <translation>เลื่อนขวา</translation>
+ </message>
+</context>
+<context>
+ <name>QTextControl</name>
+ <message>
+ <source>&Undo</source>
+ <translation>เ&ลิกทำ</translation>
+ </message>
+ <message>
+ <source>&Redo</source>
+ <translation>ทำ&ซ้ำ</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>&ตัด</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&คัดลอก</translation>
+ </message>
+ <message>
+ <source>Copy &Link Location</source>
+ <translation>คัดลอก&ที่ตั้งลิงค์</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&วาง</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>ลบ</translation>
+ </message>
+ <message>
+ <source>Select All</source>
+ <translation>เลือกทั้งหมด</translation>
+ </message>
+</context>
+<context>
+ <name>QToolButton</name>
+ <message>
+ <source>Press</source>
+ <translation>กด</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>เปิด</translation>
+ </message>
+</context>
+<context>
+ <name>QUdpSocket</name>
+ <message>
+ <source>This platform does not support IPv6</source>
+ <translation>แพลตฟอร์มนี้ไม่รองรับ IPv6</translation>
+ </message>
+</context>
+<context>
+ <name>QUndoGroup</name>
+ <message>
+ <source>Undo</source>
+ <translation>เลิกทำ</translation>
+ </message>
+ <message>
+ <source>Redo</source>
+ <translation>ทำซ้ำ</translation>
+ </message>
+</context>
+<context>
+ <name>QUndoModel</name>
+ <message>
+ <source><empty></source>
+ <translation><ว่าง></translation>
+ </message>
+</context>
+<context>
+ <name>QUndoStack</name>
+ <message>
+ <source>Undo</source>
+ <translation>เลิกทำ</translation>
+ </message>
+ <message>
+ <source>Redo</source>
+ <translation>ทำซ้ำ</translation>
+ </message>
+</context>
+<context>
+ <name>QUnicodeControlCharacterMenu</name>
+ <message>
+ <source>LRM Left-to-right mark</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>RLM Right-to-left mark</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>ZWJ Zero width joiner</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>ZWNJ Zero width non-joiner</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>ZWSP Zero width space</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>LRE Start of left-to-right embedding</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>RLE Start of right-to-left embedding</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>LRO Start of left-to-right override</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>RLO Start of right-to-left override</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>PDF Pop directional formatting</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Insert Unicode control character</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QWebFrame</name>
+ <message>
+ <source>Request cancelled</source>
+ <translation>คำขอถูกยกเลิก</translation>
+ </message>
+ <message>
+ <source>Request blocked</source>
+ <translation>คำขอถูกบล็อก</translation>
+ </message>
+ <message>
+ <source>Cannot show URL</source>
+ <translation>ไม่สามารถแสดง URL</translation>
+ </message>
+ <message>
+ <source>Frame load interruped by policy change</source>
+ <translation>การโหลดเฟรมถูกขัดจังหวะจากการเปลี่ยนนโยบาย</translation>
+ </message>
+ <message>
+ <source>Cannot show mimetype</source>
+ <translation>ไม่สามารถแสดงชนิดไมม์</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>ไม่มีไฟล์นี้อยู่</translation>
+ </message>
+</context>
+<context>
+ <name>QWebPage</name>
+ <message>
+ <source>Bad HTTP request</source>
+ <translation>คำขอ HTTP ไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Submit</source>
+ <comment>default label for Submit buttons in forms on web pages</comment>
+ <translation>ส่ง</translation>
+ </message>
+ <message>
+ <source>Submit</source>
+ <comment>Submit (input element) alt text for <input> elements with no alt, title, or value</comment>
+ <translation>ส่ง</translation>
+ </message>
+ <message>
+ <source>Reset</source>
+ <comment>default label for Reset buttons in forms on web pages</comment>
+ <translation>รีเซ็ต</translation>
+ </message>
+ <message>
+ <source>This is a searchable index. Enter search keywords: </source>
+ <comment>text that appears at the start of nearly-obsolete web pages in the form of a 'searchable index'</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Choose File</source>
+ <comment>title for file button used in HTML forms</comment>
+ <translation>เลือกไฟล์</translation>
+ </message>
+ <message>
+ <source>No file selected</source>
+ <comment>text to display in file button used in HTML forms when no file is selected</comment>
+ <translation>ไม่มีไฟล์ที่ถูกเลือก</translation>
+ </message>
+ <message>
+ <source>Open in New Window</source>
+ <comment>Open in New Window context menu item</comment>
+ <translation>เปิดในหน้าต่างใหม่</translation>
+ </message>
+ <message>
+ <source>Save Link...</source>
+ <comment>Download Linked File context menu item</comment>
+ <translation>บันทึกลิงค์...</translation>
+ </message>
+ <message>
+ <source>Copy Link</source>
+ <comment>Copy Link context menu item</comment>
+ <translation>คัดลอกลิงค์</translation>
+ </message>
+ <message>
+ <source>Open Image</source>
+ <comment>Open Image in New Window context menu item</comment>
+ <translation>เปิดรูปภาพ</translation>
+ </message>
+ <message>
+ <source>Save Image</source>
+ <comment>Download Image context menu item</comment>
+ <translation>บันทึกรูปภาพ</translation>
+ </message>
+ <message>
+ <source>Copy Image</source>
+ <comment>Copy Link context menu item</comment>
+ <translation>สำเนารูปภาพ</translation>
+ </message>
+ <message>
+ <source>Open Frame</source>
+ <comment>Open Frame in New Window context menu item</comment>
+ <translation>เปิดเฟรม</translation>
+ </message>
+ <message>
+ <source>Copy</source>
+ <comment>Copy context menu item</comment>
+ <translation>คัดลอก</translation>
+ </message>
+ <message>
+ <source>Go Back</source>
+ <comment>Back context menu item</comment>
+ <translation>กลับไป</translation>
+ </message>
+ <message>
+ <source>Go Forward</source>
+ <comment>Forward context menu item</comment>
+ <translation>ถัดไป</translation>
+ </message>
+ <message>
+ <source>Stop</source>
+ <comment>Stop context menu item</comment>
+ <translation>หยุด</translation>
+ </message>
+ <message>
+ <source>Reload</source>
+ <comment>Reload context menu item</comment>
+ <translation>เรียกซ้ำ</translation>
+ </message>
+ <message>
+ <source>Cut</source>
+ <comment>Cut context menu item</comment>
+ <translation>ตัด</translation>
+ </message>
+ <message>
+ <source>Paste</source>
+ <comment>Paste context menu item</comment>
+ <translation>วาง</translation>
+ </message>
+ <message>
+ <source>No Guesses Found</source>
+ <comment>No Guesses Found context menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Ignore</source>
+ <comment>Ignore Spelling context menu item</comment>
+ <translation>ละเว้น</translation>
+ </message>
+ <message>
+ <source>Add To Dictionary</source>
+ <comment>Learn Spelling context menu item</comment>
+ <translation>เพิ่มไปยังพจนานุกรม</translation>
+ </message>
+ <message>
+ <source>Search The Web</source>
+ <comment>Search The Web context menu item</comment>
+ <translation>ค้นหาจากเว็บ</translation>
+ </message>
+ <message>
+ <source>Look Up In Dictionary</source>
+ <comment>Look Up in Dictionary context menu item</comment>
+ <translation>ค้นหาในพจนานุกรม</translation>
+ </message>
+ <message>
+ <source>Open Link</source>
+ <comment>Open Link context menu item</comment>
+ <translation>เปิดลิงค์</translation>
+ </message>
+ <message>
+ <source>Ignore</source>
+ <comment>Ignore Grammar context menu item</comment>
+ <translation>ละเว้น</translation>
+ </message>
+ <message>
+ <source>Spelling</source>
+ <comment>Spelling and Grammar context sub-menu item</comment>
+ <translation>การสะกด</translation>
+ </message>
+ <message>
+ <source>Show Spelling and Grammar</source>
+ <comment>menu item title</comment>
+ <translation>แสดงการสะกดและไวยากรณ์</translation>
+ </message>
+ <message>
+ <source>Hide Spelling and Grammar</source>
+ <comment>menu item title</comment>
+ <translation>ซ่อนการสะกดและไวยากรณ์</translation>
+ </message>
+ <message>
+ <source>Check Spelling</source>
+ <comment>Check spelling context menu item</comment>
+ <translation>ตรวจสอบการสะกด</translation>
+ </message>
+ <message>
+ <source>Check Spelling While Typing</source>
+ <comment>Check spelling while typing context menu item</comment>
+ <translation>ตรวจสอบการสะกดขณะพิมพ์</translation>
+ </message>
+ <message>
+ <source>Check Grammar With Spelling</source>
+ <comment>Check grammar with spelling context menu item</comment>
+ <translation>ตรวจสอบไวยากรณ์พร้อมการสะกด</translation>
+ </message>
+ <message>
+ <source>Fonts</source>
+ <comment>Font context sub-menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Bold</source>
+ <comment>Bold context menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Italic</source>
+ <comment>Italic context menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Underline</source>
+ <comment>Underline context menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Outline</source>
+ <comment>Outline context menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Direction</source>
+ <comment>Writing direction context sub-menu item</comment>
+ <translation>ทิศทาง</translation>
+ </message>
+ <message>
+ <source>Default</source>
+ <comment>Default writing direction context menu item</comment>
+ <translation>ค่าตั้งต้น</translation>
+ </message>
+ <message>
+ <source>LTR</source>
+ <comment>Left to Right context menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>RTL</source>
+ <comment>Right to Left context menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Inspect</source>
+ <comment>Inspect Element context menu item</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No recent searches</source>
+ <comment>Label for only item in menu that appears when clicking on the search field image, when no searches have been performed</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recent searches</source>
+ <comment>label for first item in the menu that appears when clicking on the search field image, used as embedded menu title</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Clear recent searches</source>
+ <comment>menu item in Recent Searches menu that empties menu's contents</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <comment>Unknown filesize FTP directory listing item</comment>
+ <translation>ไม่รู้จัก</translation>
+ </message>
+ <message>
+ <source>%1 (%2x%3 pixels)</source>
+ <comment>Title string for images</comment>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Web Inspector - %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QWhatsThisAction</name>
+ <message>
+ <source>What's This?</source>
+ <translation>นี่คืออะไร?</translation>
+ </message>
+</context>
+<context>
+ <name>QWidget</name>
+ <message>
+ <source>*</source>
+ <translation>*</translation>
+ </message>
+</context>
+<context>
+ <name>QWizard</name>
+ <message>
+ <source>Go Back</source>
+ <translation>กลับไป</translation>
+ </message>
+ <message>
+ <source>Continue</source>
+ <translation>ทำต่อ</translation>
+ </message>
+ <message>
+ <source>Commit</source>
+ <translation>คอมมิท</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>เสร็จ</translation>
+ </message>
+ <message>
+ <source>Quit</source>
+ <translation>ออก</translation>
+ </message>
+ <message>
+ <source>Help</source>
+ <translation>ช่วยเหลือ</translation>
+ </message>
+ <message>
+ <source>< &Back</source>
+ <translation>< &ย้อนกลับ</translation>
+ </message>
+ <message>
+ <source>&Finish</source>
+ <translation>เ&สร็จสิ้น</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ยกเลิก</translation>
+ </message>
+ <message>
+ <source>&Help</source>
+ <translation>&ช่วยเหลือ</translation>
+ </message>
+ <message>
+ <source>&Next</source>
+ <translation>&ถัดไป</translation>
+ </message>
+ <message>
+ <source>&Next ></source>
+ <translation>&ถัดไป ></translation>
+ </message>
+</context>
+<context>
+ <name>QWorkspace</name>
+ <message>
+ <source>&Restore</source>
+ <translation>&คืนค่า</translation>
+ </message>
+ <message>
+ <source>&Move</source>
+ <translation>&ย้าย</translation>
+ </message>
+ <message>
+ <source>&Size</source>
+ <translation>&ขนาด</translation>
+ </message>
+ <message>
+ <source>Mi&nimize</source>
+ <translation>ย่อให้เ&ล็กสุด</translation>
+ </message>
+ <message>
+ <source>Ma&ximize</source>
+ <translation>ขยายให้ให&ญ่สุด</translation>
+ </message>
+ <message>
+ <source>&Close</source>
+ <translation>&ปิด</translation>
+ </message>
+ <message>
+ <source>Stay on &Top</source>
+ <translation>แสดงไว้&บนสุด</translation>
+ </message>
+ <message>
+ <source>Sh&ade</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 - [%2]</source>
+ <translation>%1 - [%2]</translation>
+ </message>
+ <message>
+ <source>Minimize</source>
+ <translation>ย่อให้เล็กสุด</translation>
+ </message>
+ <message>
+ <source>Restore Down</source>
+ <translation>คืนขนาดลง</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>ปิด</translation>
+ </message>
+ <message>
+ <source>&Unshade</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QXml</name>
+ <message>
+ <source>no error occurred</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>error triggered by consumer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>unexpected end of file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>more than one document type definition</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>error occurred while parsing element</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>tag mismatch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>error occurred while parsing content</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>unexpected character</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>invalid name for processing instruction</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>version expected while reading the XML declaration</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>wrong value for standalone declaration</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>encoding declaration or standalone declaration expected while reading the XML declaration</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>standalone declaration expected while reading the XML declaration</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>error occurred while parsing document type definition</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>letter is expected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>error occurred while parsing comment</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>error occurred while parsing reference</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>internal general entity reference not allowed in DTD</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>external parsed general entity reference not allowed in attribute value</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>external parsed general entity reference not allowed in DTD</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>unparsed entity reference in wrong context</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>recursive entities</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>error in the text declaration of an external entity</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QXmlStream</name>
+ <message>
+ <source>Extra content at end of document.</source>
+ <translation>มีเนื้อหาเพิ่มเติมที่ส่วนท้ายเอกสาร</translation>
+ </message>
+ <message>
+ <source>Invalid entity value.</source>
+ <translation>ค่าเอนทิตีไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Invalid XML character.</source>
+ <translation>อักขระ XML ไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Sequence ']]>' not allowed in content.</source>
+ <translation>ไม่อนุญาตให้ใช้ลำดับ ']]>' ในเนื้อหา</translation>
+ </message>
+ <message>
+ <source>Namespace prefix '%1' not declared</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Attribute redefined.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unexpected character '%1' in public id literal.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Invalid XML version string.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unsupported XML version.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an invalid encoding name.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Encoding %1 is unsupported</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Standalone accepts only yes or no.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Invalid attribute in XML declaration.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Premature end of document.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Invalid document.</source>
+ <translation>เอกสารไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Expected </source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>, but got '</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unexpected '</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Expected character data.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recursive entity detected.</source>
+ <translation>ตรวจพบเอนทิตีเรียกซ้ำ</translation>
+ </message>
+ <message>
+ <source>Start tag expected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>XML declaration not at start of document.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>NDATA in parameter entity declaration.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an invalid processing instruction name.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Invalid processing instruction name.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Illegal namespace declaration.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Invalid XML name.</source>
+ <translation>ชื่อ XML ไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Opening and ending tag mismatch.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Reference to unparsed entity '%1'.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Entity '%1' not declared.</source>
+ <translation>ไม่ได้ประกาศเอนทิตี '%1' ไว้</translation>
+ </message>
+ <message>
+ <source>Reference to external entity '%1' in attribute value.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Invalid character reference.</source>
+ <translation>อ้างอิงอักขระที่ไม่ถูกต้อง</translation>
+ </message>
+ <message>
+ <source>Encountered incorrectly encoded content.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The standalone pseudo attribute must appear after the encoding.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an invalid PUBLIC identifier.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QtXmlPatterns</name>
+ <message>
+ <source>An %1-attribute with value %2 has already been declared.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>An %1-attribute must have a valid %2 as value, which %3 isn't.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Network timeout.</source>
+ <translation>หมดเวลาเครือข่าย</translation>
+ </message>
+ <message>
+ <source>Element %1 can't be serialized because it appears outside the document element.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Year %1 is invalid because it begins with %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Day %1 is outside the range %2..%3.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Month %1 is outside the range %2..%3.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Overflow: Can't represent date %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Day %1 is invalid for month %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Time 24:%1:%2.%3 is invalid. Hour is 24, but minutes, seconds, and milliseconds are not all 0; </source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Time %1:%2:%3.%4 is invalid.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Overflow: Date can't be represented.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>At least one component must be present.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>At least one time component must appear after the %1-delimiter.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No operand in an integer division, %1, can be %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The first operand in an integer division, %1, cannot be infinity (%2).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The second operand in a division, %1, cannot be zero (%2).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a valid value of type %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>When casting to %1 from %2, the source value cannot be %3.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Integer division (%1) by zero (%2) is undefined.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Division (%1) by zero (%2) is undefined.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Modulus division (%1) by zero (%2) is undefined.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dividing a value of type %1 by %2 (not-a-number) is not allowed.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dividing a value of type %1 by %2 or %3 (plus or minus zero) is not allowed.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Multiplication of a value of type %1 by %2 or %3 (plus or minus infinity) is not allowed.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A value of type %1 cannot have an Effective Boolean Value.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Effective Boolean Value cannot be calculated for a sequence containing two or more atomic values.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Value %1 of type %2 exceeds maximum (%3).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Value %1 of type %2 is below minimum (%3).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A value of type %1 must contain an even number of digits. The value %2 does not.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not valid as a value of type %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Operator %1 cannot be used on type %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Operator %1 cannot be used on atomic values of type %2 and %3.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The namespace URI in the name for a computed attribute cannot be %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The name for a computed attribute cannot have the namespace URI %1 with the local name %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Type error in cast, expected %1, received %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>When casting to %1 or types derived from it, the source value must be of the same type, or it must be a string literal. Type %2 is not allowed.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No casting is possible with %1 as the target type.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>It is not possible to cast from %1 to %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Casting to %1 is not possible because it is an abstract type, and can therefore never be instantiated.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>It's not possible to cast the value %1 of type %2 to %3</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failure when casting from %1 to %2: %3</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A comment cannot contain %1</source>
+ <translation>คอมเมนต์ไม่สามารถมี %1 ได้</translation>
+ </message>
+ <message>
+ <source>A comment cannot end with a %1.</source>
+ <translation>คอมเมนต์ไม่สามารถจบด้วย %1 ได้</translation>
+ </message>
+ <message>
+ <source>No comparisons can be done involving the type %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Operator %1 is not available between atomic values of type %2 and %3.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>An attribute node cannot be a child of a document node. Therefore, the attribute %1 is out of place.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A library module cannot be evaluated directly. It must be imported from a main module.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A value of type %1 cannot be a predicate. A predicate must have either a numeric type or an Effective Boolean Value type.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A positional predicate must evaluate to a single numeric value.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The target name in a processing instruction cannot be %1 in any combination of upper and lower case. Therefore, is %2 invalid.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a valid target name in a processing instruction. It must be a %2 value, e.g. %3.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The last step in a path must contain either nodes or atomic values. It cannot be a mixture between the two.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The data of a processing instruction cannot contain the string %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No namespace binding exists for the prefix %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No namespace binding exists for the prefix %1 in %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an invalid %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message numerus="yes">
+ <source>%1 takes at most %n argument(s). %2 is therefore invalid.</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ </translation>
+ </message>
+ <message numerus="yes">
+ <source>%1 requires at least %n argument(s). %2 is therefore invalid.</source>
+ <translation type="unfinished">
+ <numerusform></numerusform>
+ </translation>
+ </message>
+ <message>
+ <source>The first argument to %1 cannot be of type %2. It must be a numeric type, xs:yearMonthDuration or xs:dayTimeDuration.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The first argument to %1 cannot be of type %2. It must be of type %3, %4, or %5.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The second argument to %1 cannot be of type %2. It must be of type %3, %4, or %5.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a valid XML 1.0 character.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The first argument to %1 cannot be of type %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>If both values have zone offsets, they must have the same zone offset. %1 and %2 are not the same.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 was called.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 must be followed by %2 or %3, not at the end of the replacement string.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>In the replacement string, %1 must be followed by at least one digit when not escaped.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>In the replacement string, %1 can only be used to escape itself or %2, not %3</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 matches newline characters</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 and %2 match the start and end of a line.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Matches are case insensitive</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Whitespace characters are removed, except when they appear in character classes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an invalid regular expression pattern: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an invalid flag for regular expressions. Valid flags are:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>If the first argument is the empty sequence or a zero-length string (no namespace), a prefix cannot be specified. Prefix %1 was specified.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>It will not be possible to retrieve %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The root node of the second argument to function %1 must be a document node. %2 is not a document node.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The default collection is undefined</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 cannot be retrieved</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The normalization form %1 is unsupported. The supported forms are %2, %3, %4, and %5, and none, i.e. the empty string (no normalization).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A zone offset must be in the range %1..%2 inclusive. %3 is out of range.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a whole number of minutes.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Required cardinality is %1; got cardinality %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The item %1 did not match the required type %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an unknown schema type.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Only one %1 declaration can occur in the query prolog.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The initialization of variable %1 depends on itself</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No variable by name %1 exists</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The variable %1 is unused</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Version %1 is not supported. The supported XQuery version is 1.0.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The encoding %1 is invalid. It must contain Latin characters only, must not contain whitespace, and must match the regular expression %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No function with signature %1 is available</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A default namespace declaration must occur before function, variable, and option declarations.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Namespace declarations must occur before function, variable, and option declarations.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Module imports must occur before function, variable, and option declarations.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>It is not possible to redeclare prefix %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Only the prefix %1 can be declared to bind the namespace %2. By default, it is already bound to the prefix %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Prefix %1 is already declared in the prolog.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The name of an option must have a prefix. There is no default namespace for options.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The Schema Import feature is not supported, and therefore %1 declarations cannot occur.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The target namespace of a %1 cannot be empty.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The module import feature is not supported</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A variable by name %1 has already been declared in the prolog.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No value is available for the external variable by name %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The namespace %1 is reserved; therefore user defined functions may not use it. Try the predefined prefix %2, which exists for these cases.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The namespace of a user defined function in a library module must be equivalent to the module namespace. In other words, it should be %1 instead of %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A function already exists with the signature %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No external functions are supported. All supported functions can be used directly, without first declaring them as external</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>An argument by name %1 has already been declared. Every argument name must be unique.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The name of a variable bound in a for-expression must be different from the positional variable. Hence, the two variables named %1 collide.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The Schema Validation Feature is not supported. Hence, %1-expressions may not be used.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>None of the pragma expressions are supported. Therefore, a fallback expression must be present</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The %1-axis is unsupported in XQuery</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a valid numeric literal.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No function by name %1 is available.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The namespace URI cannot be the empty string when binding to a prefix, %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an invalid namespace URI.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>It is not possible to bind to the prefix %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Namespace %1 can only be bound to %2 (and it is, in either case, pre-declared).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Prefix %1 can only be bound to %2 (and it is, in either case, pre-declared).</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Two namespace declaration attributes have the same name: %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The namespace URI must be a constant and cannot use enclosed expressions.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>An attribute by name %1 has already appeared on this element.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A direct element constructor is not well-formed. %1 is ended with %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The name %1 does not refer to any schema type.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is an complex type. Casting to complex types is not possible. However, casting to atomic types such as %2 works.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not an atomic type. Casting is only possible to atomic types.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a valid name for a processing-instruction. Therefore this name test will never match.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not in the in-scope attribute declarations. Note that the schema import feature is not supported.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The name of an extension expression must be in a namespace.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>empty</source>
+ <translation>ว่าง</translation>
+ </message>
+ <message>
+ <source>zero or one</source>
+ <translation>ศูนย์หรือหนึ่ง</translation>
+ </message>
+ <message>
+ <source>exactly one</source>
+ <translation>หนึ่งเท่านั้น</translation>
+ </message>
+ <message>
+ <source>one or more</source>
+ <translation>หนึ่งหรือมากกว่า</translation>
+ </message>
+ <message>
+ <source>zero or more</source>
+ <translation>ศูนย์หรือมากกว่า</translation>
+ </message>
+ <message>
+ <source>Required type is %1, but %2 was found.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Promoting %1 to %2 may cause loss of precision.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The focus is undefined.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>It's not possible to add attributes after any other kind of node.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>An attribute by name %1 has already been created.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Only the Unicode Codepoint Collation is supported(%1). %2 is unsupported.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Attribute %1 can't be serialized because it appears at the top level.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The namespace for a user defined function cannot be empty (try the predefined prefix %1 which exists for cases like this)</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>VolumeSlider</name>
+ <message>
+ <source>Muted</source>
+ <translation>ปิดเสียง</translation>
+ </message>
+ <message>
+ <source>Volume: %1%</source>
+ <translation>ระดับเสียง: %1%</translation>
+ </message>
+</context>
+<context>
+ <name>WebCore::PlatformScrollbar</name>
+ <message>
+ <source>Scroll here</source>
+ <translation>เลื่อนมาที่นี่</translation>
+ </message>
+ <message>
+ <source>Left edge</source>
+ <translation>ขอบซ้าย</translation>
+ </message>
+ <message>
+ <source>Top</source>
+ <translation>ด้านบน</translation>
+ </message>
+ <message>
+ <source>Right edge</source>
+ <translation>ขอบขวา</translation>
+ </message>
+ <message>
+ <source>Bottom</source>
+ <translation>ด้านล่าง</translation>
+ </message>
+ <message>
+ <source>Page left</source>
+ <translation>เลื่อนหน้าซ้าย</translation>
+ </message>
+ <message>
+ <source>Page up</source>
+ <translation>เลื่อนหน้าขึ้น</translation>
+ </message>
+ <message>
+ <source>Page right</source>
+ <translation>เลื่อนหน้าขวา</translation>
+ </message>
+ <message>
+ <source>Page down</source>
+ <translation>เลื่อนหน้าลง</translation>
+ </message>
+ <message>
+ <source>Scroll left</source>
+ <translation>เลื่อนซ้าย</translation>
+ </message>
+ <message>
+ <source>Scroll up</source>
+ <translation>เลื่อนขึ้น</translation>
+ </message>
+ <message>
+ <source>Scroll right</source>
+ <translation>เลื่อนขวา</translation>
+ </message>
+ <message>
+ <source>Scroll down</source>
+ <translation>เลื่อนลง</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/VBox/Frontends/VirtualBox/src/UIVMInfoDialog.cpp b/src/VBox/Frontends/VirtualBox/src/UIVMInfoDialog.cpp
index a41b631..e7be383 100644
--- a/src/VBox/Frontends/VirtualBox/src/UIVMInfoDialog.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/UIVMInfoDialog.cpp
@@ -283,7 +283,7 @@ void UIVMInfoDialog::retranslateUi()
}
/* Network statistics: */
- ulong count = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
+ ulong count = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine.GetChipsetType());
for (ulong i = 0; i < count; ++i)
{
CNetworkAdapter na = machine.GetNetworkAdapter(i);
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
index 3e4517c..0c60594 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.cpp
@@ -1254,7 +1254,7 @@ QString VBoxGlobal::detailsReport (const CMachine &aMachine, bool aWithLinks)
{
QString item;
- ulong count = m_vbox.GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
+ ulong count = m_vbox.GetSystemProperties().GetMaxNetworkAdapters(aMachine.GetChipsetType());
int rows = 2; /* including section header and footer */
for (ulong slot = 0; slot < count; slot ++)
{
@@ -3382,7 +3382,7 @@ void VBoxGlobal::setFullScreenFlag(QWidget *pWidget)
Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
Atom net_wm_state_fullscreen = XInternAtom(pDisplay, "_NET_WM_STATE_FULLSCREEN", True /* only if exists */);
- /* Append resultNetWmState with full-screen flag if necessary: */
+ /* Append resultNetWmState with fullscreen flag if necessary: */
if (!resultNetWmState.contains(net_wm_state_fullscreen))
{
resultNetWmState.append(net_wm_state_fullscreen);
@@ -3392,6 +3392,50 @@ void VBoxGlobal::setFullScreenFlag(QWidget *pWidget)
(unsigned char*)resultNetWmState.data(), resultNetWmState.size());
}
}
+
+/* static */
+void VBoxGlobal::setSkipTaskBarFlag(QWidget *pWidget)
+{
+ /* Get display: */
+ Display *pDisplay = QX11Info::display();
+
+ /* Prepare atoms: */
+ QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
+ Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
+ Atom net_wm_state_skip_taskbar = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_TASKBAR", True /* only if exists */);
+
+ /* Append resultNetWmState with skip-taskbar flag if necessary: */
+ if (!resultNetWmState.contains(net_wm_state_skip_taskbar))
+ {
+ resultNetWmState.append(net_wm_state_skip_taskbar);
+ /* Apply property to widget again: */
+ XChangeProperty(pDisplay, pWidget->window()->winId(),
+ net_wm_state, XA_ATOM, 32, PropModeReplace,
+ (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
+ }
+}
+
+/* static */
+void VBoxGlobal::setSkipPagerFlag(QWidget *pWidget)
+{
+ /* Get display: */
+ Display *pDisplay = QX11Info::display();
+
+ /* Prepare atoms: */
+ QVector<Atom> resultNetWmState = flagsNetWmState(pWidget);
+ Atom net_wm_state = XInternAtom(pDisplay, "_NET_WM_STATE", True /* only if exists */);
+ Atom net_wm_state_skip_pager = XInternAtom(pDisplay, "_NET_WM_STATE_SKIP_PAGER", True /* only if exists */);
+
+ /* Append resultNetWmState with skip-pager flag if necessary: */
+ if (!resultNetWmState.contains(net_wm_state_skip_pager))
+ {
+ resultNetWmState.append(net_wm_state_skip_pager);
+ /* Apply property to widget again: */
+ XChangeProperty(pDisplay, pWidget->window()->winId(),
+ net_wm_state, XA_ATOM, 32, PropModeReplace,
+ (unsigned char*)resultNetWmState.data(), resultNetWmState.size());
+ }
+}
#endif /* VBOX_WS_X11 */
/**
diff --git a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
index 5deb432..8f2a408 100644
--- a/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
+++ b/src/VBox/Frontends/VirtualBox/src/globals/VBoxGlobal.h
@@ -397,6 +397,10 @@ public:
static bool isFullScreenFlagSet(QWidget *pWidget);
/** X11: Sets _NET_WM_STATE_FULLSCREEN flag for passed @a pWidget. */
static void setFullScreenFlag(QWidget *pWidget);
+ /** X11: Sets _NET_WM_STATE_SKIP_TASKBAR flag for passed @a pWidget. */
+ static void setSkipTaskBarFlag(QWidget *pWidget);
+ /** X11: Sets _NET_WM_STATE_SKIP_PAGER flag for passed @a pWidget. */
+ static void setSkipPagerFlag(QWidget *pWidget);
#endif /* VBOX_WS_X11 */
static QString removeAccelMark (const QString &aText);
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
index c01e421..f1308f2 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
@@ -1148,8 +1148,12 @@ void UIFrameBufferPrivate::handlePaintEvent(QPaintEvent *pEvent)
void UIFrameBufferPrivate::handleSetVisibleRegion(const QRegion ®ion)
{
- /* Make sure async visible-region has changed: */
- if (m_asyncVisibleRegion == region)
+ /* Make sure async visible-region has changed or wasn't yet applied: */
+ if ( m_asyncVisibleRegion == region
+#ifdef VBOX_WITH_MASKED_SEAMLESS
+ && m_asyncVisibleRegion == m_pMachineView->machineWindow()->mask()
+#endif /* VBOX_WITH_MASKED_SEAMLESS */
+ )
return;
/* We are accounting async visible-regions one-by-one
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
index ee756b2..f55b5b3 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/fullscreen/UIMachineViewFullscreen.cpp
@@ -83,9 +83,7 @@ bool UIMachineViewFullscreen::eventFilter(QObject *pWatched, QEvent *pEvent)
/* Recalculate max guest size: */
setMaxGuestSize();
- /* And resize guest to that size: */
- if (m_bIsGuestAutoresizeEnabled && uisession()->isGuestSupportsGraphics())
- QTimer::singleShot(0, this, SLOT(sltPerformGuestResize()));
+
break;
}
default:
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/information/UIInformationDataItem.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/information/UIInformationDataItem.cpp
index 7783c8a..140d3b4 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/information/UIInformationDataItem.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/information/UIInformationDataItem.cpp
@@ -397,7 +397,7 @@ QVariant UIInformationDataNetwork::data(const QModelIndex &index, int role) cons
{
UITextTable p_text;
- ulong count = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
+ ulong count = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(m_machine.GetChipsetType());
for (ulong slot = 0; slot < count; slot++)
{
CNetworkAdapter adapter = m_machine.GetNetworkAdapter(slot);
@@ -774,7 +774,7 @@ UIInformationDataNetworkStatistics::UIInformationDataNetworkStatistics(const CMa
: UIInformationDataItem(InformationElementType_NetworkStatistics, machine, console, pModel)
{
/* Network statistics: */
- ulong count = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
+ ulong count = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(m_machine.GetChipsetType());
for (ulong i = 0; i < count; ++i)
{
CNetworkAdapter na = machine.GetNetworkAdapter(i);
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
index 5f5a15a..fcbd3e6 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/normal/UIMachineViewNormal.cpp
@@ -153,6 +153,10 @@ void UIMachineViewNormal::setGuestAutoresizeEnabled(bool fEnabled)
void UIMachineViewNormal::resendSizeHint()
{
+ /* Skip if another visual representation mode requested: */
+ if (uisession()->requestedVisualState() == UIVisualStateType_Seamless) // Seamless only for now.
+ return;
+
/* Get the last guest-screen size-hint, taking the scale factor into account. */
const QSize sizeHint = scaledBackward(guestScreenSizeHint());
LogRel(("GUI: UIMachineViewNormal::resendSizeHint: Restoring guest size-hint for screen %d to %dx%d\n",
@@ -227,6 +231,15 @@ void UIMachineViewNormal::adjustGuestScreenSize()
fAdjust = false;
}
}
+ /* Step 5: Is another visual representation mode requested? */
+ if (fAdjust)
+ {
+ if (uisession()->requestedVisualState() == UIVisualStateType_Seamless) // Seamless only for now.
+ {
+ LogRel2(("GUI: UIMachineViewNormal::adjustGuestScreenSize: Seamless mode is requested, adjustment is omitted.\n"));
+ fAdjust = false;
+ }
+ }
/* Final step: Adjust if requested/allowed. */
if (fAdjust)
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
index b71cbe0..6805075 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineViewSeamless.cpp
@@ -95,9 +95,7 @@ bool UIMachineViewSeamless::eventFilter(QObject *pWatched, QEvent *pEvent)
/* Recalculate max guest size: */
setMaxGuestSize();
- /* And resize guest to that size: */
- if (uisession()->isGuestSupportsGraphics())
- QTimer::singleShot(0, this, SLOT(sltPerformGuestResize()));
+
break;
}
default:
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
index 2cf80bb..a2cb357 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.cpp
@@ -51,6 +51,9 @@ UIMachineWindowSeamless::UIMachineWindowSeamless(UIMachineLogic *pMachineLogic,
, m_pMiniToolBar(0)
#endif /* VBOX_WS_WIN || VBOX_WS_X11 */
, m_fWasMinimized(false)
+#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
+ , m_fIsMinimized(false)
+#endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */
{
}
@@ -171,14 +174,50 @@ void UIMachineWindowSeamless::cleanupVisualState()
void UIMachineWindowSeamless::placeOnScreen()
{
+ /* Make sure this window has seamless logic: */
+ UIMachineLogicSeamless *pSeamlessLogic = qobject_cast<UIMachineLogicSeamless*>(machineLogic());
+ AssertPtrReturnVoid(pSeamlessLogic);
+
/* Get corresponding host-screen: */
- const int iHostScreen = qobject_cast<UIMachineLogicSeamless*>(machineLogic())->hostScreenForGuestScreen(m_uScreenId);
+ const int iHostScreen = pSeamlessLogic->hostScreenForGuestScreen(m_uScreenId);
/* And corresponding working area: */
const QRect workingArea = gpDesktop->availableGeometry(iHostScreen);
+ Q_UNUSED(workingArea);
- /* Set appropriate geometry for window: */
- resize(workingArea.size());
- move(workingArea.topLeft());
+#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
+
+ /* Make sure we are located on corresponding host-screen: */
+ if ( gpDesktop->screenCount() > 1
+ && (x() != workingArea.x() || y() != workingArea.y()))
+ {
+ // WORKAROUND:
+ // With Qt5 on X11 we can't just move the window onto desired host-screen if
+ // window size is more than the available geometry (working area) of that
+ // host-screen. So we are resizing it to a smaller size first of all:
+ const QSize newSize = workingArea.size() * .9;
+ LogRel(("GUI: UIMachineWindowSeamless::placeOnScreen: Resize window: %d to smaller size: %dx%d\n",
+ m_uScreenId, newSize.width(), newSize.height()));
+ resize(newSize);
+ /* Move window onto required screen: */
+ const QPoint newPosition = workingArea.topLeft();
+ LogRel(("GUI: UIMachineWindowSeamless::placeOnScreen: Move window: %d to: %dx%d\n",
+ m_uScreenId, newPosition.x(), newPosition.y()));
+ move(newPosition);
+ }
+
+#else
+
+ /* Set appropriate window geometry: */
+ const QSize newSize = workingArea.size();
+ LogRel(("GUI: UIMachineWindowSeamless::placeOnScreen: Resize window: %d to: %dx%d\n",
+ m_uScreenId, newSize.width(), newSize.height()));
+ resize(newSize);
+ const QPoint newPosition = workingArea.topLeft();
+ LogRel(("GUI: UIMachineWindowSeamless::placeOnScreen: Move window: %d to: %dx%d\n",
+ m_uScreenId, newPosition.x(), newPosition.y()));
+ move(newPosition);
+
+#endif
}
void UIMachineWindowSeamless::showInNecessaryMode()
@@ -211,8 +250,14 @@ void UIMachineWindowSeamless::showInNecessaryMode()
/* Make sure window have appropriate geometry: */
placeOnScreen();
- /* Show window in normal mode: */
+#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
+ /* Show window: */
+ if (!isMaximized())
+ showMaximized();
+#else
+ /* Show window: */
show();
+#endif
/* Restore minimized state if necessary: */
if (m_fWasMinimized || fWasMinimized)
@@ -255,6 +300,46 @@ void UIMachineWindowSeamless::updateAppearanceOf(int iElement)
}
#endif /* VBOX_WS_WIN || VBOX_WS_X11 */
+#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
+void UIMachineWindowSeamless::changeEvent(QEvent *pEvent)
+{
+ switch (pEvent->type())
+ {
+ case QEvent::WindowStateChange:
+ {
+ /* Watch for window state changes: */
+ QWindowStateChangeEvent *pChangeEvent = static_cast<QWindowStateChangeEvent*>(pEvent);
+ LogRel2(("GUI: UIMachineWindowSeamless::changeEvent: Window state changed from %d to %d\n",
+ (int)pChangeEvent->oldState(), (int)windowState()));
+ if ( windowState() == Qt::WindowMinimized
+ && pChangeEvent->oldState() == Qt::WindowNoState
+ && !m_fIsMinimized)
+ {
+ /* Mark window minimized, isMinimized() is not enough due to Qt5vsX11 fight: */
+ LogRel2(("GUI: UIMachineWindowSeamless::changeEvent: Window minimized\n"));
+ m_fIsMinimized = true;
+ }
+ else
+ if ( windowState() == Qt::WindowNoState
+ && pChangeEvent->oldState() == Qt::WindowMinimized
+ && m_fIsMinimized)
+ {
+ /* Mark window restored, and do manual restoring with showInNecessaryMode(): */
+ LogRel2(("GUI: UIMachineWindowSeamless::changeEvent: Window restored\n"));
+ m_fIsMinimized = false;
+ showInNecessaryMode();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* Call to base-class: */
+ UIMachineWindow::changeEvent(pEvent);
+}
+#endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */
+
#ifdef VBOX_WS_WIN
# if QT_VERSION >= 0x050000
void UIMachineWindowSeamless::showEvent(QShowEvent *pEvent)
diff --git a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
index 0f89942..10724c8 100644
--- a/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
+++ b/src/VBox/Frontends/VirtualBox/src/runtime/seamless/UIMachineWindowSeamless.h
@@ -73,6 +73,11 @@ private:
void updateAppearanceOf(int iElement);
#endif /* VBOX_WS_WIN || VBOX_WS_X11 */
+#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
+ /** Handles @a pEvent about state change. */
+ void changeEvent(QEvent *pEvent);
+#endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */
+
#ifdef VBOX_WS_WIN
# if QT_VERSION >= 0x050000
/** Win: Handles show @a pEvent. */
@@ -100,6 +105,11 @@ private:
/** Holds whether the window was minimized before became hidden.
* Used to restore minimized state when the window shown again. */
bool m_fWasMinimized;
+#if defined(VBOX_WS_X11) && QT_VERSION >= 0x050000
+ /** Holds whether the window is currently minimized.
+ * Used to restore maximized state when the window restored again. */
+ bool m_fIsMinimized;
+#endif /* VBOX_WS_X11 && QT_VERSION >= 0x050000 */
/** Factory support. */
friend class UIMachineWindow;
diff --git a/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.cpp b/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.cpp
index 624a711..9b120b8 100644
--- a/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGDetailsElements.cpp
@@ -591,8 +591,8 @@ void UIGDetailsUpdateTaskNetwork::run()
{
/* Iterate over all the adapters: */
bool fSomeInfo = false;
- ulong uSount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3);
- for (ulong uSlot = 0; uSlot < uSount; ++uSlot)
+ ulong uCount = vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(machine.GetChipsetType());
+ for (ulong uSlot = 0; uSlot < uCount; ++uSlot)
{
const CNetworkAdapter &adapter = machine.GetNetworkAdapter(uSlot);
if (adapter.GetEnabled())
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.cpp b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.cpp
index 2bed6c5..cd85b08 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.cpp
@@ -63,6 +63,7 @@ UISettingsDialog::UISettingsDialog(QWidget *pParent)
/* Serialization stuff: */
, m_pSerializeProcess(0)
, m_fSerializationIsInProgress(false)
+ , m_fSerializationClean(true)
/* Status-bar stuff: */
, m_pStatusBar(0)
/* Process-bar stuff: */
@@ -176,8 +177,12 @@ void UISettingsDialog::accept()
/* Save data: */
saveOwnData();
- /* Call to base-class: */
- QIWithRetranslateUI<QIMainDialog>::accept();
+ /* If serialization was clean: */
+ if (m_fSerializationClean)
+ {
+ /* Call to base-class: */
+ QIWithRetranslateUI<QIMainDialog>::accept();
+ }
}
void UISettingsDialog::sltCategoryChanged(int cId)
@@ -330,6 +335,9 @@ void UISettingsDialog::saveData(QVariant &data)
* We have to check if the dialog still valid. */
if (pDlgSerializeProgress)
{
+ /* Remember whether the serialization was clean: */
+ m_fSerializationClean = pDlgSerializeProgress->isClean();
+
/* Upload 'settings saver' data: */
data = pDlgSerializeProgress->data();
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.h b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.h
index 92090df..5d7dab9 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsDialog.h
@@ -146,6 +146,8 @@ private:
UISettingsSerializer *m_pSerializeProcess;
/** Holds whether the serialization is in progress. */
bool m_fSerializationIsInProgress;
+ /** Holds whether there were no serialization errors. */
+ bool m_fSerializationClean;
/* Status bar widget: */
QStackedWidget *m_pStatusBar;
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.cpp b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.cpp
index cdbc4d8..34a8ddb 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.cpp
@@ -203,6 +203,7 @@ UISettingsSerializerProgress::UISettingsSerializerProgress(QWidget *pParent, UIS
, m_pBarOperationProgress(0)
, m_pLabelSubOperationProgress(0)
, m_pBarSubOperationProgress(0)
+ , m_fClean(true)
{
/* Prepare: */
prepare();
@@ -382,6 +383,9 @@ void UISettingsSerializerProgress::sltHandleOperationProgressChange(ulong iOpera
void UISettingsSerializerProgress::sltHandleOperationProgressError(QString strErrorInfo)
{
+ /* Mark the serialization process dirty: */
+ m_fClean = false;
+
/* Show the error message: */
msgCenter().cannotSaveSettings(strErrorInfo, this);
}
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.h b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.h
index 2877d2d..f0ad0c3 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/UISettingsSerializer.h
@@ -165,6 +165,9 @@ public:
/** Returns the instance of wrapper(s) to load/save the data from/to. */
QVariant& data();
+ /** Returns whether there were no errors. */
+ bool isClean() const { return m_fClean; }
+
protected:
/** Prepare routine. */
@@ -222,6 +225,9 @@ private:
/** Holds the sub-operation progress bar. */
QProgressBar *m_pBarSubOperationProgress;
+ /** Holds whether there were no errors. */
+ bool m_fClean;
+
/** Holds the template for the sub-operation progress label. */
static QString m_strProgressDescriptionTemplate;
};
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetwork.cpp b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetwork.cpp
index 2183816..233454b 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetwork.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetwork.cpp
@@ -53,8 +53,8 @@ public:
UIItemNetworkNAT();
/* API: Get/return data to/form items: */
- void fetchNetworkData(const UIDataNetworkNAT &data);
- void uploadNetworkData(UIDataNetworkNAT &data);
+ void fetchNetworkData(const UIDataSettingsGlobalNetworkNAT &data);
+ void uploadNetworkData(UIDataSettingsGlobalNetworkNAT &data);
/* API: Validation stuff: */
bool validate(UIValidationMessage &message);
@@ -70,7 +70,7 @@ public:
private:
/* Variable: Network data: */
- UIDataNetworkNAT m_data;
+ UIDataSettingsGlobalNetworkNAT m_data;
};
@@ -83,8 +83,8 @@ public:
UIItemNetworkHost();
/* API: Get/return data to/form items: */
- void fetchNetworkData(const UIDataNetworkHost &data);
- void uploadNetworkData(UIDataNetworkHost &data);
+ void fetchNetworkData(const UIDataSettingsGlobalNetworkHost &data);
+ void uploadNetworkData(UIDataSettingsGlobalNetworkHost &data);
/* API: Validation stuff: */
bool validate(UIValidationMessage &message);
@@ -98,7 +98,7 @@ public:
private:
/* Variable: Network data: */
- UIDataNetworkHost m_data;
+ UIDataSettingsGlobalNetworkHost m_data;
};
@@ -107,7 +107,7 @@ UIItemNetworkNAT::UIItemNetworkNAT()
{
}
-void UIItemNetworkNAT::fetchNetworkData(const UIDataNetworkNAT &data)
+void UIItemNetworkNAT::fetchNetworkData(const UIDataSettingsGlobalNetworkNAT &data)
{
/* Get from cache: */
m_data = data;
@@ -116,7 +116,7 @@ void UIItemNetworkNAT::fetchNetworkData(const UIDataNetworkNAT &data)
updateInfo();
}
-void UIItemNetworkNAT::uploadNetworkData(UIDataNetworkNAT &data)
+void UIItemNetworkNAT::uploadNetworkData(UIDataSettingsGlobalNetworkNAT &data)
{
/* Put to cache: */
data = m_data;
@@ -219,7 +219,7 @@ UIItemNetworkHost::UIItemNetworkHost()
{
}
-void UIItemNetworkHost::fetchNetworkData(const UIDataNetworkHost &data)
+void UIItemNetworkHost::fetchNetworkData(const UIDataSettingsGlobalNetworkHost &data)
{
/* Get from cache: */
m_data = data;
@@ -228,7 +228,7 @@ void UIItemNetworkHost::fetchNetworkData(const UIDataNetworkHost &data)
updateInfo();
}
-void UIItemNetworkHost::uploadNetworkData(UIDataNetworkHost &data)
+void UIItemNetworkHost::uploadNetworkData(UIDataSettingsGlobalNetworkHost &data)
{
/* Put to cache: */
data = m_data;
@@ -488,12 +488,11 @@ UIGlobalSettingsNetwork::UIGlobalSettingsNetwork()
m_pToolbarNetworkHost->addAction(m_pActionEditNetworkHost);
}
-#ifndef VBOX_WS_WIN
- /* On Windows host that looks ugly, but
- * On Mac OS X and X11 that deserves it's place. */
+#ifdef VBOX_WS_MAC
+ /* On macOS we can do a bit of smoothness: */
m_pLayoutNAT->setContentsMargins(0, 0, 0, 0);
m_pLayoutHostOnly->setContentsMargins(0, 0, 0, 0);
-#endif /* !VBOX_WS_WIN */
+#endif
/* Apply language settings: */
retranslateUi();
@@ -524,14 +523,16 @@ void UIGlobalSettingsNetwork::loadToCacheFrom(QVariant &data)
void UIGlobalSettingsNetwork::getFromCache()
{
/* Fetch NAT networks from cache: */
- foreach (const UIDataNetworkNAT &network, m_cache.m_networksNAT)
+ foreach (const UIDataSettingsGlobalNetworkNAT &network, m_cache.m_networksNAT)
createTreeItemNetworkNAT(network);
+ m_pTreeNetworkNAT->sortByColumn(1, Qt::AscendingOrder);
m_pTreeNetworkNAT->setCurrentItem(m_pTreeNetworkNAT->topLevelItem(0));
sltHandleCurrentItemChangeNetworkNAT();
/* Fetch Host networks from cache: */
- foreach (const UIDataNetworkHost &network, m_cache.m_networksHost)
+ foreach (const UIDataSettingsGlobalNetworkHost &network, m_cache.m_networksHost)
createTreeItemNetworkHost(network);
+ m_pTreeNetworkHost->sortByColumn(0, Qt::AscendingOrder);
m_pTreeNetworkHost->setCurrentItem(m_pTreeNetworkHost->topLevelItem(0));
sltHandleCurrentItemChangeNetworkHost();
@@ -545,7 +546,7 @@ void UIGlobalSettingsNetwork::putToCache()
m_cache.m_networksNAT.clear();
for (int iNetworkIndex = 0; iNetworkIndex < m_pTreeNetworkNAT->topLevelItemCount(); ++iNetworkIndex)
{
- UIDataNetworkNAT data;
+ UIDataSettingsGlobalNetworkNAT data;
UIItemNetworkNAT *pItem = static_cast<UIItemNetworkNAT*>(m_pTreeNetworkNAT->topLevelItem(iNetworkIndex));
pItem->uploadNetworkData(data);
m_cache.m_networksNAT << data;
@@ -555,7 +556,7 @@ void UIGlobalSettingsNetwork::putToCache()
m_cache.m_networksHost.clear();
for (int iNetworkIndex = 0; iNetworkIndex < m_pTreeNetworkHost->topLevelItemCount(); ++iNetworkIndex)
{
- UIDataNetworkHost data;
+ UIDataSettingsGlobalNetworkHost data;
UIItemNetworkHost *pItem = static_cast<UIItemNetworkHost*>(m_pTreeNetworkHost->topLevelItem(iNetworkIndex));
pItem->uploadNetworkData(data);
m_cache.m_networksHost << data;
@@ -572,11 +573,11 @@ void UIGlobalSettingsNetwork::saveFromCacheTo(QVariant &data)
UISettingsPageGlobal::fetchData(data);
/* Save NAT networks from cache: */
- foreach (const UIDataNetworkNAT &data, m_cache.m_networksNAT)
+ foreach (const UIDataSettingsGlobalNetworkNAT &data, m_cache.m_networksNAT)
saveCacheItemNetworkNAT(data);
/* Save Host networks from cache: */
- foreach (const UIDataNetworkHost &data, m_cache.m_networksHost)
+ foreach (const UIDataSettingsGlobalNetworkHost &data, m_cache.m_networksHost)
saveCacheItemNetworkHost(data);
/* Upload properties & settings to data: */
@@ -730,6 +731,7 @@ void UIGlobalSettingsNetwork::sltAddNetworkNAT()
/* Update tree: */
createTreeItemNetworkNAT(generateDataNetworkNAT(network), true);
+ m_pTreeNetworkNAT->sortByColumn(1, Qt::AscendingOrder);
}
void UIGlobalSettingsNetwork::sltDelNetworkNAT()
@@ -767,7 +769,7 @@ void UIGlobalSettingsNetwork::sltEditNetworkNAT()
AssertMsg(pItem, ("Current item should present!\n"));
/* Edit current item data: */
- UIDataNetworkNAT data;
+ UIDataSettingsGlobalNetworkNAT data;
pItem->uploadNetworkData(data);
UIGlobalSettingsNetworkDetailsNAT details(this, data);
if (details.exec() == QDialog::Accepted)
@@ -820,6 +822,7 @@ void UIGlobalSettingsNetwork::sltAddNetworkHost()
/* Update tree: */
createTreeItemNetworkHost(generateDataNetworkHost(iface), true);
+ m_pTreeNetworkHost->sortByColumn(0, Qt::AscendingOrder);
}
void UIGlobalSettingsNetwork::sltDelNetworkHost()
@@ -870,7 +873,7 @@ void UIGlobalSettingsNetwork::sltEditNetworkHost()
AssertMsg(pItem, ("Current item should present!\n"));
/* Edit current item data: */
- UIDataNetworkHost data;
+ UIDataSettingsGlobalNetworkHost data;
pItem->uploadNetworkData(data);
UIGlobalSettingsNetworkDetailsHost details(this, data);
if (details.exec() == QDialog::Accepted)
@@ -936,10 +939,10 @@ void UIGlobalSettingsNetwork::sltShowContextMenuNetworkHost(const QPoint &pos)
menu.exec(m_pTreeNetworkHost->mapToGlobal(pos));
}
-UIDataNetworkNAT UIGlobalSettingsNetwork::generateDataNetworkNAT(const CNATNetwork &network)
+UIDataSettingsGlobalNetworkNAT UIGlobalSettingsNetwork::generateDataNetworkNAT(const CNATNetwork &network)
{
/* Prepare data: */
- UIDataNetworkNAT data;
+ UIDataSettingsGlobalNetworkNAT data;
/* Load NAT network settings: */
data.m_fEnabled = network.GetEnabled();
@@ -1002,7 +1005,7 @@ UIDataNetworkNAT UIGlobalSettingsNetwork::generateDataNetworkNAT(const CNATNetwo
return data;
}
-void UIGlobalSettingsNetwork::saveCacheItemNetworkNAT(const UIDataNetworkNAT &data)
+void UIGlobalSettingsNetwork::saveCacheItemNetworkNAT(const UIDataSettingsGlobalNetworkNAT &data)
{
/* Make sure corresponding NAT network exists: */
CVirtualBox vbox = vboxGlobal().virtualBox();
@@ -1038,7 +1041,7 @@ void UIGlobalSettingsNetwork::saveCacheItemNetworkNAT(const UIDataNetworkNAT &da
newRule.guestIp, newRule.guestPort.value());
}
-void UIGlobalSettingsNetwork::createTreeItemNetworkNAT(const UIDataNetworkNAT &data, bool fChooseItem)
+void UIGlobalSettingsNetwork::createTreeItemNetworkNAT(const UIDataSettingsGlobalNetworkNAT &data, bool fChooseItem)
{
/* Add new item to the tree: */
UIItemNetworkNAT *pItem = new UIItemNetworkNAT;
@@ -1055,10 +1058,10 @@ void UIGlobalSettingsNetwork::removeTreeItemNetworkNAT(UIItemNetworkNAT *pItem)
delete pItem;
}
-UIDataNetworkHost UIGlobalSettingsNetwork::generateDataNetworkHost(const CHostNetworkInterface &iface)
+UIDataSettingsGlobalNetworkHost UIGlobalSettingsNetwork::generateDataNetworkHost(const CHostNetworkInterface &iface)
{
/* Prepare data: */
- UIDataNetworkHost data;
+ UIDataSettingsGlobalNetworkHost data;
/* Get DHCP server (create if necessary): */
CDHCPServer dhcp = vboxGlobal().virtualBox().FindDHCPServerByNetworkName(iface.GetNetworkName());
@@ -1097,7 +1100,7 @@ UIDataNetworkHost UIGlobalSettingsNetwork::generateDataNetworkHost(const CHostNe
return data;
}
-void UIGlobalSettingsNetwork::saveCacheItemNetworkHost(const UIDataNetworkHost &data)
+void UIGlobalSettingsNetwork::saveCacheItemNetworkHost(const UIDataSettingsGlobalNetworkHost &data)
{
/* Make sure corresponding Host interface exists: */
CHost host = vboxGlobal().host();
@@ -1148,23 +1151,28 @@ void UIGlobalSettingsNetwork::saveCacheItemNetworkHost(const UIDataNetworkHost &
/* Save DHCP server configuration: */
dhcp.SetEnabled(data.m_dhcpserver.m_fDhcpServerEnabled);
- AssertMsg(RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpServerAddress.toUtf8().constData()),
- ("DHCP server IPv4 address must be IPv4-valid!\n"));
- AssertMsg(RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpServerMask.toUtf8().constData()),
- ("DHCP server IPv4 network mask must be IPv4-valid!\n"));
- AssertMsg(RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpLowerAddress.toUtf8().constData()),
- ("DHCP server IPv4 lower bound must be IPv4-valid!\n"));
- AssertMsg(RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpUpperAddress.toUtf8().constData()),
- ("DHCP server IPv4 upper bound must be IPv4-valid!\n"));
- if (RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpServerAddress.toUtf8().constData()) &&
- RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpServerMask.toUtf8().constData()) &&
- RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpLowerAddress.toUtf8().constData()) &&
- RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpUpperAddress.toUtf8().constData()))
- dhcp.SetConfiguration(data.m_dhcpserver.m_strDhcpServerAddress, data.m_dhcpserver.m_strDhcpServerMask,
- data.m_dhcpserver.m_strDhcpLowerAddress, data.m_dhcpserver.m_strDhcpUpperAddress);
+ if (data.m_dhcpserver.m_fDhcpServerEnabled)
+ {
+ AssertMsg(RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpServerAddress.toUtf8().constData()),
+ ("DHCP server IPv4 address must be IPv4-valid!\n"));
+ AssertMsg(RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpServerMask.toUtf8().constData()),
+ ("DHCP server IPv4 network mask must be IPv4-valid!\n"));
+ AssertMsg(RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpLowerAddress.toUtf8().constData()),
+ ("DHCP server IPv4 lower bound must be IPv4-valid!\n"));
+ AssertMsg(RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpUpperAddress.toUtf8().constData()),
+ ("DHCP server IPv4 upper bound must be IPv4-valid!\n"));
+ if (RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpServerAddress.toUtf8().constData()) &&
+ RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpServerMask.toUtf8().constData()) &&
+ RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpLowerAddress.toUtf8().constData()) &&
+ RTNetIsIPv4AddrStr(data.m_dhcpserver.m_strDhcpUpperAddress.toUtf8().constData()))
+ dhcp.SetConfiguration(data.m_dhcpserver.m_strDhcpServerAddress, data.m_dhcpserver.m_strDhcpServerMask,
+ data.m_dhcpserver.m_strDhcpLowerAddress, data.m_dhcpserver.m_strDhcpUpperAddress);
+ }
+ if (!dhcp.isOk())
+ emit sigOperationProgressError(UIMessageCenter::formatErrorInfo(dhcp));
}
-void UIGlobalSettingsNetwork::createTreeItemNetworkHost(const UIDataNetworkHost &data, bool fChooseItem)
+void UIGlobalSettingsNetwork::createTreeItemNetworkHost(const UIDataSettingsGlobalNetworkHost &data, bool fChooseItem)
{
/* Add new item to the tree: */
UIItemNetworkHost *pItem = new UIItemNetworkHost;
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetwork.h b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetwork.h
index 32f8472..d224298 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetwork.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetwork.h
@@ -29,7 +29,7 @@ class UIItemNetworkHost;
/* Global settings / Network page / NAT network data: */
-struct UIDataNetworkNAT
+struct UIDataSettingsGlobalNetworkNAT
{
/* NAT Network: */
bool m_fEnabled;
@@ -41,7 +41,7 @@ struct UIDataNetworkNAT
bool m_fAdvertiseDefaultIPv6Route;
UIPortForwardingDataList m_ipv4rules;
UIPortForwardingDataList m_ipv6rules;
- bool operator==(const UIDataNetworkNAT &other) const
+ bool operator==(const UIDataSettingsGlobalNetworkNAT &other) const
{
return m_fEnabled == other.m_fEnabled &&
m_strName == other.m_strName &&
@@ -57,7 +57,7 @@ struct UIDataNetworkNAT
/* Global settings / Network page / Host interface data: */
-struct UIDataNetworkHostInterface
+struct UIDataSettingsGlobalNetworkHostInterface
{
/* Host Interface: */
QString m_strName;
@@ -67,7 +67,7 @@ struct UIDataNetworkHostInterface
bool m_fIpv6Supported;
QString m_strInterfaceAddress6;
QString m_strInterfaceMaskLength6;
- bool operator==(const UIDataNetworkHostInterface &other) const
+ bool operator==(const UIDataSettingsGlobalNetworkHostInterface &other) const
{
return m_strName == other.m_strName &&
m_fDhcpClientEnabled == other.m_fDhcpClientEnabled &&
@@ -80,7 +80,7 @@ struct UIDataNetworkHostInterface
};
/* Global settings / Network page / Host DHCP server data: */
-struct UIDataNetworkDHCPServer
+struct UIDataSettingsGlobalNetworkDHCPServer
{
/* DHCP Server: */
bool m_fDhcpServerEnabled;
@@ -88,7 +88,7 @@ struct UIDataNetworkDHCPServer
QString m_strDhcpServerMask;
QString m_strDhcpLowerAddress;
QString m_strDhcpUpperAddress;
- bool operator==(const UIDataNetworkDHCPServer &other) const
+ bool operator==(const UIDataSettingsGlobalNetworkDHCPServer &other) const
{
return m_fDhcpServerEnabled == other.m_fDhcpServerEnabled &&
m_strDhcpServerAddress == other.m_strDhcpServerAddress &&
@@ -99,11 +99,11 @@ struct UIDataNetworkDHCPServer
};
/* Global settings / Network page / Host network data: */
-struct UIDataNetworkHost
+struct UIDataSettingsGlobalNetworkHost
{
- UIDataNetworkHostInterface m_interface;
- UIDataNetworkDHCPServer m_dhcpserver;
- bool operator==(const UIDataNetworkHost &other) const
+ UIDataSettingsGlobalNetworkHostInterface m_interface;
+ UIDataSettingsGlobalNetworkDHCPServer m_dhcpserver;
+ bool operator==(const UIDataSettingsGlobalNetworkHost &other) const
{
return m_interface == other.m_interface &&
m_dhcpserver == other.m_dhcpserver;
@@ -114,8 +114,8 @@ struct UIDataNetworkHost
/* Global settings / Network page / Global network cache: */
struct UISettingsCacheGlobalNetwork
{
- QList<UIDataNetworkNAT> m_networksNAT;
- QList<UIDataNetworkHost> m_networksHost;
+ QList<UIDataSettingsGlobalNetworkNAT> m_networksNAT;
+ QList<UIDataSettingsGlobalNetworkHost> m_networksHost;
};
@@ -178,19 +178,19 @@ private slots:
private:
/* Helpers: NAT network cache stuff: */
- UIDataNetworkNAT generateDataNetworkNAT(const CNATNetwork &network);
- void saveCacheItemNetworkNAT(const UIDataNetworkNAT &data);
+ UIDataSettingsGlobalNetworkNAT generateDataNetworkNAT(const CNATNetwork &network);
+ void saveCacheItemNetworkNAT(const UIDataSettingsGlobalNetworkNAT &data);
/* Helpers: NAT network tree stuff: */
- void createTreeItemNetworkNAT(const UIDataNetworkNAT &data, bool fChooseItem = false);
+ void createTreeItemNetworkNAT(const UIDataSettingsGlobalNetworkNAT &data, bool fChooseItem = false);
void removeTreeItemNetworkNAT(UIItemNetworkNAT *pItem);
/* Helpers: Host network cache stuff: */
- UIDataNetworkHost generateDataNetworkHost(const CHostNetworkInterface &iface);
- void saveCacheItemNetworkHost(const UIDataNetworkHost &data);
+ UIDataSettingsGlobalNetworkHost generateDataNetworkHost(const CHostNetworkInterface &iface);
+ void saveCacheItemNetworkHost(const UIDataSettingsGlobalNetworkHost &data);
/* Helpers: Host network tree stuff: */
- void createTreeItemNetworkHost(const UIDataNetworkHost &data, bool fChooseItem = false);
+ void createTreeItemNetworkHost(const UIDataSettingsGlobalNetworkHost &data, bool fChooseItem = false);
void removeTreeItemNetworkHost(UIItemNetworkHost *pItem);
/* Variables: NAT network actions: */
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsHost.cpp b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsHost.cpp
index 0840670..de162fb 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsHost.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsHost.cpp
@@ -29,7 +29,7 @@
#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
-UIGlobalSettingsNetworkDetailsHost::UIGlobalSettingsNetworkDetailsHost(QWidget *pParent, UIDataNetworkHost &data)
+UIGlobalSettingsNetworkDetailsHost::UIGlobalSettingsNetworkDetailsHost(QWidget *pParent, UIDataSettingsGlobalNetworkHost &data)
: QIWithRetranslateUI2<QIDialog>(pParent)
, m_data(data)
{
@@ -162,10 +162,33 @@ void UIGlobalSettingsNetworkDetailsHost::loadServerStuff()
if (fIsManual)
{
+ /* Load values from COM wrappers: */
m_pDhcpAddressEditor->setText(m_data.m_dhcpserver.m_strDhcpServerAddress);
m_pDhcpMaskEditor->setText(m_data.m_dhcpserver.m_strDhcpServerMask);
m_pDhcpLowerAddressEditor->setText(m_data.m_dhcpserver.m_strDhcpLowerAddress);
m_pDhcpUpperAddressEditor->setText(m_data.m_dhcpserver.m_strDhcpUpperAddress);
+
+ /* Invent default values where necessary: */
+ const quint32 uAddr = ipv4FromQStringToQuint32(m_data.m_interface.m_strInterfaceAddress);
+ const quint32 uMask = ipv4FromQStringToQuint32(m_data.m_interface.m_strInterfaceMask);
+ const quint32 uProp = uAddr & uMask;
+ const QString strMask = ipv4FromQuint32ToQString(uMask);
+ const QString strProp = ipv4FromQuint32ToQString(uProp);
+ //printf("Proposal is = %s x %s\n",
+ // strProp.toUtf8().constData(),
+ // strMask.toUtf8().constData());
+ if ( m_data.m_dhcpserver.m_strDhcpServerAddress.isEmpty()
+ || m_data.m_dhcpserver.m_strDhcpServerAddress == "0.0.0.0")
+ m_pDhcpAddressEditor->setText(strProp);
+ if ( m_data.m_dhcpserver.m_strDhcpServerMask.isEmpty()
+ || m_data.m_dhcpserver.m_strDhcpServerMask == "0.0.0.0")
+ m_pDhcpMaskEditor->setText(strMask);
+ if ( m_data.m_dhcpserver.m_strDhcpLowerAddress.isEmpty()
+ || m_data.m_dhcpserver.m_strDhcpLowerAddress == "0.0.0.0")
+ m_pDhcpLowerAddressEditor->setText(strProp);
+ if ( m_data.m_dhcpserver.m_strDhcpUpperAddress.isEmpty()
+ || m_data.m_dhcpserver.m_strDhcpUpperAddress == "0.0.0.0")
+ m_pDhcpUpperAddressEditor->setText(strProp);
}
}
@@ -195,3 +218,31 @@ void UIGlobalSettingsNetworkDetailsHost::save()
}
}
+/* static */
+quint32 UIGlobalSettingsNetworkDetailsHost::ipv4FromQStringToQuint32(const QString &strAddress)
+{
+ quint32 uAddress = 0;
+ foreach (const QString &strPart, strAddress.split('.'))
+ {
+ uAddress = uAddress << 8;
+ bool fOk = false;
+ uint uPart = strPart.toUInt(&fOk);
+ if (fOk)
+ uAddress += uPart;
+ }
+ return uAddress;
+}
+
+/* static */
+QString UIGlobalSettingsNetworkDetailsHost::ipv4FromQuint32ToQString(quint32 uAddress)
+{
+ QStringList address;
+ while (uAddress)
+ {
+ uint uPart = uAddress & 0xFF;
+ address.prepend(QString::number(uPart));
+ uAddress = uAddress >> 8;
+ }
+ return address.join('.');
+}
+
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsHost.h b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsHost.h
index 2c633cf..2453949 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsHost.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsHost.h
@@ -24,7 +24,7 @@
#include "UIGlobalSettingsNetworkDetailsHost.gen.h"
/* Forward decalrations: */
-struct UIDataNetworkHost;
+struct UIDataSettingsGlobalNetworkHost;
/* Global settings / Network page / Details sub-dialog: */
class UIGlobalSettingsNetworkDetailsHost : public QIWithRetranslateUI2<QIDialog>, public Ui::UIGlobalSettingsNetworkDetailsHost
@@ -34,7 +34,7 @@ class UIGlobalSettingsNetworkDetailsHost : public QIWithRetranslateUI2<QIDialog>
public:
/* Constructor: */
- UIGlobalSettingsNetworkDetailsHost(QWidget *pParent, UIDataNetworkHost &data);
+ UIGlobalSettingsNetworkDetailsHost(QWidget *pParent, UIDataSettingsGlobalNetworkHost &data);
protected:
@@ -58,8 +58,13 @@ private:
void loadServerStuff();
void save();
+ /** Converts IPv4 address from QString to quint32. */
+ static quint32 ipv4FromQStringToQuint32(const QString &strAddress);
+ /** Converts IPv4 address from quint32 to QString. */
+ static QString ipv4FromQuint32ToQString(quint32 uAddress);
+
/* Variable: External data reference: */
- UIDataNetworkHost &m_data;
+ UIDataSettingsGlobalNetworkHost &m_data;
};
#endif /* __UIGlobalSettingsNetworkDetailsHost_h__ */
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsNAT.cpp b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsNAT.cpp
index ffffeae..52bd416 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsNAT.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsNAT.cpp
@@ -30,7 +30,7 @@
#endif /* !VBOX_WITH_PRECOMPILED_HEADERS */
-UIGlobalSettingsNetworkDetailsNAT::UIGlobalSettingsNetworkDetailsNAT(QWidget *pParent, UIDataNetworkNAT &data)
+UIGlobalSettingsNetworkDetailsNAT::UIGlobalSettingsNetworkDetailsNAT(QWidget *pParent, UIDataSettingsGlobalNetworkNAT &data)
: QIWithRetranslateUI2<QIDialog>(pParent)
, m_data(data)
{
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsNAT.h b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsNAT.h
index 5e68e82..33c48ac 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsNAT.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsNetworkDetailsNAT.h
@@ -24,7 +24,7 @@
#include "UIGlobalSettingsNetworkDetailsNAT.gen.h"
/* Forward decalrations: */
-struct UIDataNetworkNAT;
+struct UIDataSettingsGlobalNetworkNAT;
/* Global settings / Network page / Details sub-dialog: */
class UIGlobalSettingsNetworkDetailsNAT : public QIWithRetranslateUI2<QIDialog>, public Ui::UIGlobalSettingsNetworkDetailsNAT
@@ -34,7 +34,7 @@ class UIGlobalSettingsNetworkDetailsNAT : public QIWithRetranslateUI2<QIDialog>,
public:
/* Constructor: */
- UIGlobalSettingsNetworkDetailsNAT(QWidget *pParent, UIDataNetworkNAT &data);
+ UIGlobalSettingsNetworkDetailsNAT(QWidget *pParent, UIDataSettingsGlobalNetworkNAT &data);
protected:
@@ -59,7 +59,7 @@ private:
void save();
/* Variable: External data reference: */
- UIDataNetworkNAT &m_data;
+ UIDataSettingsGlobalNetworkNAT &m_data;
};
#endif /* __UIGlobalSettingsNetworkDetailsNAT_h__ */
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsAudio.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsAudio.h
index a12b595..ed18310 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsAudio.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsAudio.h
@@ -46,7 +46,7 @@ struct UIDataSettingsMachineAudio
KAudioDriverType m_audioDriverType;
KAudioControllerType m_audioControllerType;
};
-typedef UISettingsCache<UIDataSettingsMachineAudio> UICacheSettingsMachineAudio;
+typedef UISettingsCache<UIDataSettingsMachineAudio> UISettingsCacheMachineAudio;
/* Machine settings / Audio page: */
class UIMachineSettingsAudio : public UISettingsPageMachine, public Ui::UIMachineSettingsAudio
@@ -93,7 +93,7 @@ private:
void prepareComboboxes();
/* Cache: */
- UICacheSettingsMachineAudio m_cache;
+ UISettingsCacheMachineAudio m_cache;
};
#endif // __UIMachineSettingsAudio_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsDisplay.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsDisplay.h
index 7b0e89e..7e91033 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsDisplay.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsDisplay.h
@@ -120,7 +120,7 @@ struct UIDataSettingsMachineDisplay
int m_iVideoCaptureBitRate;
QVector<BOOL> m_screens;
};
-typedef UISettingsCache<UIDataSettingsMachineDisplay> UICacheSettingsMachineDisplay;
+typedef UISettingsCache<UIDataSettingsMachineDisplay> UISettingsCacheMachineDisplay;
/* Machine settings / Display page: */
class UIMachineSettingsDisplay : public UISettingsPageMachine,
@@ -237,7 +237,7 @@ private:
#endif /* VBOX_WITH_CRHGSMI */
/* Cache: */
- UICacheSettingsMachineDisplay m_cache;
+ UISettingsCacheMachineDisplay m_cache;
};
#endif // __UIMachineSettingsDisplay_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.h
index 683570a..2cdf939 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsGeneral.h
@@ -94,7 +94,7 @@ struct UIDataSettingsMachineGeneral
/** Holds the encryption passwords. */
EncryptionPasswordMap m_encryptionPasswords;
};
-typedef UISettingsCache<UIDataSettingsMachineGeneral> UICacheSettingsMachineGeneral;
+typedef UISettingsCache<UIDataSettingsMachineGeneral> UISettingsCacheMachineGeneral;
/** Machine settings: General page. */
class UIMachineSettingsGeneral : public UISettingsPageMachine,
@@ -171,7 +171,7 @@ private:
void polishPage();
/** Holds the page cache. */
- UICacheSettingsMachineGeneral m_cache;
+ UISettingsCacheMachineGeneral m_cache;
/** Holds whether HW virtualization extension is enabled. */
bool m_fHWVirtExEnabled;
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsInterface.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsInterface.h
index b56e4a2..36ec0dc 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsInterface.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsInterface.h
@@ -111,7 +111,7 @@ struct UIDataSettingsMachineInterface
bool m_fMiniToolBarAtTop;
#endif /* !VBOX_WS_MAC */
};
-typedef UISettingsCache<UIDataSettingsMachineInterface> UICacheSettingsMachineInterface;
+typedef UISettingsCache<UIDataSettingsMachineInterface> UISettingsCacheMachineInterface;
/* Machine settings / User Interface page: */
class UIMachineSettingsInterface : public UISettingsPageMachine,
@@ -163,7 +163,7 @@ private:
void cleanup();
/* Cache: */
- UICacheSettingsMachineInterface m_cache;
+ UISettingsCacheMachineInterface m_cache;
/** Holds the machine ID copy. */
const QString m_strMachineID;
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.cpp b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.cpp
index a63a075..b0d6b03 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.cpp
@@ -90,7 +90,7 @@ UIMachineSettingsNetwork::UIMachineSettingsNetwork(UIMachineSettingsNetworkPage
retranslateUi();
}
-void UIMachineSettingsNetwork::fetchAdapterCache(const UICacheSettingsMachineNetworkAdapter &adapterCache)
+void UIMachineSettingsNetwork::fetchAdapterCache(const UISettingsCacheMachineNetworkAdapter &adapterCache)
{
/* Get adapter data: */
const UIDataSettingsMachineNetworkAdapter &adapterData = adapterCache.base();
@@ -129,7 +129,7 @@ void UIMachineSettingsNetwork::fetchAdapterCache(const UICacheSettingsMachineNet
m_portForwardingRules = adapterData.m_redirects;
}
-void UIMachineSettingsNetwork::uploadAdapterCache(UICacheSettingsMachineNetworkAdapter &adapterCache)
+void UIMachineSettingsNetwork::uploadAdapterCache(UISettingsCacheMachineNetworkAdapter &adapterCache)
{
/* Prepare adapter data: */
UIDataSettingsMachineNetworkAdapter adapterData = adapterCache.base();
@@ -825,6 +825,10 @@ UIMachineSettingsNetworkPage::UIMachineSettingsNetworkPage()
pMainLayout->addWidget(m_pTwAdapters);
/* How many adapters to display: */
+ /** @todo r=klaus this needs to be done based on the actual chipset type of the VM,
+ * but in this place the m_machine field isn't set yet. My observation (on Linux)
+ * is that the limitation to 4 isn't necessary any more, but this needs to be checked
+ * on all platforms to be certain that it's usable everywhere. */
ulong uCount = qMin((ULONG)4, vboxGlobal().virtualBox().GetSystemProperties().GetMaxNetworkAdapters(KChipsetType_PIIX3));
/* Add corresponding tab pages to parent tab widget: */
for (ulong uSlot = 0; uSlot < uCount; ++uSlot)
@@ -965,7 +969,7 @@ void UIMachineSettingsNetworkPage::saveFromCacheTo(QVariant &data)
for (int iSlot = 0; iSlot < m_pTwAdapters->count(); ++iSlot)
{
/* Check if adapter data was changed: */
- const UICacheSettingsMachineNetworkAdapter &adapterCache = m_cache.child(iSlot);
+ const UISettingsCacheMachineNetworkAdapter &adapterCache = m_cache.child(iSlot);
if (adapterCache.wasChanged())
{
/* Check if adapter still valid: */
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.h
index 54a7ac4..843fba9 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsNetwork.h
@@ -83,7 +83,7 @@ struct UIDataSettingsMachineNetworkAdapter
bool m_fCableConnected;
UIPortForwardingDataList m_redirects;
};
-typedef UISettingsCache<UIDataSettingsMachineNetworkAdapter> UICacheSettingsMachineNetworkAdapter;
+typedef UISettingsCache<UIDataSettingsMachineNetworkAdapter> UISettingsCacheMachineNetworkAdapter;
/* Machine settings / Network page / Network data: */
struct UIDataSettingsMachineNetwork
@@ -94,7 +94,7 @@ struct UIDataSettingsMachineNetwork
bool operator==(const UIDataSettingsMachineNetwork& /* other */) const { return true; }
bool operator!=(const UIDataSettingsMachineNetwork& /* other */) const { return false; }
};
-typedef UISettingsCachePool<UIDataSettingsMachineNetwork, UICacheSettingsMachineNetworkAdapter> UICacheSettingsMachineNetwork;
+typedef UISettingsCachePool<UIDataSettingsMachineNetwork, UISettingsCacheMachineNetworkAdapter> UISettingsCacheMachineNetwork;
/* Machine settings / Network page / Adapter tab: */
class UIMachineSettingsNetwork : public QIWithRetranslateUI<QWidget>, public Ui::UIMachineSettingsNetwork
@@ -107,8 +107,8 @@ public:
UIMachineSettingsNetwork(UIMachineSettingsNetworkPage *pParent);
/* Load / Save API: */
- void fetchAdapterCache(const UICacheSettingsMachineNetworkAdapter &adapterCache);
- void uploadAdapterCache(UICacheSettingsMachineNetworkAdapter &adapterCache);
+ void fetchAdapterCache(const UISettingsCacheMachineNetworkAdapter &adapterCache);
+ void uploadAdapterCache(UISettingsCacheMachineNetworkAdapter &adapterCache);
/* API: Validation stuff: */
bool validate(QList<UIValidationMessage> &messages);
@@ -260,7 +260,7 @@ private:
QStringList m_natNetworkList;
/* Cache: */
- UICacheSettingsMachineNetwork m_cache;
+ UISettingsCacheMachineNetwork m_cache;
};
#endif // __UIMachineSettingsNetwork_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsParallel.cpp b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsParallel.cpp
index e20f219..c3d40ae 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsParallel.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsParallel.cpp
@@ -86,7 +86,7 @@ void UIMachineSettingsParallel::polishTab()
mLePath->setEnabled(m_pParent->isMachineOffline());
}
-void UIMachineSettingsParallel::fetchPortData(const UICacheSettingsMachineParallelPort &portCache)
+void UIMachineSettingsParallel::fetchPortData(const UISettingsCacheMachineParallelPort &portCache)
{
/* Get port data: */
const UIDataSettingsMachineParallelPort &portData = portCache.base();
@@ -105,7 +105,7 @@ void UIMachineSettingsParallel::fetchPortData(const UICacheSettingsMachineParall
mGbParallelToggled(mGbParallel->isChecked());
}
-void UIMachineSettingsParallel::uploadPortData(UICacheSettingsMachineParallelPort &portCache)
+void UIMachineSettingsParallel::uploadPortData(UISettingsCacheMachineParallelPort &portCache)
{
/* Prepare port data: */
UIDataSettingsMachineParallelPort portData = portCache.base();
@@ -302,7 +302,7 @@ void UIMachineSettingsParallelPage::saveFromCacheTo(QVariant &data)
for (int iPort = 0; iPort < mTabWidget->count(); ++iPort)
{
/* Check if port data was changed: */
- const UICacheSettingsMachineParallelPort &portCache = m_cache.child(iPort);
+ const UISettingsCacheMachineParallelPort &portCache = m_cache.child(iPort);
if (portCache.wasChanged())
{
/* Check if port still valid: */
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsParallel.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsParallel.h
index d704179..d17ae0d 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsParallel.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsParallel.h
@@ -55,7 +55,7 @@ struct UIDataSettingsMachineParallelPort
ulong m_uIOBase;
QString m_strPath;
};
-typedef UISettingsCache<UIDataSettingsMachineParallelPort> UICacheSettingsMachineParallelPort;
+typedef UISettingsCache<UIDataSettingsMachineParallelPort> UISettingsCacheMachineParallelPort;
/* Machine settings / Parallel page / Ports data: */
struct UIDataSettingsMachineParallel
@@ -66,7 +66,7 @@ struct UIDataSettingsMachineParallel
bool operator==(const UIDataSettingsMachineParallel& /* other */) const { return true; }
bool operator!=(const UIDataSettingsMachineParallel& /* other */) const { return false; }
};
-typedef UISettingsCachePool<UIDataSettingsMachineParallel, UICacheSettingsMachineParallelPort> UICacheSettingsMachineParallel;
+typedef UISettingsCachePool<UIDataSettingsMachineParallel, UISettingsCacheMachineParallelPort> UISettingsCacheMachineParallel;
class UIMachineSettingsParallel : public QIWithRetranslateUI<QWidget>,
public Ui::UIMachineSettingsParallel
@@ -79,8 +79,8 @@ public:
void polishTab();
- void fetchPortData(const UICacheSettingsMachineParallelPort &portCache);
- void uploadPortData(UICacheSettingsMachineParallelPort &portCache);
+ void fetchPortData(const UISettingsCacheMachineParallelPort &portCache);
+ void uploadPortData(UISettingsCacheMachineParallelPort &portCache);
QWidget* setOrderAfter (QWidget *aAfter);
@@ -145,7 +145,7 @@ private:
QITabWidget *mTabWidget;
/* Cache: */
- UICacheSettingsMachineParallel m_cache;
+ UISettingsCacheMachineParallel m_cache;
};
#endif // __UIMachineSettingsParallel_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSF.cpp b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSF.cpp
index 686b0fb..00e5590 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSF.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSF.cpp
@@ -365,7 +365,7 @@ void UIMachineSettingsSF::saveFromCacheTo(UISharedFolderType sharedFoldersType)
for (int iSharedFolderIndex = 0; iSharedFolderIndex < m_cache.childCount(); ++iSharedFolderIndex)
{
/* Check if this shared folder data was actually changed: */
- const UICacheSettingsSharedFolder &sharedFolderCache = m_cache.child(iSharedFolderIndex);
+ const UISettingsCacheSharedFolder &sharedFolderCache = m_cache.child(iSharedFolderIndex);
if (sharedFolderCache.wasChanged())
{
/* If shared folder was removed: */
@@ -741,7 +741,7 @@ CSharedFolderVector UIMachineSettingsSF::getSharedFolders(UISharedFolderType sha
return sharedFolders;
}
-bool UIMachineSettingsSF::removeSharedFolder(const UICacheSettingsSharedFolder &folderCache)
+bool UIMachineSettingsSF::removeSharedFolder(const UISettingsCacheSharedFolder &folderCache)
{
/* Get shared folder data: */
const UIDataSettingsSharedFolder &folderData = folderCache.base();
@@ -796,7 +796,7 @@ bool UIMachineSettingsSF::removeSharedFolder(const UICacheSettingsSharedFolder &
return true;
}
-bool UIMachineSettingsSF::createSharedFolder(const UICacheSettingsSharedFolder &folderCache)
+bool UIMachineSettingsSF::createSharedFolder(const UISettingsCacheSharedFolder &folderCache)
{
/* Get shared folder data: */
const UIDataSettingsSharedFolder &folderData = folderCache.data();
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSF.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSF.h
index c515917..8200df1 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSF.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSF.h
@@ -61,7 +61,7 @@ struct UIDataSettingsSharedFolder
bool m_fAutoMount;
bool m_fWritable;
};
-typedef UISettingsCache<UIDataSettingsSharedFolder> UICacheSettingsSharedFolder;
+typedef UISettingsCache<UIDataSettingsSharedFolder> UISettingsCacheSharedFolder;
/* Machine settings / Shared Folders page / Shared Folders data: */
struct UIDataSettingsSharedFolders
@@ -72,7 +72,7 @@ struct UIDataSettingsSharedFolders
bool operator==(const UIDataSettingsSharedFolders& /* other */) const { return true; }
bool operator!=(const UIDataSettingsSharedFolders& /* other */) const { return false; }
};
-typedef UISettingsCachePool<UIDataSettingsSharedFolders, UICacheSettingsSharedFolder> UICacheSettingsSharedFolders;
+typedef UISettingsCachePool<UIDataSettingsSharedFolders, UISettingsCacheSharedFolder> UISettingsCacheSharedFolders;
class UIMachineSettingsSF : public UISettingsPageMachine,
public Ui::UIMachineSettingsSF
@@ -138,8 +138,8 @@ private:
CSharedFolderVector getSharedFolders(UISharedFolderType sharedFoldersType);
- bool removeSharedFolder(const UICacheSettingsSharedFolder &folderCache);
- bool createSharedFolder(const UICacheSettingsSharedFolder &folderCache);
+ bool removeSharedFolder(const UISettingsCacheSharedFolder &folderCache);
+ bool createSharedFolder(const UISettingsCacheSharedFolder &folderCache);
QAction *mNewAction;
QAction *mEdtAction;
@@ -149,7 +149,7 @@ private:
QString mTrYes;
/* Cache: */
- UICacheSettingsSharedFolders m_cache;
+ UISettingsCacheSharedFolders m_cache;
};
#endif // __UIMachineSettingsSF_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSerial.cpp b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSerial.cpp
index 65ef327..c1ee5d4 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSerial.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSerial.cpp
@@ -100,7 +100,7 @@ void UIMachineSettingsSerial::polishTab()
mLePath->setEnabled(mode != KPortMode_Disconnected && m_pParent->isMachineOffline());
}
-void UIMachineSettingsSerial::fetchPortData(const UICacheSettingsMachineSerialPort &portCache)
+void UIMachineSettingsSerial::fetchPortData(const UISettingsCacheMachineSerialPort &portCache)
{
/* Get port data: */
const UIDataSettingsMachineSerialPort &portData = portCache.base();
@@ -121,7 +121,7 @@ void UIMachineSettingsSerial::fetchPortData(const UICacheSettingsMachineSerialPo
mGbSerialToggled(mGbSerial->isChecked());
}
-void UIMachineSettingsSerial::uploadPortData(UICacheSettingsMachineSerialPort &portCache)
+void UIMachineSettingsSerial::uploadPortData(UISettingsCacheMachineSerialPort &portCache)
{
/* Prepare port data: */
UIDataSettingsMachineSerialPort portData = portCache.base();
@@ -343,7 +343,7 @@ void UIMachineSettingsSerialPage::saveFromCacheTo(QVariant &data)
for (int iPort = 0; iPort < mTabWidget->count(); ++iPort)
{
/* Check if port data was changed: */
- const UICacheSettingsMachineSerialPort &portCache = m_cache.child(iPort);
+ const UISettingsCacheMachineSerialPort &portCache = m_cache.child(iPort);
if (portCache.wasChanged())
{
/* Check if port still valid: */
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSerial.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSerial.h
index b34379e..56d93d2 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSerial.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSerial.h
@@ -61,7 +61,7 @@ struct UIDataSettingsMachineSerialPort
bool m_fServer;
QString m_strPath;
};
-typedef UISettingsCache<UIDataSettingsMachineSerialPort> UICacheSettingsMachineSerialPort;
+typedef UISettingsCache<UIDataSettingsMachineSerialPort> UISettingsCacheMachineSerialPort;
/* Machine settings / Serial page / Ports data: */
struct UIDataSettingsMachineSerial
@@ -72,7 +72,7 @@ struct UIDataSettingsMachineSerial
bool operator==(const UIDataSettingsMachineSerial& /* other */) const { return true; }
bool operator!=(const UIDataSettingsMachineSerial& /* other */) const { return false; }
};
-typedef UISettingsCachePool<UIDataSettingsMachineSerial, UICacheSettingsMachineSerialPort> UICacheSettingsMachineSerial;
+typedef UISettingsCachePool<UIDataSettingsMachineSerial, UISettingsCacheMachineSerialPort> UISettingsCacheMachineSerial;
class UIMachineSettingsSerial : public QIWithRetranslateUI<QWidget>,
public Ui::UIMachineSettingsSerial
@@ -85,8 +85,8 @@ public:
void polishTab();
- void fetchPortData(const UICacheSettingsMachineSerialPort &data);
- void uploadPortData(UICacheSettingsMachineSerialPort &data);
+ void fetchPortData(const UISettingsCacheMachineSerialPort &data);
+ void uploadPortData(UISettingsCacheMachineSerialPort &data);
QWidget* setOrderAfter (QWidget *aAfter);
@@ -152,7 +152,7 @@ private:
QITabWidget *mTabWidget;
/* Cache: */
- UICacheSettingsMachineSerial m_cache;
+ UISettingsCacheMachineSerial m_cache;
};
#endif // __UIMachineSettingsSerial_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.cpp b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.cpp
index 6970823..26619c9 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.cpp
@@ -2268,7 +2268,7 @@ void UIMachineSettingsStorage::getFromCache()
for (int iControllerIndex = 0; iControllerIndex < m_cache.childCount(); ++iControllerIndex)
{
/* Get storage controller cache: */
- const UICacheSettingsMachineStorageController &controllerCache = m_cache.child(iControllerIndex);
+ const UISettingsCacheMachineStorageController &controllerCache = m_cache.child(iControllerIndex);
/* Get storage controller data from cache: */
const UIDataSettingsMachineStorageController &controllerData = controllerCache.base();
@@ -2284,7 +2284,7 @@ void UIMachineSettingsStorage::getFromCache()
for (int iAttachmentIndex = 0; iAttachmentIndex < controllerCache.childCount(); ++iAttachmentIndex)
{
/* Get storage attachment cache: */
- const UICacheSettingsMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
+ const UISettingsCacheMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
/* Get storage controller data from cache: */
const UIDataSettingsMachineStorageAttachment &attachmentData = attachmentCache.base();
@@ -3563,7 +3563,7 @@ bool UIMachineSettingsStorage::updateStorageData()
for (int iControllerIndex = 0; fSuccess && iControllerIndex < m_cache.childCount(); ++iControllerIndex)
{
/* Get controller cache: */
- const UICacheSettingsMachineStorageController &controllerCache = m_cache.child(iControllerIndex);
+ const UISettingsCacheMachineStorageController &controllerCache = m_cache.child(iControllerIndex);
/* Remove controllers marked for 'remove' and 'update' (if they can't be updated): */
if (controllerCache.wasRemoved() || (controllerCache.wasUpdated() && !isControllerCouldBeUpdated(controllerCache)))
@@ -3578,7 +3578,7 @@ bool UIMachineSettingsStorage::updateStorageData()
for (int iAttachmentIndex = 0; fSuccess && iAttachmentIndex < controllerCache.childCount(); ++iAttachmentIndex)
{
/* Get attachment cache: */
- const UICacheSettingsMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
+ const UISettingsCacheMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
/* Remove attachments marked for 'remove' and 'update' (if they can't be updated): */
if (attachmentCache.wasRemoved() || (attachmentCache.wasUpdated() && !isAttachmentCouldBeUpdated(attachmentCache)))
@@ -3591,7 +3591,7 @@ bool UIMachineSettingsStorage::updateStorageData()
for (int iControllerIndex = 0; fSuccess && iControllerIndex < m_cache.childCount(); ++iControllerIndex)
{
/* Get controller cache: */
- const UICacheSettingsMachineStorageController &controllerCache = m_cache.child(iControllerIndex);
+ const UISettingsCacheMachineStorageController &controllerCache = m_cache.child(iControllerIndex);
/* Create controllers marked for 'create' or 'update' (if they can't be updated): */
if (controllerCache.wasCreated() || (controllerCache.wasUpdated() && !isControllerCouldBeUpdated(controllerCache)))
@@ -3609,7 +3609,7 @@ bool UIMachineSettingsStorage::updateStorageData()
return fSuccess;
}
-bool UIMachineSettingsStorage::removeStorageController(const UICacheSettingsMachineStorageController &controllerCache)
+bool UIMachineSettingsStorage::removeStorageController(const UISettingsCacheMachineStorageController &controllerCache)
{
/* Prepare result: */
bool fSuccess = m_machine.isOk();
@@ -3638,7 +3638,7 @@ bool UIMachineSettingsStorage::removeStorageController(const UICacheSettingsMach
return fSuccess;
}
-bool UIMachineSettingsStorage::createStorageController(const UICacheSettingsMachineStorageController &controllerCache)
+bool UIMachineSettingsStorage::createStorageController(const UISettingsCacheMachineStorageController &controllerCache)
{
/* Prepare result: */
bool fSuccess = m_machine.isOk();
@@ -3681,7 +3681,7 @@ bool UIMachineSettingsStorage::createStorageController(const UICacheSettingsMach
for (int iAttachmentIndex = 0; fSuccess && iAttachmentIndex < controllerCache.childCount(); ++iAttachmentIndex)
{
/* Get storage attachment cache: */
- const UICacheSettingsMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
+ const UISettingsCacheMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
/* Create attachment if it was not just 'removed': */
if (!attachmentCache.wasRemoved())
@@ -3694,7 +3694,7 @@ bool UIMachineSettingsStorage::createStorageController(const UICacheSettingsMach
return fSuccess;
}
-bool UIMachineSettingsStorage::updateStorageController(const UICacheSettingsMachineStorageController &controllerCache)
+bool UIMachineSettingsStorage::updateStorageController(const UISettingsCacheMachineStorageController &controllerCache)
{
/* Prepare result: */
bool fSuccess = m_machine.isOk();
@@ -3730,7 +3730,7 @@ bool UIMachineSettingsStorage::updateStorageController(const UICacheSettingsMach
for (int iAttachmentIndex = 0; fSuccess && iAttachmentIndex < controllerCache.childCount(); ++iAttachmentIndex)
{
/* Get storage attachment cache: */
- const UICacheSettingsMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
+ const UISettingsCacheMachineStorageAttachment &attachmentCache = controllerCache.child(iAttachmentIndex);
/* Create attachments marked for 'create' and 'update' (if they can't be updated): */
if (attachmentCache.wasCreated() || (attachmentCache.wasUpdated() && !isAttachmentCouldBeUpdated(attachmentCache)))
@@ -3748,8 +3748,8 @@ bool UIMachineSettingsStorage::updateStorageController(const UICacheSettingsMach
return fSuccess;
}
-bool UIMachineSettingsStorage::removeStorageAttachment(const UICacheSettingsMachineStorageController &controllerCache,
- const UICacheSettingsMachineStorageAttachment &attachmentCache)
+bool UIMachineSettingsStorage::removeStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
+ const UISettingsCacheMachineStorageAttachment &attachmentCache)
{
/* Prepare result: */
bool fSuccess = m_machine.isOk();
@@ -3783,8 +3783,8 @@ bool UIMachineSettingsStorage::removeStorageAttachment(const UICacheSettingsMach
return fSuccess;
}
-bool UIMachineSettingsStorage::createStorageAttachment(const UICacheSettingsMachineStorageController &controllerCache,
- const UICacheSettingsMachineStorageAttachment &attachmentCache)
+bool UIMachineSettingsStorage::createStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
+ const UISettingsCacheMachineStorageAttachment &attachmentCache)
{
/* Prepare result: */
bool fSuccess = m_machine.isOk();
@@ -3872,8 +3872,8 @@ bool UIMachineSettingsStorage::createStorageAttachment(const UICacheSettingsMach
return fSuccess;
}
-bool UIMachineSettingsStorage::updateStorageAttachment(const UICacheSettingsMachineStorageController &controllerCache,
- const UICacheSettingsMachineStorageAttachment &attachmentCache)
+bool UIMachineSettingsStorage::updateStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
+ const UISettingsCacheMachineStorageAttachment &attachmentCache)
{
/* Prepare result: */
bool fSuccess = m_machine.isOk();
@@ -3961,7 +3961,7 @@ bool UIMachineSettingsStorage::updateStorageAttachment(const UICacheSettingsMach
return fSuccess;
}
-bool UIMachineSettingsStorage::isControllerCouldBeUpdated(const UICacheSettingsMachineStorageController &controllerCache) const
+bool UIMachineSettingsStorage::isControllerCouldBeUpdated(const UISettingsCacheMachineStorageController &controllerCache) const
{
/* IController interface doesn't allows to change 'name' and 'bus' attributes.
* But those attributes could be changed in GUI directly or indirectly.
@@ -3973,7 +3973,7 @@ bool UIMachineSettingsStorage::isControllerCouldBeUpdated(const UICacheSettingsM
newControllerData.m_strControllerName == oldControllerData.m_strControllerName;
}
-bool UIMachineSettingsStorage::isAttachmentCouldBeUpdated(const UICacheSettingsMachineStorageAttachment &attachmentCache) const
+bool UIMachineSettingsStorage::isAttachmentCouldBeUpdated(const UISettingsCacheMachineStorageAttachment &attachmentCache) const
{
/* IMediumAttachment could be indirectly updated through IMachine
* only if attachment type, device and port were NOT changed and is one of the next types:
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.h
index 00bf5af..56e7b68 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.h
@@ -624,7 +624,7 @@ struct UIDataSettingsMachineStorageAttachment
bool m_fAttachmentNonRotational;
bool m_fAttachmentHotPluggable;
};
-typedef UISettingsCache<UIDataSettingsMachineStorageAttachment> UICacheSettingsMachineStorageAttachment;
+typedef UISettingsCache<UIDataSettingsMachineStorageAttachment> UISettingsCacheMachineStorageAttachment;
/* Machine settings / Storage page / Storage controller data: */
struct UIDataSettingsMachineStorageController
@@ -655,7 +655,7 @@ struct UIDataSettingsMachineStorageController
uint m_uPortCount;
bool m_fUseHostIOCache;
};
-typedef UISettingsCachePool<UIDataSettingsMachineStorageController, UICacheSettingsMachineStorageAttachment> UICacheSettingsMachineStorageController;
+typedef UISettingsCachePool<UIDataSettingsMachineStorageController, UISettingsCacheMachineStorageAttachment> UISettingsCacheMachineStorageController;
/* Machine settings / Storage page / Storage data: */
struct UIDataSettingsMachineStorage
@@ -666,7 +666,7 @@ struct UIDataSettingsMachineStorage
bool operator==(const UIDataSettingsMachineStorage& /* other */) const { return true; }
bool operator!=(const UIDataSettingsMachineStorage& /* other */) const { return false; }
};
-typedef UISettingsCachePool<UIDataSettingsMachineStorage, UICacheSettingsMachineStorageController> UICacheSettingsMachineStorage;
+typedef UISettingsCachePool<UIDataSettingsMachineStorage, UISettingsCacheMachineStorageController> UISettingsCacheMachineStorage;
/* Machine settings / Storage page: */
class UIMachineSettingsStorage : public UISettingsPageMachine,
@@ -775,17 +775,17 @@ private:
void addRecentMediumActions(QMenu *pOpenMediumMenu, UIMediumType recentMediumType);
bool updateStorageData();
- bool removeStorageController(const UICacheSettingsMachineStorageController &controllerCache);
- bool createStorageController(const UICacheSettingsMachineStorageController &controllerCache);
- bool updateStorageController(const UICacheSettingsMachineStorageController &controllerCache);
- bool removeStorageAttachment(const UICacheSettingsMachineStorageController &controllerCache,
- const UICacheSettingsMachineStorageAttachment &attachmentCache);
- bool createStorageAttachment(const UICacheSettingsMachineStorageController &controllerCache,
- const UICacheSettingsMachineStorageAttachment &attachmentCache);
- bool updateStorageAttachment(const UICacheSettingsMachineStorageController &controllerCache,
- const UICacheSettingsMachineStorageAttachment &attachmentCache);
- bool isControllerCouldBeUpdated(const UICacheSettingsMachineStorageController &controllerCache) const;
- bool isAttachmentCouldBeUpdated(const UICacheSettingsMachineStorageAttachment &attachmentCache) const;
+ bool removeStorageController(const UISettingsCacheMachineStorageController &controllerCache);
+ bool createStorageController(const UISettingsCacheMachineStorageController &controllerCache);
+ bool updateStorageController(const UISettingsCacheMachineStorageController &controllerCache);
+ bool removeStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
+ const UISettingsCacheMachineStorageAttachment &attachmentCache);
+ bool createStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
+ const UISettingsCacheMachineStorageAttachment &attachmentCache);
+ bool updateStorageAttachment(const UISettingsCacheMachineStorageController &controllerCache,
+ const UISettingsCacheMachineStorageAttachment &attachmentCache);
+ bool isControllerCouldBeUpdated(const UISettingsCacheMachineStorageController &controllerCache) const;
+ bool isAttachmentCouldBeUpdated(const UISettingsCacheMachineStorageAttachment &attachmentCache) const;
/** Defines configuration access level. */
void setConfigurationAccessLevel(ConfigurationAccessLevel configurationAccessLevel);
@@ -820,7 +820,7 @@ private:
bool mDisableStaticControls;
/* Cache: */
- UICacheSettingsMachineStorage m_cache;
+ UISettingsCacheMachineStorage m_cache;
};
#endif // __UIMachineSettingsStorage_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSystem.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSystem.h
index 2f3b5ac..c1e2df8 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSystem.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsSystem.h
@@ -115,7 +115,7 @@ struct UIDataSettingsMachineSystem
bool m_fEnabledHwVirtEx;
bool m_fEnabledNestedPaging;
};
-typedef UISettingsCache<UIDataSettingsMachineSystem> UICacheSettingsMachineSystem;
+typedef UISettingsCache<UIDataSettingsMachineSystem> UISettingsCacheMachineSystem;
/* Machine settings / System page: */
class UIMachineSettingsSystem : public UISettingsPageMachine,
@@ -217,7 +217,7 @@ private:
bool m_fIsUSBEnabled;
/* Cache: */
- UICacheSettingsMachineSystem m_cache;
+ UISettingsCacheMachineSystem m_cache;
};
#endif // __UIMachineSettingsSystem_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.cpp b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.cpp
index b22768c..a777076 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.cpp
@@ -490,7 +490,7 @@ void UIMachineSettingsUSB::saveFromCacheTo(QVariant &data)
for (int iFilterIndex = 0; iFilterIndex < m_cache.childCount(); ++iFilterIndex)
{
/* Check if USB filter data really changed: */
- const UICacheSettingsMachineUSBFilter &usbFilterCache = m_cache.child(iFilterIndex);
+ const UISettingsCacheMachineUSBFilter &usbFilterCache = m_cache.child(iFilterIndex);
if (usbFilterCache.wasChanged())
{
/* If filter was removed or updated: */
diff --git a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h
index fdd0fd2..0d24abf 100644
--- a/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h
+++ b/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsUSB.h
@@ -79,7 +79,7 @@ struct UIDataSettingsMachineUSBFilter
bool m_fHostUSBDevice;
KUSBDeviceState m_hostUSBDeviceState;
};
-typedef UISettingsCache<UIDataSettingsMachineUSBFilter> UICacheSettingsMachineUSBFilter;
+typedef UISettingsCache<UIDataSettingsMachineUSBFilter> UISettingsCacheMachineUSBFilter;
/* Common settings / USB page / USB data: */
struct UIDataSettingsMachineUSB
@@ -101,7 +101,7 @@ struct UIDataSettingsMachineUSB
bool m_fUSBEnabled;
KUSBControllerType m_USBControllerType;
};
-typedef UISettingsCachePool<UIDataSettingsMachineUSB, UICacheSettingsMachineUSBFilter> UICacheSettingsMachineUSB;
+typedef UISettingsCachePool<UIDataSettingsMachineUSB, UISettingsCacheMachineUSBFilter> UISettingsCacheMachineUSB;
/* Common settings / USB page: */
class UIMachineSettingsUSB : public UISettingsPageMachine,
@@ -188,7 +188,7 @@ private:
QList<UIDataSettingsMachineUSBFilter> m_filters;
/* Cache: */
- UICacheSettingsMachineUSB m_cache;
+ UISettingsCacheMachineUSB m_cache;
};
#endif // __UIMachineSettingsUSB_h__
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
index 6c73467..a9824b6 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.cpp
@@ -390,14 +390,23 @@ void UIMiniToolBarPrivate::rebuildShape()
}
/* static */
-Qt::WindowFlags UIMiniToolBar::defaultWindowFlags()
+Qt::WindowFlags UIMiniToolBar::defaultWindowFlags(GeometryType geometryType)
{
+ /* Not everywhere: */
+ Q_UNUSED(geometryType);
+
#ifdef VBOX_WS_X11
/* Depending on current WM: */
switch (vboxGlobal().typeOfWindowManager())
{
- /* Frameless top-level window for Unity, issues with tool window there.. */
- case X11WMType_Compiz: return Qt::Window | Qt::FramelessWindowHint;
+ // WORKAROUND:
+ // Frameless top-level window for Unity(Compiz) full-screen mode,
+ // otherwise we have Unity panel and menu-bar visible in full-screen mode.
+ // Frameless top-level tool-window for Unity(Compiz) seamless mode,
+ // otherwise we have Unity panel and menu-bar hidden in seamless mode.
+ case X11WMType_Compiz: return geometryType == GeometryType_Full ?
+ Qt::Window | Qt::FramelessWindowHint :
+ Qt::Tool | Qt::FramelessWindowHint;
default: break;
}
#endif /* VBOX_WS_X11 */
@@ -410,7 +419,7 @@ UIMiniToolBar::UIMiniToolBar(QWidget *pParent,
GeometryType geometryType,
Qt::Alignment alignment,
bool fAutoHide /* = true */)
- : QWidget(pParent, defaultWindowFlags())
+ : QWidget(pParent, defaultWindowFlags(geometryType))
/* Variables: General stuff: */
, m_geometryType(geometryType)
, m_alignment(alignment)
@@ -790,6 +799,12 @@ void UIMiniToolBar::prepare()
/* Adjust geometry first time: */
adjustGeometry();
+
+#ifdef VBOX_WS_X11
+ /* Hide mini-toolbar from taskbar and pager: */
+ vboxGlobal().setSkipTaskBarFlag(this);
+ vboxGlobal().setSkipPagerFlag(this);
+#endif
}
void UIMiniToolBar::cleanup()
@@ -822,6 +837,19 @@ void UIMiniToolBar::enterEvent(QEvent*)
void UIMiniToolBar::leaveEvent(QEvent*)
{
+ // WORKAROUND:
+ // No idea why, but GUI receives mouse leave event
+ // when the mouse cursor is on the border of screen
+ // even if underlying widget is on the border of
+ // screen as well, we should detect and ignore that.
+ // Besides that, this is a good way to keep the
+ // tool-bar visible when the mouse moving through
+ // the desktop strut till the real screen border.
+ const QPoint cursorPosition = QCursor::pos();
+ if ( cursorPosition.y() <= y() + 1
+ || cursorPosition.y() >= y() + height() - 1)
+ return;
+
/* Stop the hover-enter timer if necessary: */
if (m_pHoverEnterTimer && m_pHoverEnterTimer->isActive())
m_pHoverEnterTimer->stop();
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
index 8f60e50..d47122b 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIMiniToolBar.h
@@ -66,7 +66,7 @@ signals:
public:
/** Proposes default set of window flags for particular platform. */
- static Qt::WindowFlags defaultWindowFlags();
+ static Qt::WindowFlags defaultWindowFlags(GeometryType geometryType);
/** Constructor, passes @a pParent to the QWidget constructor.
* @param geometryType determines the geometry type,
diff --git a/src/VBox/Frontends/VirtualBox/src/widgets/UIPortForwardingTable.cpp b/src/VBox/Frontends/VirtualBox/src/widgets/UIPortForwardingTable.cpp
index 52eb13c..51e36b0 100644
--- a/src/VBox/Frontends/VirtualBox/src/widgets/UIPortForwardingTable.cpp
+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIPortForwardingTable.cpp
@@ -511,11 +511,10 @@ UIPortForwardingTable::UIPortForwardingTable(const UIPortForwardingDataList &rul
QHBoxLayout *pMainLayout = new QHBoxLayout(this);
{
/* Configure layout: */
-#ifndef VBOX_WS_WIN
- /* On Windows host that looks ugly, but
- * On Mac OS X and X11 that deserves it's place. */
+#ifdef VBOX_WS_MAC
+ /* On macOS we can do a bit of smoothness: */
pMainLayout->setContentsMargins(0, 0, 0, 0);
-#endif /* !VBOX_WS_WIN */
+#endif
pMainLayout->setSpacing(3);
/* Create model: */
m_pModel = new UIPortForwardingModel(this, rules);
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp b/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp
index ba3e0af..db962a7 100644
--- a/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp
+++ b/src/VBox/HostDrivers/VBoxNetFlt/win/cfg/VBoxNetCfg.cpp
@@ -81,7 +81,7 @@ static PFNSETIPINTERFACEENTRY g_pfnSetIpInterfaceEntry = NULL;
/*
* Forward declaration for using vboxNetCfgWinSetupMetric()
*/
-HRESULT vboxNetCfgWinSetupMetric(IN HKEY hKey);
+HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid);
HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID* pLUID);
@@ -315,7 +315,7 @@ VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pNetCfg, I
{
if (pTempComponent != NULL)
{
- HKEY hkey;
+ HKEY hkey = (HKEY)INVALID_HANDLE_VALUE;
HRESULT res;
/*
@@ -325,9 +325,17 @@ VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pNetCfg, I
res = pTempComponent->OpenParamKey(&hkey);
/* Set default metric value for host-only interface only */
- if (SUCCEEDED(res) && hkey != NULL && wcsnicmp(pszwComponentId, VBOXNETCFGWIN_NETADP_ID, 256) == 0)
+ if ( SUCCEEDED(res)
+ && hkey != INVALID_HANDLE_VALUE
+ && wcsnicmp(pszwComponentId, VBOXNETCFGWIN_NETADP_ID, 256) == 0)
{
- res = vboxNetCfgWinSetupMetric(hkey);
+ NET_LUID luid;
+ res = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
+
+ /* Close the key as soon as possible. See @bugref{7973}. */
+ RegCloseKey (hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
+
if (FAILED(res))
{
/*
@@ -335,9 +343,28 @@ VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinInstallComponent(IN INetCfg *pNetCfg, I
* So we will not break installation process due to this error.
*/
NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! "
- "vboxNetCfgWinSetupMetric failed, default metric "
- "for new interface will not be set, hr (0x%x)\n", res));
+ "vboxNetCfgWinGetInterfaceLUID failed, default metric "
+ "for new interface will not be set, hr (0x%x)\n", res));
}
+ else
+ {
+ res = vboxNetCfgWinSetupMetric(&luid);
+ if (FAILED(res))
+ {
+ /*
+ * The setting of Metric is not very important functionality,
+ * So we will not break installation process due to this error.
+ */
+ NonStandardLogFlow(("VBoxNetCfgWinInstallComponent Warning! "
+ "vboxNetCfgWinSetupMetric failed, default metric "
+ "for new interface will not be set, hr (0x%x)\n", res));
+ }
+ }
+ }
+ if (hkey != INVALID_HANDLE_VALUE)
+ {
+ RegCloseKey (hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
}
if (ppComponent != NULL)
*ppComponent = pTempComponent;
@@ -3133,16 +3160,6 @@ static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath,
SetErrBreak (("SetupDiCallClassInstaller (DIF_INSTALLDEVICE) failed (0x%08X)",
GetLastError()));
- /* Figure out NetCfgInstanceId */
- hkey = SetupDiOpenDevRegKey(hDeviceInfo,
- &DeviceInfoData,
- DICS_FLAG_GLOBAL,
- 0,
- DIREG_DRV,
- KEY_READ);
- if (hkey == INVALID_HANDLE_VALUE)
- SetErrBreak(("SetupDiOpenDevRegKey failed (0x%08X)", GetLastError()));
-
/* Query the instance ID; on Windows 10, the registry key may take a short
* while to appear. Microsoft recommends waiting for up to 5 seconds, but
* we want to be on the safe side, so let's wait for 20 seconds. Waiting
@@ -3151,14 +3168,27 @@ static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath,
*/
for (int retries = 0; retries < 2 * 20; ++retries)
{
+ Sleep(500); /* half second */
+
+ /* Figure out NetCfgInstanceId */
+ hkey = SetupDiOpenDevRegKey(hDeviceInfo,
+ &DeviceInfoData,
+ DICS_FLAG_GLOBAL,
+ 0,
+ DIREG_DRV,
+ KEY_READ);
+ if (hkey == INVALID_HANDLE_VALUE)
+ break;
+
cbSize = sizeof(pWCfgGuidString);
ret = RegQueryValueExW (hkey, L"NetCfgInstanceId", NULL,
&dwValueType, (LPBYTE) pWCfgGuidString, &cbSize);
/* As long as the return code is FILE_NOT_FOUND, sleep and retry. */
- if (ret == ERROR_FILE_NOT_FOUND)
- Sleep(500); /* half second */
- else
+ if (ret != ERROR_FILE_NOT_FOUND)
break;
+
+ RegCloseKey (hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
}
if (ret == ERROR_FILE_NOT_FOUND)
@@ -3167,14 +3197,23 @@ static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath,
break;
}
+ /*
+ * We need to check 'hkey' after we check 'ret' to distinguish the case
+ * of failed SetupDiOpenDevRegKey from the case when we timed out.
+ */
+ if (hkey == INVALID_HANDLE_VALUE)
+ SetErrBreak(("SetupDiOpenDevRegKey failed (0x%08X)", GetLastError()));
+
if (ret != ERROR_SUCCESS)
SetErrBreak(("Querying NetCfgInstanceId failed (0x%08X)", ret));
- /*
- * Set default metric value of interface to fix multicast issue
- * See @bugref{6379} for details.
- */
- HRESULT hSMRes = vboxNetCfgWinSetupMetric(hkey);
+ NET_LUID luid;
+ HRESULT hSMRes = vboxNetCfgWinGetInterfaceLUID(hkey, &luid);
+
+ /* Close the key as soon as possible. See @bugref{7973}. */
+ RegCloseKey (hkey);
+ hkey = (HKEY)INVALID_HANDLE_VALUE;
+
if (FAILED(hSMRes))
{
/*
@@ -3182,10 +3221,29 @@ static HRESULT vboxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pInfPath,
* So we will not break installation process due to this error.
*/
NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface Warning! "
- "vboxNetCfgWinSetupMetric failed, default metric "
- "for new interface will not be set, hr (0x%x)\n", hSMRes));
+ "vboxNetCfgWinGetInterfaceLUID failed, default metric "
+ "for new interface will not be set, hr (0x%x)\n", hSMRes));
+ }
+ else
+ {
+ /*
+ * Set default metric value of interface to fix multicast issue
+ * See @bugref{6379} for details.
+ */
+ hSMRes = vboxNetCfgWinSetupMetric(&luid);
+ if (FAILED(hSMRes))
+ {
+ /*
+ * The setting of Metric is not very important functionality,
+ * So we will not break installation process due to this error.
+ */
+ NonStandardLogFlow(("vboxNetCfgWinCreateHostOnlyNetworkInterface Warning! "
+ "vboxNetCfgWinSetupMetric failed, default metric "
+ "for new interface will not be set, hr (0x%x)\n", hSMRes));
+ }
}
+
#ifndef VBOXNETCFG_DELAYEDRENAME
/*
* We need to query the device name after we have succeeded in querying its
@@ -3378,8 +3436,11 @@ VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWS
/* Give up and report the error. */
if (hrc == E_ABORT)
{
- bstr_t bstrError = bstr_printf("Querying NetCfgInstanceId failed (0x%08X)", ERROR_FILE_NOT_FOUND);
- *pErrMsg = bstrError.Detach();
+ if (pErrMsg)
+ {
+ bstr_t bstrError = bstr_printf("Querying NetCfgInstanceId failed (0x%08X)", ERROR_FILE_NOT_FOUND);
+ *pErrMsg = bstrError.Detach();
+ }
hrc = E_FAIL;
}
}
@@ -3500,21 +3561,16 @@ HRESULT vboxNetCfgWinGetInterfaceLUID(IN HKEY hKey, OUT NET_LUID* pLUID)
}
-HRESULT vboxNetCfgWinSetupMetric(IN HKEY hKey)
+HRESULT vboxNetCfgWinSetupMetric(IN NET_LUID* pLuid)
{
HINSTANCE hModule = NULL;
HRESULT rc = vboxLoadIpHelpFunctions(hModule);
if (SUCCEEDED(rc))
{
- NET_LUID luid;
- rc = vboxNetCfgWinGetInterfaceLUID(hKey, &luid);
+ int loopbackMetric;
+ rc = vboxNetCfgWinGetLoopbackMetric(&loopbackMetric);
if (SUCCEEDED(rc))
- {
- int loopbackMetric;
- rc = vboxNetCfgWinGetLoopbackMetric(&loopbackMetric);
- if (SUCCEEDED(rc))
- rc = vboxNetCfgWinSetInterfaceMetric(&luid, loopbackMetric - 1);
- }
+ rc = vboxNetCfgWinSetInterfaceMetric(pLuid, loopbackMetric - 1);
}
g_pfnInitializeIpInterfaceEntry = NULL;
diff --git a/src/VBox/HostServices/GuestProperties/service.cpp b/src/VBox/HostServices/GuestProperties/service.cpp
index 0e123c7..e8e7cf6 100644
--- a/src/VBox/HostServices/GuestProperties/service.cpp
+++ b/src/VBox/HostServices/GuestProperties/service.cpp
@@ -1582,6 +1582,18 @@ int Service::initialize()
return rc;
}
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK, Destroys Property.}
+ */
+static DECLCALLBACK(int) destroyProperty(PRTSTRSPACECORE pStr, void *pvUser)
+{
+ RT_NOREF(pvUser);
+ Property *pProp = RT_FROM_MEMBER(pStr, struct Property, mStrCore);
+ delete pProp;
+ return 0;
+}
+
#endif
int Service::uninit()
@@ -1600,6 +1612,8 @@ int Service::uninit()
AssertRC(rc);
mhReqQNotifyHost = NIL_RTREQQUEUE;
mhThreadNotifyHost = NIL_RTTHREAD;
+ RTStrSpaceDestroy(&mhProperties, destroyProperty, NULL);
+ mhProperties = NULL;
}
#endif
diff --git a/src/VBox/HostServices/SharedFolders/vbsfpath.cpp b/src/VBox/HostServices/SharedFolders/vbsfpath.cpp
index 94d867e..97a023b 100644
--- a/src/VBox/HostServices/SharedFolders/vbsfpath.cpp
+++ b/src/VBox/HostServices/SharedFolders/vbsfpath.cpp
@@ -362,80 +362,6 @@ static int vbsfNormalizeStringDarwin(const PRTUTF16 pwszSrc, uint32_t cwcSrc, PR
#endif
-/**
- * Check the given UTF-8 path for root escapes.
- *
- * Verify that the path is within the root directory of the mapping. Count '..'
- * and other path components and check that we do not go over the root.
- *
- * @returns VBox status code.
- * @retval VINF_SUCCESS
- * @retval VERR_INVALID_NAME
- *
- * @param pszPath The (UTF-8) path to check. Slashes has been convert
- * to host slashes by this time.
- *
- * @remarks This function assumes that the path will be appended to the root
- * directory of the shared folder mapping. Keep that in mind when
- * checking absolute paths!
- */
-static int vbsfPathCheckRootEscape(const char *pszPath)
-{
- /*
- * Walk the path, component by component and check for escapes.
- */
-
- int cComponents = 0; /* How many normal path components. */
- int cParentDirs = 0; /* How many '..' components. */
-
- for (;;)
- {
- char ch;
-
- /* Skip leading path delimiters. */
- do
- ch = *pszPath++;
- while (RTPATH_IS_SLASH(ch));
- if (ch == '\0')
- return VINF_SUCCESS;
-
- /* Check if that is a dot component. */
- int cDots = 0;
- while (ch == '.')
- {
- cDots++;
- ch = *pszPath++;
- }
-
- if ( cDots >= 1
- && (ch == '\0' || RTPATH_IS_SLASH(ch)) )
- {
- if (cDots >= 2) /* Consider all multidots sequences as a 'parent dir'. */
- {
- cParentDirs++;
-
- /* Escaping? */
- if (cParentDirs > cComponents)
- return VERR_INVALID_NAME;
- }
- /* else: Single dot, nothing changes. */
- }
- else
- {
- /* Not a dot component, skip to the end of it. */
- while (ch != '\0' && !RTPATH_IS_SLASH(ch))
- ch = *pszPath++;
- cComponents++;
- }
- Assert(cComponents >= cParentDirs);
-
- /* The end? */
- Assert(ch == '\0' || RTPATH_IS_SLASH(ch));
- if (ch == '\0')
- return VINF_SUCCESS;
- }
-}
-
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
/* See MSDN "Naming Files, Paths, and Namespaces".
* '<', '>' and '"' are allowed as possible wildcards (see ANSI_DOS_STAR, etc in ntifs.h)
@@ -608,112 +534,130 @@ int vbsfPathGuestToHost(SHFLCLIENTDATA *pClient, SHFLROOT hRoot,
/*
* Allocate enough memory to build the host full path from the root and the relative path.
*/
- uint32_t cbFullPathAlloc = cbRootLen + 1 + cbGuestPath + 1; /* root + possible_slash + relative + 0 */
+ const uint32_t cbFullPathAlloc = cbRootLen + 1 + cbGuestPath + 1; /* root + possible_slash + relative + 0 */
pszFullPath = (char *)RTMemAlloc(cbFullPathAlloc);
if (RT_LIKELY(pszFullPath != NULL))
{
- /* Copy the root. */
- memcpy(pszFullPath, pszRoot, cbRootLen);
- if (!RTPATH_IS_SLASH(pszFullPath[cbRootLen - 1]))
+ /* Buffer for the verified guest path. */
+ char *pchVerifiedPath = (char *)RTMemAlloc(cbGuestPath + 1);
+ if (RT_LIKELY(pchVerifiedPath != NULL))
{
- pszFullPath[cbRootLen++] = RTPATH_SLASH;
- }
+ /* Init the pointer for the guest relative path. */
+ uint32_t cbSrc = cbGuestPath;
+ const char *pchSrc = pchGuestPath;
- /* Init the pointer for the relative path. */
- char *pchDst = &pszFullPath[cbRootLen];
-
- uint32_t cbSrc = cbGuestPath;
- const char *pchSrc = pchGuestPath;
-
- /* Strip leading delimiters from the path the guest specified. */
- while ( cbSrc > 0
- && *pchSrc == pClient->PathDelimiter)
- {
- ++pchSrc;
- --cbSrc;
- }
+ /* Strip leading delimiters from the path the guest specified. */
+ while ( cbSrc > 0
+ && *pchSrc == pClient->PathDelimiter)
+ {
+ ++pchSrc;
+ --cbSrc;
+ }
- /*
- * Iterate the guest path components, verify each of them
- * and append to the host full path replacing delimiters with host slash.
- */
- bool fLastComponentHasWildcard = false;
- for (; cbSrc > 0; --cbSrc, ++pchSrc)
- {
- if (RT_LIKELY(*pchSrc != pClient->PathDelimiter))
+ /*
+ * Iterate the guest path components, verify each of them replacing delimiters with the host slash.
+ */
+ char *pchDst = pchVerifiedPath;
+ bool fLastComponentHasWildcard = false;
+ for (; cbSrc > 0; --cbSrc, ++pchSrc)
{
- if (RT_LIKELY(vbsfPathIsValidNameChar(*pchSrc)))
+ if (RT_LIKELY(*pchSrc != pClient->PathDelimiter))
{
- if (pfu32PathFlags && vbsfPathIsWildcardChar(*pchSrc))
+ if (RT_LIKELY(vbsfPathIsValidNameChar(*pchSrc)))
{
- fLastComponentHasWildcard = true;
- }
+ if (pfu32PathFlags && vbsfPathIsWildcardChar(*pchSrc))
+ {
+ fLastComponentHasWildcard = true;
+ }
- *pchDst++ = *pchSrc;
+ *pchDst++ = *pchSrc;
+ }
+ else
+ {
+ rc = VERR_INVALID_NAME;
+ break;
+ }
}
else
{
- rc = VERR_INVALID_NAME;
- break;
- }
- }
- else
- {
- /* Replace with the host slash. */
- *pchDst++ = RTPATH_SLASH;
+ /* Replace with the host slash. */
+ *pchDst++ = RTPATH_SLASH;
- if (pfu32PathFlags && fLastComponentHasWildcard && cbSrc > 1)
- {
- /* Processed component has a wildcard and there are more characters in the path. */
- *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_PREFIX;
+ if (pfu32PathFlags && fLastComponentHasWildcard && cbSrc > 1)
+ {
+ /* Processed component has a wildcard and there are more characters in the path. */
+ *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_PREFIX;
+ }
+ fLastComponentHasWildcard = false;
}
- fLastComponentHasWildcard = false;
- }
- }
-
- if (RT_SUCCESS(rc))
- {
- const size_t cbFullPathLength = pchDst - &pszFullPath[0]; /* As strlen(pszFullPath). */
-
- *pchDst++ = 0;
-
- if (pfu32PathFlags && fLastComponentHasWildcard)
- {
- *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_LAST;
}
- /* Check the appended path for root escapes. */
- if (fu32Options & VBSF_O_PATH_CHECK_ROOT_ESCAPE)
- {
- rc = vbsfPathCheckRootEscape(&pszFullPath[cbRootLen]);
- }
if (RT_SUCCESS(rc))
{
- /*
- * When the host file system is case sensitive and the guest expects
- * a case insensitive fs, then problems can occur.
- */
- if ( vbsfIsHostMappingCaseSensitive(hRoot)
- && !vbsfIsGuestMappingCaseSensitive(hRoot))
- {
- bool fWildCard = RT_BOOL(fu32Options & VBSF_O_PATH_WILDCARD);
- bool fPreserveLastComponent = RT_BOOL(fu32Options & VBSF_O_PATH_PRESERVE_LAST_COMPONENT);
- rc = vbsfCorrectPathCasing(pClient, pszFullPath, cbFullPathLength, fWildCard, fPreserveLastComponent);
- }
+ const size_t cbFullPathLength = pchDst - &pszFullPath[0]; /* As strlen(pszFullPath). */
+ *pchDst++ = 0;
+ /* Construct the full host path removing '.' and '..'. */
+ rc = RTPathAbsEx(pszRoot, pchVerifiedPath, pszFullPath, cbFullPathAlloc);
if (RT_SUCCESS(rc))
{
- LogFunc(("%s\n", pszFullPath));
+ if (pfu32PathFlags && fLastComponentHasWildcard)
+ {
+ *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_LAST;
+ }
- /* Return the full host path. */
- *ppszHostPath = pszFullPath;
+ /* Check if the full path is still within the shared folder. */
+ if (fu32Options & VBSF_O_PATH_CHECK_ROOT_ESCAPE)
+ {
+ if (!RTPathStartsWith(pszFullPath, pszRoot))
+ {
+ rc = VERR_INVALID_NAME;
+ }
+ }
- if (pcbHostPathRoot)
- {
- *pcbHostPathRoot = cbRootLen - 1; /* Must index the path delimiter. */
- }
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * If the host file system is case sensitive and the guest expects
+ * a case insensitive fs, then correct the path components casing.
+ */
+ if ( vbsfIsHostMappingCaseSensitive(hRoot)
+ && !vbsfIsGuestMappingCaseSensitive(hRoot))
+ {
+ const bool fWildCard = RT_BOOL(fu32Options & VBSF_O_PATH_WILDCARD);
+ const bool fPreserveLastComponent = RT_BOOL(fu32Options & VBSF_O_PATH_PRESERVE_LAST_COMPONENT);
+ rc = vbsfCorrectPathCasing(pClient, pszFullPath, cbFullPathLength,
+ fWildCard, fPreserveLastComponent);
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ LogFlowFunc(("%s\n", pszFullPath));
+
+ /* Return the full host path. */
+ *ppszHostPath = pszFullPath;
+
+ if (pcbHostPathRoot)
+ {
+ /* Return the length of the root path without the trailing slash. */
+ *pcbHostPathRoot = RTPATH_IS_SLASH(pszFullPath[cbRootLen - 1]) ?
+ cbRootLen - 1 : /* pszRoot already had the trailing slash. */
+ cbRootLen; /* pszRoot did not have the trailing slash. */
+ }
+ }
+ }
+ }
+ else
+ {
+ LogFunc(("RTPathAbsEx %Rrc\n", rc));
}
}
+
+ RTMemFree(pchVerifiedPath);
+ }
+ else
+ {
+ rc = VERR_NO_MEMORY;
}
}
else
@@ -737,6 +681,7 @@ int vbsfPathGuestToHost(SHFLCLIENTDATA *pClient, SHFLROOT hRoot,
*/
RTMemFree(pszFullPath);
+ LogFunc(("%Rrc\n", rc));
return rc;
}
diff --git a/src/VBox/Installer/common/virtualbox.desktop.in b/src/VBox/Installer/common/virtualbox.desktop.in
index 276cd40..d507a6e 100644
--- a/src/VBox/Installer/common/virtualbox.desktop.in
+++ b/src/VBox/Installer/common/virtualbox.desktop.in
@@ -15,6 +15,7 @@ MimeType=application/x-virtualbox-vbox;application/x-virtualbox-vbox-extpack;app
DocPath=file://@VBOX_DOC_PATH@/UserManual.pdf
Icon=virtualbox
Categories=Emulator;System;
+Actions=Manager;
Comment=Run several virtual systems on a single host computer
Comment[de]=Mehrere virtuelle Maschinen auf einem einzigen Rechner ausführen
Comment[it]=Esegui più macchine virtuali su un singolo computer
@@ -22,3 +23,8 @@ Comment[ko]=가상 머신
Comment[pl]=Uruchamianie wielu systemów wirtualnych na jednym komputerze gospodarza
Comment[ru]=Запуск нескольких виртуальных машин на одном компьютере
Comment[sv]=Kör flera virtuella system på en enda värddator
+
+[Desktop Action Manager]
+Exec=VirtualBox
+Name=Open VM Manager
+Name[de]=VM Manager öffnen
diff --git a/src/VBox/Installer/linux/vboxdrv.sh b/src/VBox/Installer/linux/vboxdrv.sh
index 7fb25d4..4ead614 100755
--- a/src/VBox/Installer/linux/vboxdrv.sh
+++ b/src/VBox/Installer/linux/vboxdrv.sh
@@ -388,7 +388,6 @@ cleanup()
setup()
{
begin_msg "Building VirtualBox kernel modules" console
- cleanup
if ! $BUILDINTMP \
--save-module-symvers /tmp/vboxdrv-Module.symvers \
--module-source "$MODULE_SRC/vboxdrv" \
@@ -472,6 +471,7 @@ setup)
## todo Do we need a udev rule to create /dev/vboxdrv[u] at all? We have
## working fall-back code here anyway, and the "right" code is more complex
## than the fall-back. Unnecessary duplication?
+ stop && cleanup
setup_usb "$GROUP" "$DEVICE_MODE" "$INSTALL_DIR"
setup && start
;;
diff --git a/src/VBox/Installer/win/NLS/en_US.wxl b/src/VBox/Installer/win/NLS/en_US.wxl
index fa3d8e6..df2f23f 100644
--- a/src/VBox/Installer/win/NLS/en_US.wxl
+++ b/src/VBox/Installer/win/NLS/en_US.wxl
@@ -181,7 +181,7 @@ This is default for newer versions of Windows (Vista and newer).</String>
<!---->
- <String Id="FilesInUse_Text">The following applications are using files that need to be updated by this setup. Close these applications and then click &Retry to continue the installation or Cancel to exit it.</String>
+ <String Id="FilesInUse_Text">The following applications are using files that need to be updated by this setup. Close these applications and then click &Retry to continue the installation or Exit to exit it.</String>
<String Id="FilesInUse_Description">Some files that need to be updated are currently in use.</String>
<String Id="FilesInUse_Title">Files in Use</String>
diff --git a/src/VBox/Installer/win/NLS/it_IT.wxl b/src/VBox/Installer/win/NLS/it_IT.wxl
index 5d0b4c5..a5d4b63 100644
--- a/src/VBox/Installer/win/NLS/it_IT.wxl
+++ b/src/VBox/Installer/win/NLS/it_IT.wxl
@@ -138,7 +138,7 @@ This is default for newer versions of Windows (Vista and newer).</String>
<String Id="FatalErrorDlg_Desc">L'installazione di [ProductName] è stata terminata in anticipo a causa di un errore. Il sistema non è stato modificato. Per installare questo programma successivamente, esegui nuovamente l'installazione.</String>
<String Id="FatalErrorDlg_Footer">Fai clic sul pulsante Fine per uscire dalla procedura guidata.</String>
<!---->
- <String Id="FilesInUse_Text">The following applications are using files that need to be updated by this setup. Close these applications and then click &Retry to continue the installation or Cancel to exit it.</String>
+ <String Id="FilesInUse_Text">The following applications are using files that need to be updated by this setup. Close these applications and then click &Retry to continue the installation or Exit to exit it.</String>
<String Id="FilesInUse_Description">Alcuni file che devono essere aggiornati sono attualmente utilizzati.</String>
<String Id="FilesInUse_Title">File in uso</String>
<!---->
diff --git a/src/VBox/Main/Makefile.kmk b/src/VBox/Main/Makefile.kmk
index 451844a..847cf23 100644
--- a/src/VBox/Main/Makefile.kmk
+++ b/src/VBox/Main/Makefile.kmk
@@ -784,14 +784,10 @@ VBoxC_SOURCES = \
$(VBOX_AUTOGEN_EVENT_CPP) \
$(VBOX_XML_SCHEMADEFS_CPP)
-# Audio bits.
-VBoxC_DEFS += \
- $(if $(VBOX_WITH_AUDIO_50), VBOX_WITH_AUDIO_50,)
-
VBoxC_SOURCES += \
- ../Devices/$(VBOX_AUDIO_PATH_SOURCES)/AudioMixBuffer.cpp \
- ../Devices/$(VBOX_AUDIO_PATH_SOURCES)/DrvAudioCommon.cpp \
- $(if $(VBOX_WITH_VRDE_AUDIO),src-client/DrvAudioVRDE$(VBOX_AUDIO_FILE_SUFFIX).cpp,)
+ ../Devices/Audio/AudioMixBuffer.cpp \
+ ../Devices/Audio/DrvAudioCommon.cpp \
+ $(if $(VBOX_WITH_VRDE_AUDIO),src-client/DrvAudioVRDE.cpp,)
VBoxC_SOURCES.win = \
src-client/win/dllmain.cpp \
diff --git a/src/VBox/Main/include/ApplianceImplPrivate.h b/src/VBox/Main/include/ApplianceImplPrivate.h
index 1be6f12..f49dc06 100644
--- a/src/VBox/Main/include/ApplianceImplPrivate.h
+++ b/src/VBox/Main/include/ApplianceImplPrivate.h
@@ -235,6 +235,8 @@ struct Appliance::Data
struct Appliance::XMLStack
{
std::map<Utf8Str, const VirtualSystemDescriptionEntry*> mapDisks;
+ std::list<Utf8Str> mapDiskSequence;
+ std::list<Utf8Str> mapDiskSequenceForOneVM;//temporary keeps all disks attached to one exported VM
std::map<Utf8Str, bool> mapNetworks;
};
diff --git a/src/VBox/Main/include/DrvAudioVRDE.h b/src/VBox/Main/include/DrvAudioVRDE.h
index 3690219..7d31636 100644
--- a/src/VBox/Main/include/DrvAudioVRDE.h
+++ b/src/VBox/Main/include/DrvAudioVRDE.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2014-2016 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/include/DrvAudioVRDE_50.h b/src/VBox/Main/include/DrvAudioVRDE_50.h
deleted file mode 100644
index 6c5e420..0000000
--- a/src/VBox/Main/include/DrvAudioVRDE_50.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* $Id: DrvAudioVRDE_50.h $ */
-/** @file
- * VirtualBox driver interface to VRDE backend.
- */
-
-/*
- * Copyright (C) 2014-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef ____H_DRVAUDIOVRDE
-#define ____H_DRVAUDIOVRDE
-
-#include <VBox/com/ptr.h>
-#include <VBox/RemoteDesktop/VRDE.h>
-#include <VBox/vmm/pdmdrv.h>
-#include <VBox/vmm/pdmifs.h>
-
-class Console;
-
-class AudioVRDE
-{
-
-public:
-
- AudioVRDE(Console *pConsole);
- virtual ~AudioVRDE(void);
-
-public:
-
- static const PDMDRVREG DrvReg;
-
- Console *getParent(void) { return mParent; }
-
-public:
-
- int onVRDEControl(bool fEnable, uint32_t uFlags);
- int onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin);
- int onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData);
- int onVRDEInputEnd(void *pvContext);
- int onVRDEInputIntercept(bool fIntercept);
-
-public:
-
- static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
- static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns);
-
-private:
-
- /** Pointer to the associated VRDE audio driver. */
- struct DRVAUDIOVRDE *mpDrv;
- /** Pointer to parent. */
- Console * const mParent;
-};
-
-#endif /* !____H_DRVAUDIOVRDE */
-
diff --git a/src/VBox/Main/include/DrvAudioVideoRec.h b/src/VBox/Main/include/DrvAudioVideoRec.h
index 7abb5d4..cef1e50 100644
--- a/src/VBox/Main/include/DrvAudioVideoRec.h
+++ b/src/VBox/Main/include/DrvAudioVideoRec.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2014-2016 Oracle Corporation
+ * Copyright (C) 2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Main/include/DrvAudioVideoRec_50.h b/src/VBox/Main/include/DrvAudioVideoRec_50.h
deleted file mode 100644
index 4a4a1a4..0000000
--- a/src/VBox/Main/include/DrvAudioVideoRec_50.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* $Id: DrvAudioVideoRec_50.h $ */
-/** @file
- * VirtualBox driver interface to video recording backend.
- */
-
-/*
- * Copyright (C) 2014 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-#ifndef ____H_DRVAUDIOVIDEOREC
-#define ____H_DRVAUDIOVIDEOREC
-
-#include <VBox/com/ptr.h>
-#include <VBox/vmm/pdmdrv.h>
-#include <VBox/vmm/pdmifs.h>
-
-class Console;
-
-class AudioVideoRec
-{
-
-public:
-
- AudioVideoRec(Console *pConsole);
- virtual ~AudioVideoRec(void);
-
-public:
-
- static const PDMDRVREG DrvReg;
-
- Console *getParent(void) { return mParent; }
-
-public:
-
- int handleVideoRecSvrCmdAudioInputIntercept(bool fIntercept);
- int handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels, int cBits, bool fUnsigned);
- int handleVideoRecSvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData);
- int handleVideoRecSvrCmdAudioInputEventEnd(void *pvContext);
-
-public:
-
- static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
- static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns);
-
-private:
-
- /** Pointer to the associated video recording audio driver. */
- struct DRVAUDIOVIDEOREC *mpDrv;
- /** Pointer to parent. */
- Console * const mParent;
-};
-
-#endif /* !____H_DRVAUDIOVIDEOREC */
-
diff --git a/src/VBox/Main/include/USBProxyBackend.h b/src/VBox/Main/include/USBProxyBackend.h
index 62acbcc..dd81f86 100644
--- a/src/VBox/Main/include/USBProxyBackend.h
+++ b/src/VBox/Main/include/USBProxyBackend.h
@@ -47,7 +47,8 @@ public:
void FinalRelease();
// public initializer/uninitializer for internal purposes only
- virtual int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress);
+ virtual int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings);
virtual void uninit();
bool isActive(void);
@@ -146,7 +147,8 @@ class USBProxyBackendDarwin : public USBProxyBackend
public:
DECLARE_EMPTY_CTOR_DTOR (USBProxyBackendDarwin)
- int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress);
+ int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings);
void uninit();
virtual void *insertFilter(PCUSBFILTER aFilter);
@@ -195,7 +197,8 @@ class USBProxyBackendLinux: public USBProxyBackend
public:
DECLARE_EMPTY_CTOR_DTOR (USBProxyBackendLinux)
- int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress);
+ int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings);
void uninit();
virtual int captureDevice(HostUSBDevice *aDevice);
@@ -286,7 +289,8 @@ class USBProxyBackendSolaris : public USBProxyBackend
public:
DECLARE_EMPTY_CTOR_DTOR (USBProxyBackendSolaris)
- int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress);
+ int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings);
void uninit();
virtual void *insertFilter (PCUSBFILTER aFilter);
@@ -321,7 +325,8 @@ class USBProxyBackendWindows : public USBProxyBackend
public:
DECLARE_EMPTY_CTOR_DTOR (USBProxyBackendWindows)
- int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress);
+ int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings);
void uninit();
virtual void *insertFilter (PCUSBFILTER aFilter);
@@ -352,7 +357,8 @@ class USBProxyBackendFreeBSD : public USBProxyBackend
public:
DECLARE_EMPTY_CTOR_DTOR (USBProxyBackendFreeBSD)
- int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress);
+ int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings);
void uninit();
virtual int captureDevice(HostUSBDevice *aDevice);
@@ -403,7 +409,8 @@ class USBProxyBackendUsbIp: public USBProxyBackend
public:
DECLARE_EMPTY_CTOR_DTOR (USBProxyBackendUsbIp)
- int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress);
+ int init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings);
void uninit();
virtual int captureDevice(HostUSBDevice *aDevice);
diff --git a/src/VBox/Main/include/USBProxyService.h b/src/VBox/Main/include/USBProxyService.h
index 99ec41b..6450ebb 100644
--- a/src/VBox/Main/include/USBProxyService.h
+++ b/src/VBox/Main/include/USBProxyService.h
@@ -105,7 +105,7 @@ protected:
HRESULT createUSBDeviceSource(const com::Utf8Str &aBackend, const com::Utf8Str &aId,
const com::Utf8Str &aAddress, const std::vector<com::Utf8Str> &aPropertyNames,
- const std::vector<com::Utf8Str> &aPropertyValues);
+ const std::vector<com::Utf8Str> &aPropertyValues, bool fLoadingSettings);
private:
diff --git a/src/VBox/Main/src-client/ConsoleImpl2.cpp b/src/VBox/Main/src-client/ConsoleImpl2.cpp
index 041554e..f7f281e 100644
--- a/src/VBox/Main/src-client/ConsoleImpl2.cpp
+++ b/src/VBox/Main/src-client/ConsoleImpl2.cpp
@@ -1684,8 +1684,6 @@ int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
InsertConfigNode(pDev, "0", &pInst);
InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
InsertConfigNode(pInst, "Config", &pBiosCfg);
- InsertConfigInteger(pBiosCfg, "RamSize", cbRam);
- InsertConfigInteger(pBiosCfg, "RamHoleSize", cbRamHole);
InsertConfigInteger(pBiosCfg, "NumCPUs", cCpus);
InsertConfigString(pBiosCfg, "HardDiskDevice", "piix3ide");
InsertConfigString(pBiosCfg, "FloppyDevice", "i82078");
@@ -1788,8 +1786,6 @@ int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
InsertConfigNode(pDev, "0", &pInst);
InsertConfigInteger(pInst, "Trusted", 1); /* boolean */
InsertConfigNode(pInst, "Config", &pCfg);
- InsertConfigInteger(pCfg, "RamSize", cbRam);
- InsertConfigInteger(pCfg, "RamHoleSize", cbRamHole);
InsertConfigInteger(pCfg, "NumCPUs", cCpus);
InsertConfigString(pCfg, "EfiRom", efiRomFile);
InsertConfigString(pCfg, "BootArgs", bootArgs);
@@ -2757,7 +2753,6 @@ int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
Bstr hwVersion;
hrc = pMachine->COMGETTER(HardwareVersion)(hwVersion.asOutParam()); H();
- InsertConfigInteger(pCfg, "RamSize", cbRam);
if (hwVersion.compare(Bstr("1").raw()) == 0) /* <= 2.0.x */
InsertConfigInteger(pCfg, "HeapEnabled", 0);
Bstr snapshotFolder;
@@ -3147,8 +3142,6 @@ int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
InsertConfigNode(pInst, "Config", &pCfg);
hrc = pBusMgr->assignPCIDevice("acpi", pInst); H();
- InsertConfigInteger(pCfg, "RamSize", cbRam);
- InsertConfigInteger(pCfg, "RamHoleSize", cbRamHole);
InsertConfigInteger(pCfg, "NumCPUs", cCpus);
InsertConfigInteger(pCfg, "IOAPIC", fIOAPIC);
@@ -3176,6 +3169,10 @@ int Console::i_configConstructorInner(PUVM pUVM, PVM pVM, AutoWriteLock *pAlock)
{
InsertConfigInteger(pCfg, "McfgBase", uMcfgBase);
InsertConfigInteger(pCfg, "McfgLength", cbMcfgLength);
+ /* 64-bit prefetch window root resource:
+ * Only for ICH9 and if PAE or Long Mode is enabled */
+ if (fEnablePAE || fIsGuest64Bit)
+ InsertConfigInteger(pCfg, "PciPref64Enabled", 1);
}
InsertConfigInteger(pCfg, "HostBusPciAddress", uHbcPCIAddress);
InsertConfigInteger(pCfg, "ShowCpu", fShowCpu);
diff --git a/src/VBox/Main/src-client/DrvAudioVRDE.cpp b/src/VBox/Main/src-client/DrvAudioVRDE.cpp
index bdf6cd9..c8c6c71 100644
--- a/src/VBox/Main/src-client/DrvAudioVRDE.cpp
+++ b/src/VBox/Main/src-client/DrvAudioVRDE.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2013-2016 Oracle Corporation
+ * Copyright (C) 2013-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -51,22 +51,21 @@ typedef struct DRVAUDIOVRDE
{
/** Pointer to audio VRDE object. */
AudioVRDE *pAudioVRDE;
- /** Pointer to the driver instance structure. */
PPDMDRVINS pDrvIns;
- /** Pointer to host audio interface. */
+ /** Pointer to the driver instance structure. */
PDMIHOSTAUDIO IHostAudio;
/** Pointer to the VRDP's console object. */
ConsoleVRDPServer *pConsoleVRDPServer;
/** Pointer to the DrvAudio port interface that is above us. */
PPDMIAUDIOCONNECTOR pDrvAudio;
+ /** Whether this driver is enabled or not. */
+ bool fEnabled;
} DRVAUDIOVRDE, *PDRVAUDIOVRDE;
typedef struct VRDESTREAMIN
{
- /** Note: Always must come first! */
- PDMAUDIOSTREAM Stream;
- /** The PCM properties of this stream. */
- PDMAUDIOPCMPROPS Props;
+ /** Associated host input stream. */
+ PDMAUDIOHSTSTRMIN HstStrmIn;
/** Number of samples captured asynchronously in the
* onVRDEInputXXX callbacks. */
uint32_t cSamplesCaptured;
@@ -76,146 +75,92 @@ typedef struct VRDESTREAMIN
typedef struct VRDESTREAMOUT
{
- /** Note: Always must come first! */
- PDMAUDIOSTREAM Stream;
- /** The PCM properties of this stream. */
- PDMAUDIOPCMPROPS Props;
- uint64_t old_ticks;
- uint64_t cSamplesSentPerSec;
+ /** Associated host output stream. */
+ PDMAUDIOHSTSTRMOUT HstStrmOut;
+ uint64_t old_ticks;
+ uint64_t cSamplesSentPerSec;
} VRDESTREAMOUT, *PVRDESTREAMOUT;
-static int vrdeCreateStreamIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
-
- PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pStream;
- AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
-
- int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pVRDEStrmIn->Props);
- if (RT_SUCCESS(rc))
- {
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = _4K; /** @todo Make this configurable. */
- }
+ RT_NOREF(pInterface);
+ LogFlowFuncEnter();
- LogFlowFuncLeaveRC(VINF_SUCCESS);
return VINF_SUCCESS;
}
-
-static int vrdeCreateStreamOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
+static DECLCALLBACK(int) drvAudioVRDEInitIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
+ PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
+ RT_NOREF(pCfgAcq, enmRecSource);
+ PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+ AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
- PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pStream;
- AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
+ PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
+ AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
- int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pVRDEStrmOut->Props);
- if (RT_SUCCESS(rc))
- {
- if (pCfgAcq)
- pCfgAcq->cSampleBufferSize = _4K; /** @todo Make this configurable. */
- }
+ if (pcSamples)
+ *pcSamples = _4K; /** @todo Make this configurable. */
- LogFlowFuncLeaveRC(VINF_SUCCESS);
- return VINF_SUCCESS;
+ return DrvAudioStreamCfgToProps(pCfgReq, &pVRDEStrmIn->HstStrmIn.Props);
}
-
-static int vrdeControlStreamOut(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(int) drvAudioVRDEInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, uint32_t *pcSamples)
{
- RT_NOREF(enmStreamCmd);
+ RT_NOREF(pCfgAcq);
PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
- PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pStream;
+ PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-
- AudioMixBufReset(&pStream->MixBuf);
+ if (pcSamples)
+ *pcSamples = _4K; /** @todo Make this configurable. */
- return VINF_SUCCESS;
+ return DrvAudioStreamCfgToProps(pCfgReq, &pVRDEStrmOut->HstStrmOut.Props);
}
-
-static int vrdeControlStreamIn(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
+static DECLCALLBACK(bool) drvAudioVRDEIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
{
PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pStream;
- AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
-
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
+ AssertPtrReturn(pDrv, false);
- if (!pDrv->pConsoleVRDPServer)
- return VINF_SUCCESS;
+ NOREF(enmDir);
- AudioMixBufReset(&pStream->MixBuf);
+ if (!pDrv->fEnabled)
+ return false;
- /* Initialize only if not already done. */
- int rc;
- if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
- {
- rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, AudioMixBufSize(&pStream->MixBuf),
- pVRDEStrmIn->Props.uHz,
- pVRDEStrmIn->Props.cChannels, pVRDEStrmIn->Props.cBits);
- if (rc == VERR_NOT_SUPPORTED)
- {
- LogFlowFunc(("No RDP client connected, so no input recording supported\n"));
- rc = VINF_SUCCESS;
- }
- }
- else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
- {
- pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
- rc = VINF_SUCCESS;
- }
- else
- rc = VERR_INVALID_PARAMETER;
-
- return rc;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
- */
-static DECLCALLBACK(int) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
-{
- RT_NOREF(pInterface);
- LogFlowFuncEnter();
-
- return VINF_SUCCESS;
+ return true;
}
-
/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
+ * {FIXME - Missing brief description - FIXME}
+ *
+ * Transfers audio input formerly sent by a connected RDP client / VRDE backend
+ * (using the onVRDEInputXXX methods) over to the VRDE host (VM). The audio device
+ * emulation then will read and send the data to the guest.
+ *
+ * @return IPRT status code.
+ * @param pInterface
+ * @param pHstStrmIn
+ * @param pcSamplesCaptured
*/
-static DECLCALLBACK(int) drvAudioVRDEStreamCapture(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
+static DECLCALLBACK(int) drvAudioVRDECaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ uint32_t *pcSamplesCaptured)
{
- RT_NOREF2(pvBuf, cbBuf);
-
AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbRead is optional. */
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcSamplesCaptured, VERR_INVALID_POINTER);
- PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pStream;
+ PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+ AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
+
+ PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
+ AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
/** @todo Use CritSect! */
@@ -224,7 +169,7 @@ static DECLCALLBACK(int) drvAudioVRDEStreamCapture(PPDMIHOSTAUDIO pInterface,
uint32_t cProcessed = 0;
if (pVRDEStrmIn->cSamplesCaptured)
{
- rc = AudioMixBufMixToParent(&pVRDEStrmIn->Stream.MixBuf, pVRDEStrmIn->cSamplesCaptured,
+ rc = AudioMixBufMixToParent(&pVRDEStrmIn->HstStrmIn.MixBuf, pVRDEStrmIn->cSamplesCaptured,
&cProcessed);
}
else
@@ -232,59 +177,65 @@ static DECLCALLBACK(int) drvAudioVRDEStreamCapture(PPDMIHOSTAUDIO pInterface,
if (RT_SUCCESS(rc))
{
+ *pcSamplesCaptured = cProcessed;
+
Assert(pVRDEStrmIn->cSamplesCaptured >= cProcessed);
pVRDEStrmIn->cSamplesCaptured -= cProcessed;
-
- if (pcbRead)
- *pcbRead = cProcessed;
}
LogFlowFunc(("cSamplesCaptured=%RU32, cProcessed=%RU32 rc=%Rrc\n", pVRDEStrmIn->cSamplesCaptured, cProcessed, rc));
return rc;
}
-
/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
+ * Transfers VM audio output to remote client.
+ *
+ * Transfers VM audio output over to the VRDE instance for playing remotely
+ * on the client.
+ *
+ * @return IPRT status code.
+ * @param pInterface
+ * @param pHstStrmOut
+ * @param pcSamplesPlayed
*/
-static DECLCALLBACK(int) drvAudioVRDEStreamPlay(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
+static DECLCALLBACK(int) drvAudioVRDEPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ uint32_t *pcSamplesPlayed)
{
- RT_NOREF2(pvBuf, cbBuf);
-
AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- /* pcbWritten is optional. */
+ AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
+ /* pcSamplesPlayed is optional. */
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pStream;
+ PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+ AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
- uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
+ PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
+ AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
+ uint32_t live = AudioMixBufAvail(&pHstStrmOut->MixBuf);
uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
uint64_t ticks = now - pVRDEStrmOut->old_ticks;
uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
/* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
- uint32_t cSamplesPlayed = (int)((2 * ticks * pVRDEStrmOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
+ uint32_t cSamplesPlayed = (int)((2 * ticks * pHstStrmOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
/* Don't play more than available. */
- if (cSamplesPlayed > cLive)
- cSamplesPlayed = cLive;
+ if (cSamplesPlayed > live)
+ cSamplesPlayed = live;
/* Remember when samples were consumed. */
pVRDEStrmOut->old_ticks = now;
- VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pVRDEStrmOut->Props.uHz,
- pVRDEStrmOut->Props.cChannels,
- pVRDEStrmOut->Props.cBits,
- pVRDEStrmOut->Props.fSigned);
+ VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHstStrmOut->Props.uHz,
+ pHstStrmOut->Props.cChannels,
+ pHstStrmOut->Props.cBits,
+ pHstStrmOut->Props.fSigned);
int cSamplesToSend = cSamplesPlayed;
LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, enmFormat=%ld, cSamplesToSend=%RU32\n",
- pVRDEStrmOut->Props.uHz, pVRDEStrmOut->Props.cChannels,
- pVRDEStrmOut->Props.cBits, pVRDEStrmOut->Props.fSigned,
+ pHstStrmOut->Props.uHz, pHstStrmOut->Props.cChannels,
+ pHstStrmOut->Props.cBits, pHstStrmOut->Props.fSigned,
format, cSamplesToSend));
/*
@@ -294,7 +245,7 @@ static DECLCALLBACK(int) drvAudioVRDEStreamPlay(PPDMIHOSTAUDIO pInterface,
PPDMAUDIOSAMPLE pSamples;
uint32_t cRead;
- int rc = AudioMixBufAcquire(&pStream->MixBuf, cSamplesToSend,
+ int rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend,
&pSamples, &cRead);
if ( RT_SUCCESS(rc)
&& cRead)
@@ -304,7 +255,7 @@ static DECLCALLBACK(int) drvAudioVRDEStreamPlay(PPDMIHOSTAUDIO pInterface,
if (rc == VINF_TRY_AGAIN)
{
- rc = AudioMixBufAcquire(&pStream->MixBuf, cSamplesToSend - cRead,
+ rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend - cRead,
&pSamples, &cRead);
if (RT_SUCCESS(rc))
pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
@@ -313,23 +264,22 @@ static DECLCALLBACK(int) drvAudioVRDEStreamPlay(PPDMIHOSTAUDIO pInterface,
}
}
- AudioMixBufFinish(&pStream->MixBuf, cSamplesToSend);
+ AudioMixBufFinish(&pHstStrmOut->MixBuf, cSamplesToSend);
/*
* Always report back all samples acquired, regardless of whether the
* VRDP server actually did process those.
*/
- if (pcbWritten)
- *pcbWritten = cReadTotal;
+ if (pcSamplesPlayed)
+ *pcSamplesPlayed = cReadTotal;
LogFlowFunc(("cReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));
return rc;
}
-
-static int vrdeDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvAudioVRDEFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
- RT_NOREF(pStream);
+ RT_NOREF(pHstStrmIn);
PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
@@ -339,149 +289,94 @@ static int vrdeDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStrea
return VINF_SUCCESS;
}
-
-static int vrdeDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvAudioVRDEFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
- RT_NOREF(pStream);
+ RT_NOREF(pHstStrmOut);
PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
- */
-static DECLCALLBACK(int) drvAudioVRDEGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
-{
- NOREF(pInterface);
- AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
-
- pBackendCfg->cbStreamOut = sizeof(VRDESTREAMOUT);
- pBackendCfg->cbStreamIn = sizeof(VRDESTREAMIN);
- pBackendCfg->cMaxStreamsIn = UINT32_MAX;
- pBackendCfg->cMaxStreamsOut = UINT32_MAX;
- pBackendCfg->cSources = 1;
- pBackendCfg->cSinks = 1;
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
- */
-static DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
+static DECLCALLBACK(int) drvAudioVRDEControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
+ RT_NOREF(enmStreamCmd);
PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturnVoid(pDrv);
-
- if (pDrv->pConsoleVRDPServer)
- pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
-}
-
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVRDEGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- RT_NOREF(enmDir);
- AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
+ AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
- return PDMAUDIOBACKENDSTS_RUNNING;
-}
+ PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
+ AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
+ LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
- */
-static DECLCALLBACK(int) drvAudioVRDEStreamCreate(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
+ AudioMixBufReset(&pHstStrmOut->MixBuf);
- int rc;
- if (pCfgReq->enmDir == PDMAUDIODIR_IN)
- rc = vrdeCreateStreamIn(pInterface, pStream, pCfgReq, pCfgAcq);
- else
- rc = vrdeCreateStreamOut(pInterface, pStream, pCfgReq, pCfgAcq);
-
- return rc;
+ return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
- */
-static DECLCALLBACK(int) drvAudioVRDEStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvAudioVRDEControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
+ PDMAUDIOSTREAMCMD enmStreamCmd)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+ AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
- int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = vrdeDestroyStreamIn(pInterface, pStream);
- else
- rc = vrdeDestroyStreamOut(pInterface, pStream);
+ PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
+ AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
- return rc;
-}
+ PPDMAUDIOHSTSTRMIN pThisStrmIn = &pVRDEStrmIn->HstStrmIn;
+ LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
- */
-static DECLCALLBACK(int) drvAudioVRDEStreamControl(PPDMIHOSTAUDIO pInterface,
- PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ if (!pDrv->pConsoleVRDPServer)
+ return VINF_SUCCESS;
- Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
+ AudioMixBufReset(&pThisStrmIn->MixBuf);
+ /* Initialize only if not already done. */
int rc;
- if (pStream->enmDir == PDMAUDIODIR_IN)
- rc = vrdeControlStreamIn(pInterface, pStream, enmStreamCmd);
+ if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
+ {
+ rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, AudioMixBufSize(&pThisStrmIn->MixBuf),
+ pThisStrmIn->Props.uHz,
+ pThisStrmIn->Props.cChannels, pThisStrmIn->Props.cBits);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ LogFlowFunc(("No RDP client connected, so no input recording supported\n"));
+ rc = VINF_SUCCESS;
+ }
+ }
+ else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
+ {
+ pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
+ rc = VINF_SUCCESS;
+ }
else
- rc = vrdeControlStreamOut(pInterface, pStream, enmStreamCmd);
+ rc = VERR_INVALID_PARAMETER;
return rc;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
- */
-static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioVRDEStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(int) drvAudioVRDEGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
{
- NOREF(pInterface);
- NOREF(pStream);
+ RT_NOREF(pInterface);
+ pCfg->cbStreamOut = sizeof(VRDESTREAMOUT);
+ pCfg->cbStreamIn = sizeof(VRDESTREAMIN);
+ pCfg->cMaxHstStrmsOut = 1;
+ pCfg->cMaxHstStrmsIn = 2; /* Microphone in + Line in. */
- return ( PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
- | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE);
+ return VINF_SUCCESS;
}
-
-/**
- * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
- */
-static DECLCALLBACK(int) drvAudioVRDEStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
+static DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
-
- LogFlowFuncEnter();
+ PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
+ AssertPtrReturnVoid(pDrv);
- /* Nothing to do here for VRDE. */
- return VINF_SUCCESS;
+ if (pDrv->pConsoleVRDPServer)
+ pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
}
-
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
@@ -495,14 +390,12 @@ static DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, con
return NULL;
}
-
AudioVRDE::AudioVRDE(Console *pConsole)
: mpDrv(NULL),
mParent(pConsole)
{
}
-
AudioVRDE::~AudioVRDE(void)
{
if (mpDrv)
@@ -512,19 +405,19 @@ AudioVRDE::~AudioVRDE(void)
}
}
-
int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
{
- RT_NOREF(fEnable, uFlags);
+ RT_NOREF(uFlags);
LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
if (mpDrv == NULL)
return VERR_INVALID_STATE;
+ mpDrv->fEnabled = fEnable;
+
return VINF_SUCCESS; /* Never veto. */
}
-
/**
* Marks the beginning of sending captured audio data from a connected
* RDP client.
@@ -542,32 +435,30 @@ int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBeg
PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
+#ifdef LOG_ENABLED
VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt;
-
- int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt); NOREF(iSampleHz);
- int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt); NOREF(cChannels);
- int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt); NOREF(cBits);
- bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt); NOREF(fUnsigned);
-
+ int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt);
+ int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt);
+ int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt);
+ bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt);
LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned));
-
+#endif
return VINF_SUCCESS;
}
-
int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
{
PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
- PPDMAUDIOSTREAM pStream = &pVRDEStrmIn->Stream;
- AssertPtrReturn(pStream, VERR_INVALID_POINTER);
+ PPDMAUDIOHSTSTRMIN pHstStrmIn = &pVRDEStrmIn->HstStrmIn;
+ AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
/** @todo Use CritSect! */
uint32_t cWritten;
- int rc = AudioMixBufWriteCirc(&pStream->MixBuf, pvData, cbData, &cWritten);
+ int rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf, pvData, cbData, &cWritten);
if (RT_SUCCESS(rc))
pVRDEStrmIn->cSamplesCaptured += cWritten;
@@ -576,7 +467,6 @@ int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbD
return rc;
}
-
int AudioVRDE::onVRDEInputEnd(void *pvContext)
{
NOREF(pvContext);
@@ -584,14 +474,12 @@ int AudioVRDE::onVRDEInputEnd(void *pvContext)
return VINF_SUCCESS;
}
-
int AudioVRDE::onVRDEInputIntercept(bool fEnabled)
{
RT_NOREF(fEnabled);
return VINF_SUCCESS; /* Never veto. */
}
-
/**
* Construct a VRDE audio driver instance.
*
@@ -601,10 +489,8 @@ int AudioVRDE::onVRDEInputIntercept(bool fEnabled)
DECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
RT_NOREF(fFlags);
-
PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
-
AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
@@ -624,6 +510,9 @@ DECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, ui
/* IHostAudio */
PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVRDE);
+ /* Init defaults. */
+ pThis->fEnabled = false;
+
/*
* Get the ConsoleVRDPServer object pointer.
*/
diff --git a/src/VBox/Main/src-client/DrvAudioVRDE_50.cpp b/src/VBox/Main/src-client/DrvAudioVRDE_50.cpp
deleted file mode 100644
index 201f8dd..0000000
--- a/src/VBox/Main/src-client/DrvAudioVRDE_50.cpp
+++ /dev/null
@@ -1,618 +0,0 @@
-/* $Id: DrvAudioVRDE_50.cpp $ */
-/** @file
- * VRDE audio backend for Main.
- */
-
-/*
- * Copyright (C) 2013-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-
-
-/*********************************************************************************************************************************
-* Header Files *
-*********************************************************************************************************************************/
-#define LOG_GROUP LOG_GROUP_DRV_VRDE_AUDIO
-#include <VBox/log.h>
-#include "DrvAudioVRDE_50.h"
-#include "ConsoleImpl.h"
-#include "ConsoleVRDPServer.h"
-
-#include "Logging.h"
-
-#include "../../Devices/Audio_50/DrvAudio.h"
-#include "../../Devices/Audio_50/AudioMixBuffer.h"
-
-#include <iprt/mem.h>
-#include <iprt/cdefs.h>
-#include <iprt/circbuf.h>
-
-#include <VBox/vmm/pdmaudioifs.h>
-#include <VBox/vmm/pdmdrv.h>
-#include <VBox/RemoteDesktop/VRDE.h>
-#include <VBox/vmm/cfgm.h>
-#include <VBox/err.h>
-
-
-/*********************************************************************************************************************************
-* Structures and Typedefs *
-*********************************************************************************************************************************/
-/**
- * Audio VRDE driver instance data.
- */
-typedef struct DRVAUDIOVRDE
-{
- /** Pointer to audio VRDE object. */
- AudioVRDE *pAudioVRDE;
- PPDMDRVINS pDrvIns;
- /** Pointer to the driver instance structure. */
- PDMIHOSTAUDIO IHostAudio;
- /** Pointer to the VRDP's console object. */
- ConsoleVRDPServer *pConsoleVRDPServer;
- /** Pointer to the DrvAudio port interface that is above us. */
- PPDMIAUDIOCONNECTOR pDrvAudio;
- /** Whether this driver is enabled or not. */
- bool fEnabled;
-} DRVAUDIOVRDE, *PDRVAUDIOVRDE;
-
-typedef struct VRDESTREAMIN
-{
- /** Associated host input stream. */
- PDMAUDIOHSTSTRMIN HstStrmIn;
- /** Number of samples captured asynchronously in the
- * onVRDEInputXXX callbacks. */
- uint32_t cSamplesCaptured;
- /** Critical section. */
- RTCRITSECT CritSect;
-} VRDESTREAMIN, *PVRDESTREAMIN;
-
-typedef struct VRDESTREAMOUT
-{
- /** Associated host output stream. */
- PDMAUDIOHSTSTRMOUT HstStrmOut;
- uint64_t old_ticks;
- uint64_t cSamplesSentPerSec;
-} VRDESTREAMOUT, *PVRDESTREAMOUT;
-
-
-
-static DECLCALLBACK(int) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
-{
- RT_NOREF(pInterface);
- LogFlowFuncEnter();
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVRDEInitIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq,
- PDMAUDIORECSOURCE enmRecSource, uint32_t *pcSamples)
-{
- RT_NOREF(pCfgAcq, enmRecSource);
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
- AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
-
- if (pcSamples)
- *pcSamples = _4K; /** @todo Make this configurable. */
-
- return DrvAudioStreamCfgToProps(pCfgReq, &pVRDEStrmIn->HstStrmIn.Props);
-}
-
-static DECLCALLBACK(int) drvAudioVRDEInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq, uint32_t *pcSamples)
-{
- RT_NOREF(pCfgAcq);
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
- AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
-
- if (pcSamples)
- *pcSamples = _4K; /** @todo Make this configurable. */
-
- return DrvAudioStreamCfgToProps(pCfgReq, &pVRDEStrmOut->HstStrmOut.Props);
-}
-
-static DECLCALLBACK(bool) drvAudioVRDEIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
-{
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, false);
-
- NOREF(enmDir);
-
- if (!pDrv->fEnabled)
- return false;
-
- return true;
-}
-
-/**
- * {FIXME - Missing brief description - FIXME}
- *
- * Transfers audio input formerly sent by a connected RDP client / VRDE backend
- * (using the onVRDEInputXXX methods) over to the VRDE host (VM). The audio device
- * emulation then will read and send the data to the guest.
- *
- * @return IPRT status code.
- * @param pInterface
- * @param pHstStrmIn
- * @param pcSamplesCaptured
- */
-static DECLCALLBACK(int) drvAudioVRDECaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- uint32_t *pcSamplesCaptured)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
- AssertPtrReturn(pcSamplesCaptured, VERR_INVALID_POINTER);
-
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
- AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
-
- /** @todo Use CritSect! */
-
- int rc;
-
- uint32_t cProcessed = 0;
- if (pVRDEStrmIn->cSamplesCaptured)
- {
- rc = AudioMixBufMixToParent(&pVRDEStrmIn->HstStrmIn.MixBuf, pVRDEStrmIn->cSamplesCaptured,
- &cProcessed);
- }
- else
- rc = VINF_SUCCESS;
-
- if (RT_SUCCESS(rc))
- {
- *pcSamplesCaptured = cProcessed;
-
- Assert(pVRDEStrmIn->cSamplesCaptured >= cProcessed);
- pVRDEStrmIn->cSamplesCaptured -= cProcessed;
- }
-
- LogFlowFunc(("cSamplesCaptured=%RU32, cProcessed=%RU32 rc=%Rrc\n", pVRDEStrmIn->cSamplesCaptured, cProcessed, rc));
- return rc;
-}
-
-/**
- * Transfers VM audio output to remote client.
- *
- * Transfers VM audio output over to the VRDE instance for playing remotely
- * on the client.
- *
- * @return IPRT status code.
- * @param pInterface
- * @param pHstStrmOut
- * @param pcSamplesPlayed
- */
-static DECLCALLBACK(int) drvAudioVRDEPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- uint32_t *pcSamplesPlayed)
-{
- AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
- AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
- /* pcSamplesPlayed is optional. */
-
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
- AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
-
- uint32_t live = AudioMixBufAvail(&pHstStrmOut->MixBuf);
- uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
- uint64_t ticks = now - pVRDEStrmOut->old_ticks;
- uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
-
- /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
- uint32_t cSamplesPlayed = (int)((2 * ticks * pHstStrmOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
-
- /* Don't play more than available. */
- if (cSamplesPlayed > live)
- cSamplesPlayed = live;
-
- /* Remember when samples were consumed. */
- pVRDEStrmOut->old_ticks = now;
-
- VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHstStrmOut->Props.uHz,
- pHstStrmOut->Props.cChannels,
- pHstStrmOut->Props.cBits,
- pHstStrmOut->Props.fSigned);
-
- int cSamplesToSend = cSamplesPlayed;
-
- LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, enmFormat=%ld, cSamplesToSend=%RU32\n",
- pHstStrmOut->Props.uHz, pHstStrmOut->Props.cChannels,
- pHstStrmOut->Props.cBits, pHstStrmOut->Props.fSigned,
- format, cSamplesToSend));
-
- /*
- * Call the VRDP server with the data.
- */
- uint32_t cReadTotal = 0;
-
- PPDMAUDIOSAMPLE pSamples;
- uint32_t cRead;
- int rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend,
- &pSamples, &cRead);
- if ( RT_SUCCESS(rc)
- && cRead)
- {
- cReadTotal = cRead;
- pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
-
- if (rc == VINF_TRY_AGAIN)
- {
- rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend - cRead,
- &pSamples, &cRead);
- if (RT_SUCCESS(rc))
- pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
-
- cReadTotal += cRead;
- }
- }
-
- AudioMixBufFinish(&pHstStrmOut->MixBuf, cSamplesToSend);
-
- /*
- * Always report back all samples acquired, regardless of whether the
- * VRDP server actually did process those.
- */
- if (pcSamplesPlayed)
- *pcSamplesPlayed = cReadTotal;
-
- LogFlowFunc(("cReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioVRDEFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
-{
- RT_NOREF(pHstStrmIn);
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- if (pDrv->pConsoleVRDPServer)
- pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVRDEFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
-{
- RT_NOREF(pHstStrmOut);
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVRDEControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- RT_NOREF(enmStreamCmd);
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
- AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
-
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-
- AudioMixBufReset(&pHstStrmOut->MixBuf);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVRDEControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
-
- PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
- AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
-
- PPDMAUDIOHSTSTRMIN pThisStrmIn = &pVRDEStrmIn->HstStrmIn;
-
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-
- if (!pDrv->pConsoleVRDPServer)
- return VINF_SUCCESS;
-
- AudioMixBufReset(&pThisStrmIn->MixBuf);
-
- /* Initialize only if not already done. */
- int rc;
- if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
- {
- rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, AudioMixBufSize(&pThisStrmIn->MixBuf),
- pThisStrmIn->Props.uHz,
- pThisStrmIn->Props.cChannels, pThisStrmIn->Props.cBits);
- if (rc == VERR_NOT_SUPPORTED)
- {
- LogFlowFunc(("No RDP client connected, so no input recording supported\n"));
- rc = VINF_SUCCESS;
- }
- }
- else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
- {
- pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
- rc = VINF_SUCCESS;
- }
- else
- rc = VERR_INVALID_PARAMETER;
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioVRDEGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
-{
- RT_NOREF(pInterface);
- pCfg->cbStreamOut = sizeof(VRDESTREAMOUT);
- pCfg->cbStreamIn = sizeof(VRDESTREAMIN);
- pCfg->cMaxHstStrmsOut = 1;
- pCfg->cMaxHstStrmsIn = 2; /* Microphone in + Line in. */
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
-{
- PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
- AssertPtrReturnVoid(pDrv);
-
- if (pDrv->pConsoleVRDPServer)
- pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
-}
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
-
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
- return NULL;
-}
-
-AudioVRDE::AudioVRDE(Console *pConsole)
- : mpDrv(NULL),
- mParent(pConsole)
-{
-}
-
-AudioVRDE::~AudioVRDE(void)
-{
- if (mpDrv)
- {
- mpDrv->pAudioVRDE = NULL;
- mpDrv = NULL;
- }
-}
-
-int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
-{
- RT_NOREF(uFlags);
- LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
-
- if (mpDrv == NULL)
- return VERR_INVALID_STATE;
-
- mpDrv->fEnabled = fEnable;
-
- return VINF_SUCCESS; /* Never veto. */
-}
-
-/**
- * Marks the beginning of sending captured audio data from a connected
- * RDP client.
- *
- * @return IPRT status code.
- * @param pvContext The context; in this case a pointer to a
- * VRDESTREAMIN structure.
- * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure.
- */
-int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin)
-{
- AssertPtrReturn(pvContext, VERR_INVALID_POINTER);
- AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER);
-
- PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
- AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
-
-#ifdef LOG_ENABLED
- VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt;
- int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt);
- int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt);
- int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt);
- bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt);
- LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
- VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned));
-#endif
- return VINF_SUCCESS;
-}
-
-int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
-{
- PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
- AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
-
- PPDMAUDIOHSTSTRMIN pHstStrmIn = &pVRDEStrmIn->HstStrmIn;
- AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
-
- /** @todo Use CritSect! */
-
- uint32_t cWritten;
- int rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf, pvData, cbData, &cWritten);
- if (RT_SUCCESS(rc))
- pVRDEStrmIn->cSamplesCaptured += cWritten;
-
- LogFlowFunc(("cbData=%RU32, cWritten=%RU32, cSamplesCaptured=%RU32, rc=%Rrc\n",
- cbData, cWritten, pVRDEStrmIn->cSamplesCaptured, rc));
- return rc;
-}
-
-int AudioVRDE::onVRDEInputEnd(void *pvContext)
-{
- NOREF(pvContext);
-
- return VINF_SUCCESS;
-}
-
-int AudioVRDE::onVRDEInputIntercept(bool fEnabled)
-{
- RT_NOREF(fEnabled);
- return VINF_SUCCESS; /* Never veto. */
-}
-
-/**
- * Construct a VRDE audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-/* static */
-DECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- RT_NOREF(fFlags);
- PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
- PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
- AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
-
- LogRel(("Audio: Initializing VRDE driver\n"));
- LogFlowFunc(("fFlags=0x%x\n", fFlags));
-
- AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
- ("Configuration error: Not possible to attach anything to this driver!\n"),
- VERR_PDM_DRVINS_NO_ATTACH);
-
- /*
- * Init the static parts.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvAudioVRDEQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVRDE);
-
- /* Init defaults. */
- pThis->fEnabled = false;
-
- /*
- * Get the ConsoleVRDPServer object pointer.
- */
- void *pvUser;
- int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
- AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
-
- /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE. */
- pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
-
- /*
- * Get the AudioVRDE object pointer.
- */
- pvUser = NULL;
- rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
- AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
-
- pThis->pAudioVRDE = (AudioVRDE *)pvUser;
- pThis->pAudioVRDE->mpDrv = pThis;
-
- /*
- * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
- * Described in CFGM tree.
- */
- pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
- AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
-
- return VINF_SUCCESS;
-}
-
-
-/**
- * @interface_method_impl{PDMDRVREG,pfnDestruct}
- */
-/* static */
-DECLCALLBACK(void) AudioVRDE::drvDestruct(PPDMDRVINS pDrvIns)
-{
- PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
- PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
- LogFlowFuncEnter();
-
- /*
- * If the AudioVRDE object is still alive, we must clear it's reference to
- * us since we'll be invalid when we return from this method.
- */
- if (pThis->pAudioVRDE)
- {
- pThis->pAudioVRDE->mpDrv = NULL;
- pThis->pAudioVRDE = NULL;
- }
-}
-
-
-/**
- * VRDE audio driver registration record.
- */
-const PDMDRVREG AudioVRDE::DrvReg =
-{
- PDM_DRVREG_VERSION,
- /* szName */
- "AudioVRDE",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Audio driver for VRDE backend",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVAUDIOVRDE),
- /* pfnConstruct */
- AudioVRDE::drvConstruct,
- /* pfnDestruct */
- AudioVRDE::drvDestruct,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
-
diff --git a/src/VBox/Main/src-client/DrvAudioVideoRec.cpp b/src/VBox/Main/src-client/DrvAudioVideoRec.cpp
index 0f7b07f..770970c 100644
--- a/src/VBox/Main/src-client/DrvAudioVideoRec.cpp
+++ b/src/VBox/Main/src-client/DrvAudioVideoRec.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2014-2016 Oracle Corporation
+ * Copyright (C) 2014-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -42,7 +42,7 @@
#define CA_STATUS_INIT UINT32_C(2) /* The device is initialized */
#define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
-/// @todo move t_sample as a PDM interface
+//@todo move t_sample as a PDM interface
//typedef struct { int mute; uint32_t r; uint32_t l; } volume_t;
#define INT_MAX 0x7fffffff
@@ -129,7 +129,7 @@ static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
}
/** @todo Replace this with drvAudioHlpPcmPropsFromCfg(). */
-static int drvAudioVideoRecPcmInitInfo(PDMAUDIOPCMPROPS * pProps, PPDMAUDIOSTREAMCFG as)
+static int drvAudioVideoRecPcmInitInfo(PDMPCMPROPS * pProps, PPDMAUDIOSTREAMCFG as)
{
int rc = VINF_SUCCESS;
@@ -138,21 +138,21 @@ static int drvAudioVideoRecPcmInitInfo(PDMAUDIOPCMPROPS * pProps, PPDMAUDIOSTREA
switch (as->enmFormat)
{
- case PDMAUDIOFMT_S8:
+ case AUD_FMT_S8:
fSigned = 1;
- case PDMAUDIOFMT_U8:
+ case AUD_FMT_U8:
break;
- case PDMAUDIOFMT_S16:
+ case AUD_FMT_S16:
fSigned = 1;
- case PDMAUDIOFMT_U16:
+ case AUD_FMT_U16:
cBits = 16;
cShift = 1;
break;
- case PDMAUDIOFMT_S32:
+ case AUD_FMT_S32:
fSigned = 1;
- case PDMAUDIOFMT_U32:
+ case AUD_FMT_U32:
cBits = 32;
cShift = 2;
break;
@@ -168,7 +168,7 @@ static int drvAudioVideoRecPcmInitInfo(PDMAUDIOPCMPROPS * pProps, PPDMAUDIOSTREA
pProps->cChannels = as->cChannels;
pProps->cShift = (as->cChannels == 2) + cShift;
pProps->uAlign = (1 << pProps->cShift) - 1;
- pProps->cbBitrate = (pProps->cBits * pProps->uHz * pProps->cChannels) / 8;
+ pProps->cbPerSec = pProps->uHz << pProps->cShift;
pProps->fSwapEndian = (as->enmEndianness != PDMAUDIOHOSTENDIANESS);
return rc;
@@ -211,9 +211,9 @@ static int audio_pcm_hw_get_live_out2 (PPDMAUDIOHSTSTRMOUT hw, int *nb_live)
{
int live = smin;
- if (live < 0 || live > hw->cSampleBufferSize)
+ if (live < 0 || live > hw->cSamples)
{
- LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSampleBufferSize));
+ LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
return 0;
}
return live;
@@ -227,9 +227,9 @@ static int audio_pcm_hw_get_live_out (PPDMAUDIOHSTSTRMOUT hw)
int live;
live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
- if (live < 0 || live > hw->cSampleBufferSize)
+ if (live < 0 || live > hw->cSamples)
{
- LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSampleBufferSize));
+ LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
return 0;
}
return live;
@@ -256,9 +256,9 @@ static int audio_pcm_hw_find_min_in (PPDMAUDIOHSTSTRMIN hw)
int audio_pcm_hw_get_live_in (PPDMAUDIOHSTSTRMIN hw)
{
int live = hw->cTotalSamplesCaptured - audio_pcm_hw_find_min_in (hw);
- if (live < 0 || live > hw->cSampleBufferSize)
+ if (live < 0 || live > hw->cSamples)
{
- LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSampleBufferSize));
+ LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
return 0;
}
return live;
@@ -382,7 +382,7 @@ static DECLCALLBACK(int) drvAudioVideoRecInitOut(PPDMIHOSTAUDIO pInterface, PPDM
PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
- pHostVoiceOut->cSampleBufferSize = _4K; /* 4096 samples * 4 = 16K bytes total. */
+ pHostVoiceOut->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
return drvAudioVideoRecPcmInitInfo(&pVRDEVoiceOut->pHostVoiceOut.Props, pCfg);
}
@@ -393,7 +393,7 @@ static DECLCALLBACK(int) drvAudioVideoRecInitIn(PPDMIHOSTAUDIO pInterface, PPDMA
PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
- pHostVoiceIn->cSampleBufferSize = _4K; /* 4096 samples * 4 = 16K bytes total. */
+ pHostVoiceIn->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
return drvAudioVideoRecPcmInitInfo(&pVRDEVoice->pHostVoiceIn.Props, pCfg);
}
@@ -417,7 +417,7 @@ static DECLCALLBACK(int) drvAudioVideoRecCaptureIn(PPDMIHOSTAUDIO pInterface, PP
size_t cSamplesRingBuffer = RTCircBufUsed(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE);
/* How much space is available in the mix buffer. Use the smaller size of the too. */
- cSamplesRingBuffer = RT_MIN(cSamplesRingBuffer, (uint32_t)(pVRDEVoice->pHostVoiceIn.cSampleBufferSize -
+ cSamplesRingBuffer = RT_MIN(cSamplesRingBuffer, (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples -
audio_pcm_hw_get_live_in (&pVRDEVoice->pHostVoiceIn)));
LogFlowFunc(("Start reading buffer with %d samples (%d bytes)\n", cSamplesRingBuffer,
@@ -429,14 +429,14 @@ static DECLCALLBACK(int) drvAudioVideoRecCaptureIn(PPDMIHOSTAUDIO pInterface, PP
{
/* How much is left? Split request at the end of our samples buffer. */
size_t cSamplesToRead = RT_MIN(cSamplesRingBuffer - cSamplesRead,
- (uint32_t)(pVRDEVoice->pHostVoiceIn.cSampleBufferSize - pVRDEVoice->pHostVoiceIn.offSamplesWritten));
+ (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples - pVRDEVoice->pHostVoiceIn.offSamplesWritten));
size_t cbToRead = cSamplesToRead * sizeof(PDMAUDIOSAMPLE);
LogFlowFunc(("Try reading %zu samples (%zu bytes)\n", cSamplesToRead, cbToRead));
/* Try to acquire the necessary block from the ring buffer. Remeber in fltRecrodCallback we
* we are filling this buffer with the audio data available from VRDP. Here we are reading it
*/
- /** @todo do I need to introduce a thread to fill the buffer in fltRecordcallback. So that
+ /*todo do I need to introduce a thread to fill the buffer in fltRecordcallback. So that
* filling is in separate thread and the reading of that buffer is in separate thread
*/
void *pvSrc;
@@ -461,7 +461,7 @@ static DECLCALLBACK(int) drvAudioVideoRecCaptureIn(PPDMIHOSTAUDIO pInterface, PP
break;
pVRDEVoice->pHostVoiceIn.offSamplesWritten = (pVRDEVoice->pHostVoiceIn.offSamplesWritten + cSamplesToRead)
- % pVRDEVoice->pHostVoiceIn.cSampleBufferSize;
+ % pVRDEVoice->pHostVoiceIn.cSamples;
/* How much have we reads so far. */
cSamplesRead += cSamplesToRead;
@@ -501,22 +501,22 @@ static DECLCALLBACK(int) drvAudioVideoRecPlayOut(PPDMIHOSTAUDIO pInterface, PPDM
LogFlowFunc(("freq=%d, chan=%d, cBits = %d, fsigned = %d, cSamples=%d format=%d\n",
pHostVoiceOut->Props.uHz, pHostVoiceOut->Props.cChannels,
pHostVoiceOut->Props.cBits, pHostVoiceOut->Props.fSigned,
- pHostVoiceOut->cSampleBufferSize, format));
+ pHostVoiceOut->cSamples, format));
pVRDEVoiceOut->old_ticks = now;
int cSamplesToSend = RT_MIN(live, cSamplesPlayed);
- if (pHostVoiceOut->cOffSamplesRead + cSamplesToSend > pHostVoiceOut->cSampleBufferSize)
+ if (pHostVoiceOut->cOffSamplesRead + cSamplesToSend > pHostVoiceOut->cSamples)
{
/* send the samples till the end of pHostStereoSampleBuf */
pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
- (pHostVoiceOut->cSampleBufferSize - pHostVoiceOut->cOffSamplesRead), format);
+ (pHostVoiceOut->cSamples - pHostVoiceOut->cOffSamplesRead), format);
/*pHostStereoSampleBuff already has the samples which exceeded its space. They have overwriten the old
* played sampled starting from offset 0. So based on the number of samples that we had to play,
* read the number of samples from offset 0 .
*/
pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[0],
- (cSamplesToSend - (pHostVoiceOut->cSampleBufferSize -
+ (cSamplesToSend - (pHostVoiceOut->cSamples -
pHostVoiceOut->cOffSamplesRead)),
format);
}
@@ -526,7 +526,7 @@ static DECLCALLBACK(int) drvAudioVideoRecPlayOut(PPDMIHOSTAUDIO pInterface, PPDM
cSamplesToSend, format);
}
- pHostVoiceOut->cOffSamplesRead = (pHostVoiceOut->cOffSamplesRead + cSamplesToSend) % pHostVoiceOut->cSampleBufferSize;
+ pHostVoiceOut->cOffSamplesRead = (pHostVoiceOut->cOffSamplesRead + cSamplesToSend) % pHostVoiceOut->cSamples;
*pcSamplesPlayed = cSamplesToSend;
return VINF_SUCCESS;
@@ -572,7 +572,7 @@ static DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PP
/* initialize only if not already done */
if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
{
- /// @todo if (!pVRDEVoice->fIsInit)
+ //@todo if (!pVRDEVoice->fIsInit)
// RTCircBufReset(pVRDEVoice->pRecordedVoiceBuf);
pVRDEVoice->fIsInit = 1;
pVRDEVoice->pHostVoiceIn = *pHostVoiceIn;
@@ -583,14 +583,14 @@ static DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PP
pVRDEVoice->pvRateBuffer = NULL;
pVRDEVoice->cbRateBufferAllocated = 0;
- pVRDEVoice->pHostVoiceIn.cSampleBufferSize = 2048;
+ pVRDEVoice->pHostVoiceIn.cSamples = 2048;
/* Initialize the hardware info section with the audio settings */
ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_INIT);
/* Create the internal ring buffer. */
RTCircBufCreate(&pVRDEVoice->pRecordedVoiceBuf,
- pVRDEVoice->pHostVoiceIn.cSampleBufferSize * sizeof(PDMAUDIOSAMPLE));
+ pVRDEVoice->pHostVoiceIn.cSamples * sizeof(PDMAUDIOSAMPLE));
if (!RT_VALID_PTR(pVRDEVoice->pRecordedVoiceBuf))
{
@@ -599,7 +599,7 @@ static DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PP
}
ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_INIT);
- return pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEVoice, pHostVoiceIn->cSampleBufferSize,
+ return pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEVoice, pHostVoiceIn->cSamples,
pHostVoiceIn->Props.uHz,
pHostVoiceIn->Props.cChannels, pHostVoiceIn->Props.cBits);
}
@@ -616,17 +616,14 @@ static DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PP
return VINF_SUCCESS;
}
-static DECLCALLBACK(int) drvAudioVideoRecGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
+static DECLCALLBACK(int) drvAudioVideoRecGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pAudioConf)
{
- NOREF(pInterface);
- AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
+ LogFlowFunc(("pAudioConf=%p\n", pAudioConf));
- pCfg->cbStreamIn = sizeof(VIDEORECAUDIOIN);
- pCfg->cbStreamOut = sizeof(VIDEORECAUDIOOUT);
- pCfg->cMaxStreamsIn = UINT32_MAx;
- pCfg->cMaxStreamsOut = UINT32_MAX;
- pCfg->cSources = 1;
- pCfg->cSinks = 1;
+ pAudioConf->cbStreamOut = sizeof(VIDEORECAUDIOOUT);
+ pAudioConf->cbStreamIn = sizeof(VIDEORECAUDIOIN);
+ pAudioConf->cMaxHstStrmsOut = 1;
+ pAudioConf->cMaxHstStrmsIn = 1;
return VINF_SUCCESS;
}
@@ -703,7 +700,7 @@ int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int
LogFlowFunc(("Required freq as requested by VRDP Server = %d\n", iSampleHz));
//if (iSampleHz && iSampleHz != pVRDEVoice->pHostVoiceIn.Props.uFrequency)
{
- /** @todo if the above condition is false then pVRDEVoice->uFrequency will remain 0 */
+ /* @todo if the above condition is false then pVRDEVoice->uFrequency will remain 0 */
/*mpDrv->pUpPort->pfnPrepareAudioConversion(mpDrv->pUpPort, iSampleHz,
pVRDEVoice->pHostVoiceIn.Props.uFrequency,
&pVRDEVoice->rate);*/
@@ -736,7 +733,7 @@ int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventData(void *pvContext, cons
pVRDEVoice->convAudioDevFmtToStSampl(pHostStereoSampleBuf, pvData, cSamples, &videorec_nominal_volume);
/* count of rate adjusted samples */
- pVRDEVoice->uFrequency = 22100; /** @todo handle this. How pVRDEVoice will get proper value */
+ pVRDEVoice->uFrequency = 22100; /* @todo handle this. How pVRDEVoice will get proper value */
cConvertedSamples = (cSamples * pVRDEVoice->pHostVoiceIn.Props.uHz) / pVRDEVoice->uFrequency;
vrdeReallocRateAdjSampleBuf(pVRDEVoice, cConvertedSamples);
diff --git a/src/VBox/Main/src-client/DrvAudioVideoRec_50.cpp b/src/VBox/Main/src-client/DrvAudioVideoRec_50.cpp
deleted file mode 100644
index fac64af..0000000
--- a/src/VBox/Main/src-client/DrvAudioVideoRec_50.cpp
+++ /dev/null
@@ -1,911 +0,0 @@
-/* $Id: DrvAudioVideoRec_50.cpp $ */
-/** @file
- * Video recording audio backend for Main.
- */
-
-/*
- * Copyright (C) 2014-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- */
-#include "DrvAudioVideoRec_50.h"
-#include "ConsoleImpl.h"
-#include "ConsoleVRDPServer.h"
-
-#include "Logging.h"
-
-#include <iprt/mem.h>
-#include <iprt/cdefs.h>
-#include <iprt/circbuf.h>
-
-#include <VBox/vmm/pdmaudioifs.h>
-#include <VBox/vmm/pdmdrv.h>
-#include <VBox/RemoteDesktop/VRDE.h>
-#include <VBox/vmm/cfgm.h>
-#include <VBox/err.h>
-
-#ifdef LOG_GROUP
- #undef LOG_GROUP
-#endif
-#define LOG_GROUP LOG_GROUP_DEV_AUDIO
-#include <VBox/log.h>
-
-/* Initialization status indicator used for the recreation of the AudioUnits. */
-#define CA_STATUS_UNINIT UINT32_C(0) /* The device is uninitialized */
-#define CA_STATUS_IN_INIT UINT32_C(1) /* The device is currently initializing */
-#define CA_STATUS_INIT UINT32_C(2) /* The device is initialized */
-#define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
-
-//@todo move t_sample as a PDM interface
-//typedef struct { int mute; uint32_t r; uint32_t l; } volume_t;
-
-#define INT_MAX 0x7fffffff
-volume_t videorec_nominal_volume = {
- 0,
- INT_MAX,
- INT_MAX
-};
-
-/* The desired buffer length in milliseconds. Will be the target total stream
- * latency on newer version of pulse. Apparent latency can be less (or more.)
- * In case its need to be used. Currently its not used.
- */
-#if 0
-static struct
-{
- int buffer_msecs_out;
- int buffer_msecs_in;
-} confAudioVideoRec
-=
-{
- INIT_FIELD (.buffer_msecs_out = ) 100,
- INIT_FIELD (.buffer_msecs_in = ) 100,
-};
-#endif
-
-/**
- * Audio video recording driver instance data.
- *
- * @extends PDMIAUDIOSNIFFERCONNECTOR
- */
-typedef struct DRVAUDIOVIDEOREC
-{
- /** Pointer to audio video recording object. */
- AudioVideoRec *pAudioVideoRec;
- PPDMDRVINS pDrvIns;
- /** Pointer to the driver instance structure. */
- PDMIHOSTAUDIO IHostAudio;
- ConsoleVRDPServer *pConsoleVRDPServer;
- /** Pointer to the DrvAudio port interface that is above it. */
- PPDMIAUDIOCONNECTOR pUpPort;
-} DRVAUDIOVIDEOREC, *PDRVAUDIOVIDEOREC;
-typedef struct PDMAUDIOHSTSTRMOUT PDMAUDIOHSTSTRMOUT;
-typedef PDMAUDIOHSTSTRMOUT *PPDMAUDIOHSTSTRMOUT;
-
-typedef struct VIDEORECAUDIOIN
-{
- /* Audio and audio details for recording */
- PDMAUDIOHSTSTRMIN pHostVoiceIn;
- void * pvUserCtx;
- /* Number of bytes per frame (bitsPerSample * channels) of the actual input format. */
- uint32_t cBytesPerFrame;
- /* Frequency of the actual audio format. */
- uint32_t uFrequency;
- /* If the actual format frequence differs from the requested format, this is not NULL. */
- void *rate;
- /* Temporary buffer for st_sample_t representation of the input audio data. */
- void *pvSamplesBuffer;
- /* buffer for bytes of samples (not rate converted) */
- uint32_t cbSamplesBufferAllocated;
- /* Temporary buffer for frequency conversion. */
- void *pvRateBuffer;
- /* buffer for bytes rate converted samples */
- uint32_t cbRateBufferAllocated;
- /* A ring buffer for transferring data to the playback thread */
- PRTCIRCBUF pRecordedVoiceBuf;
- t_sample * convAudioDevFmtToStSampl;
- uint32_t fIsInit;
- uint32_t status;
-} VIDEORECAUDIOIN, *PVIDEORECAUDIOIN;
-
-typedef struct VIDEORECAUDIOOUT
-{
- PDMAUDIOHSTSTRMOUT pHostVoiceOut;
- uint64_t old_ticks;
- uint64_t cSamplesSentPerSec;
-} VIDEORECAUDIOOUT, *PVIDEORECAUDIOOUT;
-
-static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
-{
- LogFlowFuncEnter();
-
- return VINF_SUCCESS;
-}
-
-/** @todo Replace this with drvAudioHlpPcmPropsFromCfg(). */
-static int drvAudioVideoRecPcmInitInfo(PDMPCMPROPS * pProps, PPDMAUDIOSTREAMCFG as)
-{
- int rc = VINF_SUCCESS;
-
- uint8_t cBits = 8, cShift = 0;
- bool fSigned = false;
-
- switch (as->enmFormat)
- {
- case AUD_FMT_S8:
- fSigned = 1;
- case AUD_FMT_U8:
- break;
-
- case AUD_FMT_S16:
- fSigned = 1;
- case AUD_FMT_U16:
- cBits = 16;
- cShift = 1;
- break;
-
- case AUD_FMT_S32:
- fSigned = 1;
- case AUD_FMT_U32:
- cBits = 32;
- cShift = 2;
- break;
-
- default:
- rc = VERR_NOT_SUPPORTED;
- break;
- }
-
- pProps->uHz = as->uHz;
- pProps->cBits = cBits;
- pProps->fSigned = fSigned;
- pProps->cChannels = as->cChannels;
- pProps->cShift = (as->cChannels == 2) + cShift;
- pProps->uAlign = (1 << pProps->cShift) - 1;
- pProps->cbPerSec = pProps->uHz << pProps->cShift;
- pProps->fSwapEndian = (as->enmEndianness != PDMAUDIOHOSTENDIANESS);
-
- return rc;
-}
-
-/*
- * Hard voice (playback)
- */
-static int audio_pcm_hw_find_min_out (PPDMAUDIOHSTSTRMOUT hw, int *nb_livep)
-{
- PPDMAUDIOGSTSTRMOUT sw;
- PPDMAUDIOGSTSTRMOUT pIter;
- int m = INT_MAX;
- int nb_live = 0;
-
- RTListForEach(&hw->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
- {
- sw = pIter;
- if (sw->State.fActive || !sw->State.fEmpty)
- {
- m = RT_MIN (m, sw->cTotalSamplesWritten);
- nb_live += 1;
- }
- }
-
- *nb_livep = nb_live;
- return m;
-}
-
-static int audio_pcm_hw_get_live_out2 (PPDMAUDIOHSTSTRMOUT hw, int *nb_live)
-{
- int smin;
-
- smin = audio_pcm_hw_find_min_out (hw, nb_live);
-
- if (!*nb_live) {
- return 0;
- }
- else
- {
- int live = smin;
-
- if (live < 0 || live > hw->cSamples)
- {
- LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
- return 0;
- }
- return live;
- }
-}
-
-
-static int audio_pcm_hw_get_live_out (PPDMAUDIOHSTSTRMOUT hw)
-{
- int nb_live;
- int live;
-
- live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
- if (live < 0 || live > hw->cSamples)
- {
- LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
- return 0;
- }
- return live;
-}
-
-/*
- * Hard voice (capture)
- */
-static int audio_pcm_hw_find_min_in (PPDMAUDIOHSTSTRMIN hw)
-{
- PPDMAUDIOGSTSTRMIN pIter;
- int m = hw->cTotalSamplesCaptured;
-
- RTListForEach(&hw->lstGstStreamsIn, pIter, PDMAUDIOGSTSTRMIN, Node)
- {
- if (pIter->State.fActive)
- {
- m = RT_MIN (m, pIter->cTotalHostSamplesRead);
- }
- }
- return m;
-}
-
-int audio_pcm_hw_get_live_in (PPDMAUDIOHSTSTRMIN hw)
-{
- int live = hw->cTotalSamplesCaptured - audio_pcm_hw_find_min_in (hw);
- if (live < 0 || live > hw->cSamples)
- {
- LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
- return 0;
- }
- return live;
-}
-
-static inline void *advance (void *p, int incr)
-{
- uint8_t *d = (uint8_t*)p;
- return (d + incr);
-}
-
-static int vrdeReallocSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
-{
- uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
- if (cbBuffer > pVRDEVoice->cbSamplesBufferAllocated)
- {
- /** @todo r=andy Why not using RTMemReAlloc? */
- if (pVRDEVoice->pvSamplesBuffer)
- {
- RTMemFree(pVRDEVoice->pvSamplesBuffer);
- pVRDEVoice->pvSamplesBuffer = NULL;
- }
- pVRDEVoice->pvSamplesBuffer = RTMemAlloc(cbBuffer);
- if (pVRDEVoice->pvSamplesBuffer)
- pVRDEVoice->cbSamplesBufferAllocated = cbBuffer;
- else
- pVRDEVoice->cbSamplesBufferAllocated = 0;
- }
-
- return VINF_SUCCESS;
-}
-
-static int vrdeReallocRateAdjSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
-{
- uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
- if (cbBuffer > pVRDEVoice->cbRateBufferAllocated)
- {
- RTMemFree(pVRDEVoice->pvRateBuffer);
- pVRDEVoice->pvRateBuffer = RTMemAlloc(cbBuffer);
- if (pVRDEVoice->pvRateBuffer)
- pVRDEVoice->cbRateBufferAllocated = cbBuffer;
- else
- pVRDEVoice->cbRateBufferAllocated = 0;
- }
-
- return VINF_SUCCESS;
-}
-
-/*******************************************************************************
- *
- * AudioVideoRec input section
- *
- ******************************************************************************/
-
-/*
- * Callback to feed audio input buffer. Samples format is be the same as
- * in the voice. The caller prepares st_sample_t.
- *
- * @param cbSamples Size of pvSamples array in bytes.
- * @param pvSamples Points to an array of samples.
- *
- * @return IPRT status code.
- */
-static int vrdeRecordingCallback(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cbSamples, const void *pvSamples)
-{
- int rc = VINF_SUCCESS;
- size_t csWritten = 0;
-
- Assert((cbSamples % sizeof(PDMAUDIOSAMPLE)) == 0);
-
- if (!pVRDEVoice->fIsInit)
- return VINF_SUCCESS;
-
- /* If nothing is pending return immediately. */
- if (cbSamples == 0)
- return VINF_SUCCESS;
-
- /* How much space is free in the ring buffer? */
- size_t csAvail = RTCircBufFree(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE); /* bytes -> samples */
-
- /* How much space is used in the audio buffer. Use the smaller size of the too. */
- csAvail = RT_MIN(csAvail, cbSamples / sizeof(PDMAUDIOSAMPLE));
-
- /* Iterate as long as data is available. */
- while (csWritten < csAvail)
- {
- /* How much is left? */
- size_t csToWrite = csAvail - csWritten;
- size_t cbToWrite = csToWrite * sizeof(PDMAUDIOSAMPLE);
-
- /* Try to acquire the necessary space from the ring buffer. */
- void *pcDst;
- RTCircBufAcquireWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite, &pcDst, &cbToWrite);
-
- /* How much do we get? */
- csToWrite = cbToWrite / sizeof(PDMAUDIOSAMPLE);
-
- /* Copy the data from the audio buffer to the ring buffer in PVRDEVoice. */
- if (csToWrite)
- {
- memcpy(pcDst, (uint8_t *)pvSamples + (csWritten * sizeof(PDMAUDIOSAMPLE)), cbToWrite);
- csWritten += csToWrite;
- }
-
- /* Release the ring buffer, so the main thread could start reading this data. */
- RTCircBufReleaseWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite);
-
- if (RT_UNLIKELY(csToWrite == 0))
- break;
- }
-
- LogFlowFunc(("Finished writing buffer with %RU32 samples (%RU32 bytes)\n",
- csWritten, csWritten * sizeof(PDMAUDIOSAMPLE)));
-
- return rc;
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut, PPDMAUDIOSTREAMCFG pCfg)
-{
- LogFlowFuncEnter();
- PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
-
- PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
- pHostVoiceOut->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
-
- return drvAudioVideoRecPcmInitInfo(&pVRDEVoiceOut->pHostVoiceOut.Props, pCfg);
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecInitIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn, PPDMAUDIOSTREAMCFG pCfg)
-{
- LogFlowFuncEnter();
- PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
-
- PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
- pHostVoiceIn->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
-
- return drvAudioVideoRecPcmInitInfo(&pVRDEVoice->pHostVoiceIn.Props, pCfg);
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
- uint32_t *pcSamplesCaptured)
-{
- /** @todo Take care of the size of the buffer allocated to pHostVoiceIn. */
- PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
-
- /* use this from DrvHostCoreAudio.c */
- if (ASMAtomicReadU32(&pVRDEVoice->status) != CA_STATUS_INIT)
- {
- LogFlowFunc(("VRDE voice not initialized\n"));
-
- *pcSamplesCaptured = 0;
- return VERR_GENERAL_FAILURE; /** @todo Fudge! */
- }
-
- /* how much space is used in the ring buffer in pRecordedVocieBuf with pAudioVideoRec . Bytes-> samples*/
- size_t cSamplesRingBuffer = RTCircBufUsed(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE);
-
- /* How much space is available in the mix buffer. Use the smaller size of the too. */
- cSamplesRingBuffer = RT_MIN(cSamplesRingBuffer, (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples -
- audio_pcm_hw_get_live_in (&pVRDEVoice->pHostVoiceIn)));
-
- LogFlowFunc(("Start reading buffer with %d samples (%d bytes)\n", cSamplesRingBuffer,
- cSamplesRingBuffer * sizeof(PDMAUDIOSAMPLE)));
-
- /* Iterate as long as data is available */
- size_t cSamplesRead = 0;
- while (cSamplesRead < cSamplesRingBuffer)
- {
- /* How much is left? Split request at the end of our samples buffer. */
- size_t cSamplesToRead = RT_MIN(cSamplesRingBuffer - cSamplesRead,
- (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples - pVRDEVoice->pHostVoiceIn.offSamplesWritten));
- size_t cbToRead = cSamplesToRead * sizeof(PDMAUDIOSAMPLE);
- LogFlowFunc(("Try reading %zu samples (%zu bytes)\n", cSamplesToRead, cbToRead));
-
- /* Try to acquire the necessary block from the ring buffer. Remeber in fltRecrodCallback we
- * we are filling this buffer with the audio data available from VRDP. Here we are reading it
- */
- /*todo do I need to introduce a thread to fill the buffer in fltRecordcallback. So that
- * filling is in separate thread and the reading of that buffer is in separate thread
- */
- void *pvSrc;
- RTCircBufAcquireReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead, &pvSrc, &cbToRead);
-
- /* How much to we get? */
- cSamplesToRead = cbToRead / sizeof(PDMAUDIOSAMPLE);
- LogFlowFunc(("AuderVRDE: There are %d samples (%d bytes) available\n", cSamplesToRead, cbToRead));
-
- /* Break if nothing is used anymore. */
- if (cSamplesToRead)
- {
- /* Copy the data from our ring buffer to the mix buffer. */
- PPDMAUDIOSAMPLE psDst = pVRDEVoice->pHostVoiceIn.paSamples + pVRDEVoice->pHostVoiceIn.offSamplesWritten;
- memcpy(psDst, pvSrc, cbToRead);
- }
-
- /* Release the read buffer, so it could be used for new data. */
- RTCircBufReleaseReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead);
-
- if (!cSamplesToRead)
- break;
-
- pVRDEVoice->pHostVoiceIn.offSamplesWritten = (pVRDEVoice->pHostVoiceIn.offSamplesWritten + cSamplesToRead)
- % pVRDEVoice->pHostVoiceIn.cSamples;
-
- /* How much have we reads so far. */
- cSamplesRead += cSamplesToRead;
- }
-
- LogFlowFunc(("Finished reading buffer with %zu samples (%zu bytes)\n",
- cSamplesRead, cSamplesRead * sizeof(PDMAUDIOSAMPLE)));
-
- *pcSamplesCaptured = cSamplesRead;
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut,
- uint32_t *pcSamplesPlayed)
-{
- PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
- PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
-
- /*
- * Just call the VRDP server with the data.
- */
- int live = audio_pcm_hw_get_live_out(pHostVoiceOut);
- uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
- uint64_t ticks = now - pVRDEVoiceOut->old_ticks;
- uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
-
- int cSamplesPlayed = (int)((2 * ticks * pHostVoiceOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
- if (cSamplesPlayed < 0)
- cSamplesPlayed = live;
-
- pHostVoiceOut->Props.cBits = 128; /** @todo Make this configurable (or at least a define)? */
- VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHostVoiceOut->Props.uHz,
- pHostVoiceOut->Props.cChannels,
- pHostVoiceOut->Props.cBits, /* bits per sample */
- !pHostVoiceOut->Props.fSigned);
-
- LogFlowFunc(("freq=%d, chan=%d, cBits = %d, fsigned = %d, cSamples=%d format=%d\n",
- pHostVoiceOut->Props.uHz, pHostVoiceOut->Props.cChannels,
- pHostVoiceOut->Props.cBits, pHostVoiceOut->Props.fSigned,
- pHostVoiceOut->cSamples, format));
-
- pVRDEVoiceOut->old_ticks = now;
- int cSamplesToSend = RT_MIN(live, cSamplesPlayed);
-
- if (pHostVoiceOut->cOffSamplesRead + cSamplesToSend > pHostVoiceOut->cSamples)
- {
- /* send the samples till the end of pHostStereoSampleBuf */
- pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
- (pHostVoiceOut->cSamples - pHostVoiceOut->cOffSamplesRead), format);
- /*pHostStereoSampleBuff already has the samples which exceeded its space. They have overwriten the old
- * played sampled starting from offset 0. So based on the number of samples that we had to play,
- * read the number of samples from offset 0 .
- */
- pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[0],
- (cSamplesToSend - (pHostVoiceOut->cSamples -
- pHostVoiceOut->cOffSamplesRead)),
- format);
- }
- else
- {
- pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
- cSamplesToSend, format);
- }
-
- pHostVoiceOut->cOffSamplesRead = (pHostVoiceOut->cOffSamplesRead + cSamplesToSend) % pHostVoiceOut->cSamples;
-
- *pcSamplesPlayed = cSamplesToSend;
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN hw)
-{
- PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
- LogFlowFuncEnter();
- pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut)
-{
- PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
- LogFlowFuncEnter();
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT hw,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
- LogFlowFuncEnter();
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
- PDMAUDIOSTREAMCMD enmStreamCmd)
-{
- PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
-
- /* Initialize VRDEVoice and return to VRDP server which returns this struct back to us
- * in the form void * pvContext
- */
- PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
- LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
-
- /* initialize only if not already done */
- if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
- {
- //@todo if (!pVRDEVoice->fIsInit)
- // RTCircBufReset(pVRDEVoice->pRecordedVoiceBuf);
- pVRDEVoice->fIsInit = 1;
- pVRDEVoice->pHostVoiceIn = *pHostVoiceIn;
- pVRDEVoice->cBytesPerFrame = 1;
- pVRDEVoice->uFrequency = 0;
- pVRDEVoice->rate = NULL;
- pVRDEVoice->cbSamplesBufferAllocated = 0;
- pVRDEVoice->pvRateBuffer = NULL;
- pVRDEVoice->cbRateBufferAllocated = 0;
-
- pVRDEVoice->pHostVoiceIn.cSamples = 2048;
- /* Initialize the hardware info section with the audio settings */
-
- ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_INIT);
-
- /* Create the internal ring buffer. */
- RTCircBufCreate(&pVRDEVoice->pRecordedVoiceBuf,
- pVRDEVoice->pHostVoiceIn.cSamples * sizeof(PDMAUDIOSAMPLE));
-
- if (!RT_VALID_PTR(pVRDEVoice->pRecordedVoiceBuf))
- {
- LogRel(("Failed to create internal ring buffer\n"));
- return VERR_NO_MEMORY;
- }
-
- ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_INIT);
- return pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEVoice, pHostVoiceIn->cSamples,
- pHostVoiceIn->Props.uHz,
- pHostVoiceIn->Props.cChannels, pHostVoiceIn->Props.cBits);
- }
- else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
- {
- pVRDEVoice->fIsInit = 0;
- ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_UNINIT);
- RTCircBufDestroy(pVRDEVoice->pRecordedVoiceBuf);
- pVRDEVoice->pRecordedVoiceBuf = NULL;
- ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_UNINIT);
- pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
- }
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(int) drvAudioVideoRecGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pAudioConf)
-{
- LogFlowFunc(("pAudioConf=%p\n", pAudioConf));
-
- pAudioConf->cbStreamOut = sizeof(VIDEORECAUDIOOUT);
- pAudioConf->cbStreamIn = sizeof(VIDEORECAUDIOIN);
- pAudioConf->cMaxHstStrmsOut = 1;
- pAudioConf->cMaxHstStrmsIn = 1;
-
- return VINF_SUCCESS;
-}
-
-static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
-{
- NOREF(pInterface);
-}
-
-/**
- * @interface_method_impl{PDMIBASE,pfnQueryInterface}
- */
-static DECLCALLBACK(void *) drvAudioVideoRecQueryInterface(PPDMIBASE pInterface, const char *pszIID)
-{
- PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
- PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
- PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
- return NULL;
-}
-
-AudioVideoRec::AudioVideoRec(Console *pConsole)
- : mpDrv(NULL),
- mParent(pConsole)
-{
-}
-
-AudioVideoRec::~AudioVideoRec(void)
-{
- if (mpDrv)
- {
- mpDrv->pAudioVideoRec = NULL;
- mpDrv = NULL;
- }
-}
-
-int AudioVideoRec::handleVideoRecSvrCmdAudioInputIntercept(bool fIntercept)
-{
- LogFlowThisFunc(("fIntercept=%RTbool\n", fIntercept));
- return VINF_SUCCESS;
-}
-
-int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels,
- int cBits, bool fUnsigned)
-{
- int bitIdx;
- PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
- LogFlowFunc(("handleVRDPCmdInputEventBegin\n"));
- /* Prepare a format convertion for the actually used format. */
- pVRDEVoice->cBytesPerFrame = ((cBits + 7) / 8) * cChannels;
- if (cBits == 16)
- {
- bitIdx = 1;
- }
- else if (cBits == 32)
- {
- bitIdx = 2;
- }
- else
- {
- bitIdx = 0;
- }
-
- //PPDMIAUDIOCONNECTOR pPort = server->mConsole->getAudioVideoRec()->getDrvAudioPort();
- /* Call DrvAudio interface to get the t_sample type conversion function */
- /*mpDrv->pUpPort->pfnConvDevFmtToStSample(mpDrv->pUpPort,
- (cChannels == 2) ? 1 : 0,
- !fUnsigned, 0, bitIdx,
- pVRDEVoice->convAudioDevFmtToStSampl);*/
- if (pVRDEVoice->convAudioDevFmtToStSampl)
- {
- LogFlowFunc(("Failed to get the conversion function \n"));
- }
- LogFlowFunc(("Required freq as requested by VRDP Server = %d\n", iSampleHz));
- //if (iSampleHz && iSampleHz != pVRDEVoice->pHostVoiceIn.Props.uFrequency)
- {
- /* @todo if the above condition is false then pVRDEVoice->uFrequency will remain 0 */
- /*mpDrv->pUpPort->pfnPrepareAudioConversion(mpDrv->pUpPort, iSampleHz,
- pVRDEVoice->pHostVoiceIn.Props.uFrequency,
- &pVRDEVoice->rate);*/
- pVRDEVoice->uFrequency = iSampleHz;
- LogFlowFunc(("pVRDEVoice assigned requested freq =%d\n", pVRDEVoice->uFrequency));
- }
- return VINF_SUCCESS;
-}
-
-/*
- * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
- * drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
- */
-int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData)
-{
- PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
- PPDMAUDIOSAMPLE pHostStereoSampleBuf; /* target sample buffer */
- PPDMAUDIOSAMPLE pConvertedSampleBuf; /* samples adjusted for rate */
- uint32_t cSamples = cbData / pVRDEVoice->cBytesPerFrame; /* Count of samples */
- void * pTmpSampleBuf = NULL;
- uint32_t cConvertedSamples; /* samples adjusted for rate */
- uint32_t cbSamples = 0; /* count of bytes occupied by samples */
- int rc = VINF_SUCCESS;
-
- LogFlowFunc(("handleVRDPCmdInputEventData cbData = %d, bytesperfram=%d\n",
- cbData, pVRDEVoice->cBytesPerFrame));
-
- vrdeReallocSampleBuf(pVRDEVoice, cSamples);
- pHostStereoSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvSamplesBuffer;
- pVRDEVoice->convAudioDevFmtToStSampl(pHostStereoSampleBuf, pvData, cSamples, &videorec_nominal_volume);
-
- /* count of rate adjusted samples */
- pVRDEVoice->uFrequency = 22100; /* @todo handle this. How pVRDEVoice will get proper value */
- cConvertedSamples = (cSamples * pVRDEVoice->pHostVoiceIn.Props.uHz) / pVRDEVoice->uFrequency;
- vrdeReallocRateAdjSampleBuf(pVRDEVoice, cConvertedSamples);
-
- pConvertedSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvRateBuffer;
- if (pConvertedSampleBuf)
- {
- uint32_t cSampleSrc = cSamples;
- uint32_t cSampleDst = cConvertedSamples;
- /*mpDrv->pUpPort->pfnDoRateConversion(mpDrv->pUpPort, pVRDEVoice->rate, pHostStereoSampleBuf,
- pConvertedSampleBuf, &cSampleSrc, &cConvertedSamples);*/
- pTmpSampleBuf = pConvertedSampleBuf;
- cbSamples = cConvertedSamples * sizeof(PDMAUDIOSAMPLE);
- }
-
- if (cbSamples)
- rc = vrdeRecordingCallback(pVRDEVoice, cbSamples, pTmpSampleBuf);
-
- return rc;
-}
-
-/*
- * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
- * drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
- */
-int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventEnd(void *pvContext)
-{
- LogFlowFuncEnter();
-
- PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
- AssertPtrReturn(pVRDEVoice, VERR_INVALID_POINTER);
-
- /* The caller will not use this context anymore. */
- if (pVRDEVoice->rate)
- {
- //mpDrv->pUpPort->pfnEndAudioConversion(mpDrv->pUpPort, pVRDEVoice->rate);
- }
-
- if (pVRDEVoice->pvSamplesBuffer)
- {
- RTMemFree(pVRDEVoice->pvSamplesBuffer);
- pVRDEVoice->pvSamplesBuffer = NULL;
- }
-
- if (pVRDEVoice->pvRateBuffer)
- {
- RTMemFree(pVRDEVoice->pvRateBuffer);
- pVRDEVoice->pvRateBuffer = NULL;
- }
-
- return VINF_SUCCESS;
-}
-
-/**
- * Construct a VRDE audio driver instance.
- *
- * @copydoc FNPDMDRVCONSTRUCT
- */
-/* static */
-DECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
-{
- PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
- LogRel(("Audio: Initializing VRDE driver\n"));
- LogFlowFunc(("fFlags=0x%x\n", fFlags));
-
- /* we save the address of AudioVideoRec in Object node in CFGM tree and address of VRDP server in
- * ObjectVRDPServer node. So presence of both is necessary.
- */
- //if (!CFGMR3AreValuesValid(pCfg, "Object\0") || !CFGMR3AreValuesValid(pCfg, "ObjectVRDPServer\0"))
- // return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
- AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
- ("Configuration error: Not possible to attach anything to this driver!\n"),
- VERR_PDM_DRVINS_NO_ATTACH);
-
- /*
- * Init the static parts.
- */
- pThis->pDrvIns = pDrvIns;
- /* IBase */
- pDrvIns->IBase.pfnQueryInterface = drvAudioVideoRecQueryInterface;
- /* IHostAudio */
- PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVideoRec);
-
- /* Get VRDPServer pointer. */
- void *pvUser;
- int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
- if (RT_FAILURE(rc))
- {
- AssertMsgFailed(("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc));
- return rc;
- }
-
- /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVideoRec. */
- pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
-
- pvUser = NULL;
- rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
- if (RT_FAILURE(rc))
- {
- AssertMsgFailed(("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc));
- return rc;
- }
-
- pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
- pThis->pAudioVideoRec->mpDrv = pThis;
-
- /*
- * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
- * Described in CFGM tree.
- */
- pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
- if (!pThis->pUpPort)
- {
- AssertMsgFailed(("Configuration error: No upper interface specified!\n"));
- return VERR_PDM_MISSING_INTERFACE_ABOVE;
- }
-
- return VINF_SUCCESS;
-}
-
-/* static */
-DECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
-{
- LogFlowFuncEnter();
-}
-
-/**
- * VRDE audio driver registration record.
- */
-const PDMDRVREG AudioVideoRec::DrvReg =
-{
- PDM_DRVREG_VERSION,
- /* szName */
- "AudioVideoRec",
- /* szRCMod */
- "",
- /* szR0Mod */
- "",
- /* pszDescription */
- "Audio driver for video recording",
- /* fFlags */
- PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
- /* fClass. */
- PDM_DRVREG_CLASS_AUDIO,
- /* cMaxInstances */
- ~0U,
- /* cbInstance */
- sizeof(DRVAUDIOVIDEOREC),
- /* pfnConstruct */
- AudioVideoRec::drvConstruct,
- /* pfnDestruct */
- AudioVideoRec::drvDestruct,
- /* pfnRelocate */
- NULL,
- /* pfnIOCtl */
- NULL,
- /* pfnPowerOn */
- NULL,
- /* pfnReset */
- NULL,
- /* pfnSuspend */
- NULL,
- /* pfnResume */
- NULL,
- /* pfnAttach */
- NULL,
- /* pfnDetach */
- NULL,
- /* pfnPowerOff */
- NULL,
- /* pfnSoftReset */
- NULL,
- /* u32EndVersion */
- PDM_DRVREG_VERSION
-};
-
diff --git a/src/VBox/Main/src-server/ApplianceImplExport.cpp b/src/VBox/Main/src-server/ApplianceImplExport.cpp
index 931d86d..7851f4d 100644
--- a/src/VBox/Main/src-server/ApplianceImplExport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplExport.cpp
@@ -347,7 +347,7 @@ HRESULT Machine::exportTo(const ComPtr<IAppliance> &aAppliance, const com::Utf8S
if (FAILED(rc)) throw rc;
Utf8Str strName = Utf8Str(locInfo.strPath).stripPath().stripSuffix();
- strTargetImageName = Utf8StrFmt("%s-disk%d.vmdk", strName.c_str(), ++pAppliance->m->cDisks);
+ strTargetImageName = Utf8StrFmt("%s-disk%.3d.vmdk", strName.c_str(), ++pAppliance->m->cDisks);
if (strTargetImageName.length() > RTTAR_NAME_MAX)
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Cannot attach disk '%s' -- file name too long"), strTargetImageName.c_str());
@@ -439,7 +439,7 @@ HRESULT Machine::exportTo(const ComPtr<IAppliance> &aAppliance, const com::Utf8S
continue;
Utf8Str strName = Utf8Str(locInfo.strPath).stripPath().stripSuffix();
- strTargetImageName = Utf8StrFmt("%s-disk%d.iso", strName.c_str(), ++pAppliance->m->cDisks);
+ strTargetImageName = Utf8StrFmt("%s-disk%.3d.iso", strName.c_str(), ++pAppliance->m->cDisks);
if (strTargetImageName.length() > RTTAR_NAME_MAX)
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Cannot attach image '%s' -- file name too long"), strTargetImageName.c_str());
@@ -902,7 +902,7 @@ void Appliance::i_buildXML(AutoWriteLockBase& writeLock,
// this list receives pointers to the XML elements in the machine XML which
// might have UUIDs that need fixing after we know the UUIDs of the exported images
std::list<xml::ElementNode*> llElementsWithUuidAttributes;
-
+ uint32_t ulFile = 1;
list< ComObjPtr<VirtualSystemDescription> >::const_iterator it;
/* Iterate through all virtual systems of that appliance */
for (it = m->virtualSystemDescriptions.begin();
@@ -916,157 +916,159 @@ void Appliance::i_buildXML(AutoWriteLockBase& writeLock,
vsdescThis,
enFormat,
stack); // disks and networks stack
- }
- // now, fill in the network section we set up empty above according
- // to the networks we found with the hardware items
- map<Utf8Str, bool>::const_iterator itN;
- for (itN = stack.mapNetworks.begin();
- itN != stack.mapNetworks.end();
- ++itN)
- {
- const Utf8Str &strNetwork = itN->first;
- xml::ElementNode *pelmNetwork = pelmNetworkSection->createChild("Network");
- pelmNetwork->setAttribute("ovf:name", strNetwork.c_str());
- pelmNetwork->createChild("Description")->addContent("Logical network used by this appliance.");
- }
+ list<Utf8Str> diskList;
+ list<Utf8Str>::const_iterator itS;
- // Finally, write out the disk info
- list<Utf8Str> diskList;
- map<Utf8Str, const VirtualSystemDescriptionEntry*>::const_iterator itS;
- uint32_t ulFile = 1;
- for (itS = stack.mapDisks.begin();
- itS != stack.mapDisks.end();
- ++itS)
- {
- const Utf8Str &strDiskID = itS->first;
- const VirtualSystemDescriptionEntry *pDiskEntry = itS->second;
+ for (itS = stack.mapDiskSequenceForOneVM.begin();
+ itS != stack.mapDiskSequenceForOneVM.end();
+ ++itS)
+ {
+ const Utf8Str &strDiskID = *itS;
+ const VirtualSystemDescriptionEntry *pDiskEntry = stack.mapDisks[strDiskID];
- // source path: where the VBox image is
- const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent;
- Bstr bstrSrcFilePath(strSrcFilePath);
+ // source path: where the VBox image is
+ const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent;
+ Bstr bstrSrcFilePath(strSrcFilePath);
- //skip empty Medium. There are no information to add into section <References> or <DiskSection>
- if (strSrcFilePath.isEmpty() ||
- pDiskEntry->skipIt == true)
- continue;
+ //skip empty Medium. There are no information to add into section <References> or <DiskSection>
+ if (strSrcFilePath.isEmpty() ||
+ pDiskEntry->skipIt == true)
+ continue;
- // Do NOT check here whether the file exists. FindMedium will figure
- // that out, and filesystem-based tests are simply wrong in the
- // general case (think of iSCSI).
+ // Do NOT check here whether the file exists. FindMedium will figure
+ // that out, and filesystem-based tests are simply wrong in the
+ // general case (think of iSCSI).
- // We need some info from the source disks
- ComPtr<IMedium> pSourceDisk;
- //DeviceType_T deviceType = DeviceType_HardDisk;// by default
+ // We need some info from the source disks
+ ComPtr<IMedium> pSourceDisk;
+ //DeviceType_T deviceType = DeviceType_HardDisk;// by default
- Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
+ Log(("Finding source disk \"%ls\"\n", bstrSrcFilePath.raw()));
- HRESULT rc;
+ HRESULT rc;
- if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)
- {
- rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
- DeviceType_HardDisk,
- AccessMode_ReadWrite,
- FALSE /* fForceNewUuid */,
- pSourceDisk.asOutParam());
- if (FAILED(rc))
- throw rc;
- }
- else if (pDiskEntry->type == VirtualSystemDescriptionType_CDROM)//may be, this is CD/DVD
- {
- rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
- DeviceType_DVD,
- AccessMode_ReadOnly,
- FALSE,
- pSourceDisk.asOutParam());
- if (FAILED(rc))
- throw rc;
- }
+ if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)
+ {
+ rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
+ DeviceType_HardDisk,
+ AccessMode_ReadWrite,
+ FALSE /* fForceNewUuid */,
+ pSourceDisk.asOutParam());
+ if (FAILED(rc))
+ throw rc;
+ }
+ else if (pDiskEntry->type == VirtualSystemDescriptionType_CDROM)//may be, this is CD/DVD
+ {
+ rc = mVirtualBox->OpenMedium(bstrSrcFilePath.raw(),
+ DeviceType_DVD,
+ AccessMode_ReadOnly,
+ FALSE,
+ pSourceDisk.asOutParam());
+ if (FAILED(rc))
+ throw rc;
+ }
- Bstr uuidSource;
- rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam());
- if (FAILED(rc)) throw rc;
- Guid guidSource(uuidSource);
+ Bstr uuidSource;
+ rc = pSourceDisk->COMGETTER(Id)(uuidSource.asOutParam());
+ if (FAILED(rc)) throw rc;
+ Guid guidSource(uuidSource);
- // output filename
- const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf;
- // target path needs to be composed from where the output OVF is
- Utf8Str strTargetFilePath(strPath);
- strTargetFilePath.stripFilename();
- strTargetFilePath.append("/");
- strTargetFilePath.append(strTargetFileNameOnly);
+ // output filename
+ const Utf8Str &strTargetFileNameOnly = pDiskEntry->strOvf;
+ // target path needs to be composed from where the output OVF is
+ Utf8Str strTargetFilePath(strPath);
+ strTargetFilePath.stripFilename();
+ strTargetFilePath.append("/");
+ strTargetFilePath.append(strTargetFileNameOnly);
- // We are always exporting to VMDK stream optimized for now
- //Bstr bstrSrcFormat = L"VMDK";//not used
+ // We are always exporting to VMDK stream optimized for now
+ //Bstr bstrSrcFormat = L"VMDK";//not used
- diskList.push_back(strTargetFilePath);
+ diskList.push_back(strTargetFilePath);
- LONG64 cbCapacity = 0; // size reported to guest
- rc = pSourceDisk->COMGETTER(LogicalSize)(&cbCapacity);
- if (FAILED(rc)) throw rc;
- /// @todo r=poetzsch: wrong it is reported in bytes ...
- // capacity is reported in megabytes, so...
- //cbCapacity *= _1M;
-
- Guid guidTarget; /* Creates a new uniq number for the target disk. */
- guidTarget.create();
-
- // now handle the XML for the disk:
- Utf8StrFmt strFileRef("file%RI32", ulFile++);
- // <File ovf:href="WindowsXpProfessional-disk1.vmdk" ovf:id="file1" ovf:size="1710381056"/>
- xml::ElementNode *pelmFile = pelmReferences->createChild("File");
- pelmFile->setAttribute("ovf:href", strTargetFileNameOnly);
- pelmFile->setAttribute("ovf:id", strFileRef);
- /// @todo the actual size is not available at this point of time,
- // cause the disk will be compressed. The 1.0 standard says this is
- // optional! 1.1 isn't fully clear if the "gzip" format is used.
- // Need to be checked. */
- // pelmFile->setAttribute("ovf:size", Utf8StrFmt("%RI64", cbFile).c_str());
-
- // add disk to XML Disks section
- // <Disk ovf:capacity="8589934592" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="..."/>
- xml::ElementNode *pelmDisk = pelmDiskSection->createChild("Disk");
- pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str());
- pelmDisk->setAttribute("ovf:diskId", strDiskID);
- pelmDisk->setAttribute("ovf:fileRef", strFileRef);
-
- if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)//deviceType == DeviceType_HardDisk
- {
- pelmDisk->setAttribute("ovf:format",
- (enFormat == ovf::OVFVersion_0_9)
- ? "http://www.vmware.com/specifications/vmdk.html#sparse" // must be sparse or ovftool ch
- : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"
- // correct string as communicated to us by VMware (public bug #6612)
- );
- }
- else //pDiskEntry->type == VirtualSystemDescriptionType_CDROM, deviceType == DeviceType_DVD
- {
- pelmDisk->setAttribute("ovf:format",
- "http://www.ecma-international.org/publications/standards/Ecma-119.htm"
- );
- }
+ LONG64 cbCapacity = 0; // size reported to guest
+ rc = pSourceDisk->COMGETTER(LogicalSize)(&cbCapacity);
+ if (FAILED(rc)) throw rc;
+ /// @todo r=poetzsch: wrong it is reported in bytes ...
+ // capacity is reported in megabytes, so...
+ //cbCapacity *= _1M;
+
+ Guid guidTarget; /* Creates a new uniq number for the target disk. */
+ guidTarget.create();
+
+ // now handle the XML for the disk:
+ Utf8StrFmt strFileRef("file%RI32", ulFile++);
+ // <File ovf:href="WindowsXpProfessional-disk1.vmdk" ovf:id="file1" ovf:size="1710381056"/>
+ xml::ElementNode *pelmFile = pelmReferences->createChild("File");
+ pelmFile->setAttribute("ovf:id", strFileRef);
+ pelmFile->setAttribute("ovf:href", strTargetFileNameOnly);
+ /// @todo the actual size is not available at this point of time,
+ // cause the disk will be compressed. The 1.0 standard says this is
+ // optional! 1.1 isn't fully clear if the "gzip" format is used.
+ // Need to be checked. */
+ // pelmFile->setAttribute("ovf:size", Utf8StrFmt("%RI64", cbFile).c_str());
+
+ // add disk to XML Disks section
+ // <Disk ovf:capacity="8589934592" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="..."/>
+ xml::ElementNode *pelmDisk = pelmDiskSection->createChild("Disk");
+ pelmDisk->setAttribute("ovf:capacity", Utf8StrFmt("%RI64", cbCapacity).c_str());
+ pelmDisk->setAttribute("ovf:diskId", strDiskID);
+ pelmDisk->setAttribute("ovf:fileRef", strFileRef);
+
+ if (pDiskEntry->type == VirtualSystemDescriptionType_HardDiskImage)//deviceType == DeviceType_HardDisk
+ {
+ pelmDisk->setAttribute("ovf:format",
+ (enFormat == ovf::OVFVersion_0_9)
+ ? "http://www.vmware.com/specifications/vmdk.html#sparse" // must be sparse or ovftoo
+ : "http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"
+ // correct string as communicated to us by VMware (public bug #6612)
+ );
+ }
+ else //pDiskEntry->type == VirtualSystemDescriptionType_CDROM, deviceType == DeviceType_DVD
+ {
+ pelmDisk->setAttribute("ovf:format",
+ "http://www.ecma-international.org/publications/standards/Ecma-119.htm"
+ );
+ }
- // add the UUID of the newly target image to the OVF disk element, but in the
- // vbox: namespace since it's not part of the standard
- pelmDisk->setAttribute("vbox:uuid", Utf8StrFmt("%RTuuid", guidTarget.raw()).c_str());
-
- // now, we might have other XML elements from vbox:Machine pointing to this image,
- // but those would refer to the UUID of the _source_ image (which we created the
- // export image from); those UUIDs need to be fixed to the export image
- Utf8Str strGuidSourceCurly = guidSource.toStringCurly();
- for (std::list<xml::ElementNode*>::iterator eit = llElementsWithUuidAttributes.begin();
- eit != llElementsWithUuidAttributes.end();
- ++eit)
- {
- xml::ElementNode *pelmImage = *eit;
- Utf8Str strUUID;
- pelmImage->getAttributeValue("uuid", strUUID);
- if (strUUID == strGuidSourceCurly)
- // overwrite existing uuid attribute
- pelmImage->setAttribute("uuid", guidTarget.toStringCurly());
+ // add the UUID of the newly target image to the OVF disk element, but in the
+ // vbox: namespace since it's not part of the standard
+ pelmDisk->setAttribute("vbox:uuid", Utf8StrFmt("%RTuuid", guidTarget.raw()).c_str());
+
+ // now, we might have other XML elements from vbox:Machine pointing to this image,
+ // but those would refer to the UUID of the _source_ image (which we created the
+ // export image from); those UUIDs need to be fixed to the export image
+ Utf8Str strGuidSourceCurly = guidSource.toStringCurly();
+ for (std::list<xml::ElementNode*>::iterator eit = llElementsWithUuidAttributes.begin();
+ eit != llElementsWithUuidAttributes.end();
+ ++eit)
+ {
+ xml::ElementNode *pelmImage = *eit;
+ Utf8Str strUUID;
+ pelmImage->getAttributeValue("uuid", strUUID);
+ if (strUUID == strGuidSourceCurly)
+ // overwrite existing uuid attribute
+ pelmImage->setAttribute("uuid", guidTarget.toStringCurly());
+ }
}
+ llElementsWithUuidAttributes.clear();
+ stack.mapDiskSequenceForOneVM.clear();
}
+
+ // now, fill in the network section we set up empty above according
+ // to the networks we found with the hardware items
+ map<Utf8Str, bool>::const_iterator itN;
+ for (itN = stack.mapNetworks.begin();
+ itN != stack.mapNetworks.end();
+ ++itN)
+ {
+ const Utf8Str &strNetwork = itN->first;
+ xml::ElementNode *pelmNetwork = pelmNetworkSection->createChild("Network");
+ pelmNetwork->setAttribute("ovf:name", strNetwork.c_str());
+ pelmNetwork->createChild("Description")->addContent("Logical network used by this appliance.");
+ }
+
}
/**
@@ -1545,6 +1547,11 @@ void Appliance::i_buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
desc.strExtraConfigCurrent.c_str());
stack.mapDisks[strDiskID] = &desc;
+
+ //use the list stack.mapDiskSequence where the disks go as the "VirtualSystem" should be placed
+ //in the OVF description file.
+ stack.mapDiskSequence.push_back(strDiskID);
+ stack.mapDiskSequenceForOneVM.push_back(strDiskID);
}
break;
@@ -1570,9 +1577,9 @@ void Appliance::i_buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
</Item> */
if (uLoop == 2)
{
- //uint32_t cDisks = stack.mapDisks.size();
- Utf8Str strDiskID = Utf8StrFmt("iso%RI32", ++cDVDs);
-
+ uint32_t cDisks = (uint32_t)stack.mapDisks.size();
+ Utf8Str strDiskID = Utf8StrFmt("iso%RI32", ++cDisks);
+ ++cDVDs;
strDescription = "CD-ROM Drive";
strCaption = Utf8StrFmt("cdrom%RI32", cDVDs); // OVFTool starts with 1
type = ovf::ResourceType_CDDrive; // 15
@@ -1617,6 +1624,11 @@ void Appliance::i_buildXMLForOneVirtualSystem(AutoWriteLockBase& writeLock,
desc.strExtraConfigCurrent.c_str());
stack.mapDisks[strDiskID] = &desc;
+
+ //use the list stack.mapDiskSequence where the disks go as the "VirtualSystem" should be placed
+ //in the OVF description file.
+ stack.mapDiskSequence.push_back(strDiskID);
+ stack.mapDiskSequenceForOneVM.push_back(strDiskID);
// there is no DVD drive map to update because it is
// handled completely with this entry.
}
@@ -2146,12 +2158,18 @@ HRESULT Appliance::i_writeFSImpl(TaskOVF *pTask, AutoWriteLockBase& writeLock, P
}
// Finally, write out the disks!
- map<Utf8Str, const VirtualSystemDescriptionEntry*>::const_iterator itS;
- for (itS = stack.mapDisks.begin();
- itS != stack.mapDisks.end();
- ++itS)
+ //use the list stack.mapDiskSequence where the disks were put as the "VirtualSystem"s had been placed
+ //in the OVF description file. I.e. we have one "VirtualSystem" in the OVF file, we extract all disks
+ //attached to it. And these disks are stored in the stack.mapDiskSequence. Next we shift to the next
+ //"VirtualSystem" and repeat the operation.
+ //And here we go through the list and extract all disks in the same sequence
+ list<Utf8Str>::const_iterator itS;
+ for (itS = stack.mapDiskSequence.begin();
+ itS != stack.mapDiskSequence.end();
+ ++itS)
{
- const VirtualSystemDescriptionEntry *pDiskEntry = itS->second;
+ const Utf8Str &strDiskID = *itS;
+ const VirtualSystemDescriptionEntry *pDiskEntry = stack.mapDisks[strDiskID];
// source path: where the VBox image is
const Utf8Str &strSrcFilePath = pDiskEntry->strVBoxCurrent;
diff --git a/src/VBox/Main/src-server/ApplianceImplImport.cpp b/src/VBox/Main/src-server/ApplianceImplImport.cpp
index 01a9024..79e1de7 100644
--- a/src/VBox/Main/src-server/ApplianceImplImport.cpp
+++ b/src/VBox/Main/src-server/ApplianceImplImport.cpp
@@ -3332,7 +3332,7 @@ l_skipped:
mhda.lDevice);
Log(("Attaching disk %s to port %d on device %d\n",
- vsdeTargetHD->strVBoxCurrent.c_str(), mhda.lControllerPort, mhda.lDevice));
+ vsdeTargetHD->strVBoxCurrent.c_str(), mhda.lControllerPort, mhda.lDevice));
ComObjPtr<MediumFormat> mediumFormat;
rc = i_findMediumFormatFromDiskImage(diCurrent, mediumFormat);
@@ -3557,7 +3557,7 @@ void Appliance::i_importVBoxMachine(ComObjPtr<VirtualSystemDescription> &vsdescT
if ( vsdeNW->strExtraConfigCurrent.startsWith("slot=", Utf8Str::CaseInsensitive)
&& vsdeNW->strExtraConfigCurrent.length() > 6)
{
- uint32_t iSlot = vsdeNW->strExtraConfigCurrent.substr(5, 1).toUInt32();
+ uint32_t iSlot = vsdeNW->strExtraConfigCurrent.substr(5).toUInt32();
/* Iterate through all network adapters in the machine config. */
for (it1 = llNetworkAdapters.begin();
it1 != llNetworkAdapters.end();
@@ -3748,6 +3748,7 @@ l_skipped:
* Again iterate over all given disk images of the virtual system
* disks description using the found disk image
*/
+ vsdeTargetHD = NULL;
for (list<VirtualSystemDescriptionEntry*>::const_iterator itHD = avsdeHDs.begin();
itHD != avsdeHDs.end();
++itHD)
diff --git a/src/VBox/Main/src-server/DHCPServerImpl.cpp b/src/VBox/Main/src-server/DHCPServerImpl.cpp
index 56cfa5b..3d99a66 100644
--- a/src/VBox/Main/src-server/DHCPServerImpl.cpp
+++ b/src/VBox/Main/src-server/DHCPServerImpl.cpp
@@ -23,6 +23,8 @@
#include "AutoCaller.h"
#include "Logging.h"
+#include <iprt/asm.h>
+#include <iprt/net.h>
#include <iprt/cpp/utils.h>
#include <VBox/com/array.h>
@@ -254,10 +256,82 @@ HRESULT DHCPServer::setConfiguration(const com::Utf8Str &aIPAddress,
const com::Utf8Str &aLowerIP,
const com::Utf8Str &aUpperIP)
{
- AssertReturn(!aIPAddress.isEmpty(), E_INVALIDARG);
- AssertReturn(!aNetworkMask.isEmpty(), E_INVALIDARG);
- AssertReturn(!aLowerIP.isEmpty(), E_INVALIDARG);
- AssertReturn(!aUpperIP.isEmpty(), E_INVALIDARG);
+ RTNETADDRIPV4 IPAddress, NetworkMask, LowerIP, UpperIP;
+ int rc;
+
+ rc = RTNetStrToIPv4Addr(aIPAddress.c_str(), &IPAddress);
+ if (RT_FAILURE(rc))
+ return mVirtualBox->setErrorBoth(E_INVALIDARG, rc,
+ "Invalid server address");
+
+ rc = RTNetStrToIPv4Addr(aNetworkMask.c_str(), &NetworkMask);
+ if (RT_FAILURE(rc))
+ return mVirtualBox->setErrorBoth(E_INVALIDARG, rc,
+ "Invalid netmask");
+
+ rc = RTNetStrToIPv4Addr(aLowerIP.c_str(), &LowerIP);
+ if (RT_FAILURE(rc))
+ return mVirtualBox->setErrorBoth(E_INVALIDARG, rc,
+ "Invalid range lower address");
+
+ rc = RTNetStrToIPv4Addr(aUpperIP.c_str(), &UpperIP);
+ if (RT_FAILURE(rc))
+ return mVirtualBox->setErrorBoth(E_INVALIDARG, rc,
+ "Invalid range upper address");
+
+ /*
+ * Insist on continuous mask. May be also accept prefix length
+ * here or address/prefix for aIPAddress?
+ */
+ rc = RTNetMaskToPrefixIPv4(&NetworkMask, NULL);
+ if (RT_FAILURE(rc))
+ return mVirtualBox->setErrorBoth(E_INVALIDARG, rc,
+ "Invalid netmask");
+
+ /* It's more convenient to convert to host order once */
+ IPAddress.u = RT_N2H_U32(IPAddress.u);
+ NetworkMask.u = RT_N2H_U32(NetworkMask.u);
+ LowerIP.u = RT_N2H_U32(LowerIP.u);
+ UpperIP.u = RT_N2H_U32(UpperIP.u);
+
+ /*
+ * Addresses must be unicast and from the same network
+ */
+ if ( (IPAddress.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
+ || (IPAddress.u & ~NetworkMask.u) == 0
+ || ((IPAddress.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
+ {
+ return mVirtualBox->setError(E_INVALIDARG,
+ "Invalid server address");
+ }
+
+ if ( (LowerIP.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
+ || (LowerIP.u & NetworkMask.u) != (IPAddress.u &NetworkMask.u)
+ || (LowerIP.u & ~NetworkMask.u) == 0
+ || ((LowerIP.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
+ {
+ return mVirtualBox->setError(E_INVALIDARG,
+ "Invalid range lower address");
+ }
+
+ if ( (UpperIP.u & UINT32_C(0xe0000000)) == UINT32_C(0xe0000000)
+ || (UpperIP.u & NetworkMask.u) != (IPAddress.u &NetworkMask.u)
+ || (UpperIP.u & ~NetworkMask.u) == 0
+ || ((UpperIP.u & ~NetworkMask.u) | NetworkMask.u) == UINT32_C(0xffffffff))
+ {
+ return mVirtualBox->setError(E_INVALIDARG,
+ "Invalid range upper address");
+ }
+
+ /* The range should be valid ... */
+ if (LowerIP.u > UpperIP.u)
+ return mVirtualBox->setError(E_INVALIDARG,
+ "Invalid range bounds");
+
+ /* ... and shouldn't contain the server's address */
+ if (LowerIP.u <= IPAddress.u && IPAddress.u <= UpperIP.u)
+ return mVirtualBox->setError(E_INVALIDARG,
+ "Server address within range bounds");
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
m->IPAddress = aIPAddress;
diff --git a/src/VBox/Main/src-server/HostImpl.cpp b/src/VBox/Main/src-server/HostImpl.cpp
index 928514a..3c72427 100644
--- a/src/VBox/Main/src-server/HostImpl.cpp
+++ b/src/VBox/Main/src-server/HostImpl.cpp
@@ -1781,6 +1781,7 @@ HRESULT Host::i_saveSettings(settings::Host &data)
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
data.llUSBDeviceFilters.clear();
+ data.llUSBDeviceSources.clear();
for (USBDeviceFilterList::const_iterator it = m->llUSBDeviceFilters.begin();
it != m->llUSBDeviceFilters.end();
diff --git a/src/VBox/Main/src-server/MachineImpl.cpp b/src/VBox/Main/src-server/MachineImpl.cpp
index 0198019..320c569 100644
--- a/src/VBox/Main/src-server/MachineImpl.cpp
+++ b/src/VBox/Main/src-server/MachineImpl.cpp
@@ -12542,7 +12542,9 @@ void SessionMachine::uninit(Uninit::Reason aReason)
* accessing any members (and before AutoUninitSpan that does it as well).
* This self reference will be released as the very last step on return.
*/
- ComObjPtr<SessionMachine> selfRef = this;
+ ComObjPtr<SessionMachine> selfRef;
+ if (aReason != Uninit::Unexpected)
+ selfRef = this;
/* Enclose the state transition Ready->InUninit->NotReady */
AutoUninitSpan autoUninitSpan(this);
diff --git a/src/VBox/Main/src-server/MediumImpl.cpp b/src/VBox/Main/src-server/MediumImpl.cpp
index 64464ef..9e83858 100644
--- a/src/VBox/Main/src-server/MediumImpl.cpp
+++ b/src/VBox/Main/src-server/MediumImpl.cpp
@@ -1588,7 +1588,7 @@ void Medium::uninit()
* object locks, i.e. the medium caller may have to be released and be
* re-acquired in the right place later. See Medium::getParent() for sample
* code how to do this safely. */
- ComObjPtr<VirtualBox> pVirtualBox(m->pVirtualBox);
+ VirtualBox *pVirtualBox = m->pVirtualBox;
if (!pVirtualBox)
return;
diff --git a/src/VBox/Main/src-server/USBProxyBackend.cpp b/src/VBox/Main/src-server/USBProxyBackend.cpp
index a9ce0c3..75e6614 100644
--- a/src/VBox/Main/src-server/USBProxyBackend.cpp
+++ b/src/VBox/Main/src-server/USBProxyBackend.cpp
@@ -65,8 +65,11 @@ void USBProxyBackend::FinalRelease()
/**
* Stub needed as long as the class isn't virtual
*/
-int USBProxyBackend::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress)
+int USBProxyBackend::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings)
{
+ RT_NOREF1(fLoadingSettings);
+
m_pUsbProxyService = pUsbProxyService;
mThread = NIL_RTTHREAD;
mTerminate = false;
@@ -524,19 +527,19 @@ USBProxyBackend::initFilterFromDevice(PUSBFILTER aFilter, HostUSBDevice *aDevice
if (pDev->pszSerialNumber)
{
vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_SERIAL_NUMBER_STR, pDev->pszSerialNumber,
- true /*fMustBePresent*/, false /*fPurge*/);
+ true /*fMustBePresent*/, true /*fPurge*/);
AssertRC(vrc);
}
if (pDev->pszProduct)
{
vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_PRODUCT_STR, pDev->pszProduct,
- true /*fMustBePresent*/, false /*fPurge*/);
+ true /*fMustBePresent*/, true /*fPurge*/);
AssertRC(vrc);
}
if (pDev->pszManufacturer)
{
vrc = USBFilterSetStringExact(aFilter, USBFILTERIDX_MANUFACTURER_STR, pDev->pszManufacturer,
- true /*fMustBePresent*/, false /*fPurge*/);
+ true /*fMustBePresent*/, true /*fPurge*/);
AssertRC(vrc);
}
}
diff --git a/src/VBox/Main/src-server/USBProxyService.cpp b/src/VBox/Main/src-server/USBProxyService.cpp
index 14252e2..d5200f8 100644
--- a/src/VBox/Main/src-server/USBProxyService.cpp
+++ b/src/VBox/Main/src-server/USBProxyService.cpp
@@ -80,7 +80,7 @@ HRESULT USBProxyService::init(void)
ComObjPtr<USBProxyBackend> UsbProxyBackendHost;
# endif
UsbProxyBackendHost.createObject();
- int vrc = UsbProxyBackendHost->init(this, Utf8Str("host"), Utf8Str(""));
+ int vrc = UsbProxyBackendHost->init(this, Utf8Str("host"), Utf8Str(""), false /* fLoadingSettings */);
if (RT_FAILURE(vrc))
{
mLastError = vrc;
@@ -211,7 +211,8 @@ HRESULT USBProxyService::addUSBDeviceSource(const com::Utf8Str &aBackend, const
{
AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
- HRESULT hrc = createUSBDeviceSource(aBackend, aId, aAddress, aPropertyNames, aPropertyValues);
+ HRESULT hrc = createUSBDeviceSource(aBackend, aId, aAddress, aPropertyNames,
+ aPropertyValues, false /* fLoadingSettings */);
if (SUCCEEDED(hrc))
{
alock.release();
@@ -496,7 +497,8 @@ HRESULT USBProxyService::i_loadSettings(const settings::USBDeviceSourcesList &ll
{
std::vector<com::Utf8Str> vecPropNames, vecPropValues;
const settings::USBDeviceSource &src = *it;
- hrc = createUSBDeviceSource(src.strBackend, src.strName, src.strAddress, vecPropNames, vecPropValues);
+ hrc = createUSBDeviceSource(src.strBackend, src.strName, src.strAddress,
+ vecPropNames, vecPropValues, true /* fLoadingSettings */);
}
return hrc;
@@ -887,10 +889,13 @@ ComObjPtr<HostUSBDevice> USBProxyService::findDeviceById(IN_GUID aId)
* @param aAddress The backend specific address.
* @param aPropertyNames Vector of optional property keys the backend supports.
* @param aPropertyValues Vector of optional property values the backend supports.
+ * @param fLoadingSettings Flag whether the USB device source is created while the
+ * settings are loaded or through the Main API.
*/
HRESULT USBProxyService::createUSBDeviceSource(const com::Utf8Str &aBackend, const com::Utf8Str &aId,
const com::Utf8Str &aAddress, const std::vector<com::Utf8Str> &aPropertyNames,
- const std::vector<com::Utf8Str> &aPropertyValues)
+ const std::vector<com::Utf8Str> &aPropertyValues,
+ bool fLoadingSettings)
{
HRESULT hrc = S_OK;
@@ -918,7 +923,7 @@ HRESULT USBProxyService::createUSBDeviceSource(const com::Utf8Str &aBackend, con
ComObjPtr<USBProxyBackendUsbIp> UsbProxyBackend;
UsbProxyBackend.createObject();
- int vrc = UsbProxyBackend->init(this, aId, aAddress);
+ int vrc = UsbProxyBackend->init(this, aId, aAddress, fLoadingSettings);
if (RT_FAILURE(vrc))
hrc = setError(E_FAIL,
tr("Creating the USB device source \"%s\" using backend \"%s\" failed with %Rrc"),
@@ -941,7 +946,7 @@ HRESULT USBProxyService::setError(HRESULT aResultCode, const char *aText, ...)
HRESULT rc = VirtualBoxBase::setErrorInternal(aResultCode,
COM_IIDOF(IHost),
"USBProxyService",
- Utf8StrFmt(aText, va),
+ Utf8Str(aText, va),
false /* aWarning*/,
true /* aLogIt*/);
va_end(va);
diff --git a/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp b/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp
index ed04194..71a1104 100644
--- a/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp
+++ b/src/VBox/Main/src-server/darwin/USBProxyBackendDarwin.cpp
@@ -52,9 +52,10 @@ USBProxyBackendDarwin::~USBProxyBackendDarwin()
*
* @returns VBox status code.
*/
-int USBProxyBackendDarwin::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress)
+int USBProxyBackendDarwin::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings)
{
- USBProxyBackend::init(pUsbProxyService, strId, strAddress);
+ USBProxyBackend::init(pUsbProxyService, strId, strAddress, fLoadingSettings);
unconst(m_strBackend) = Utf8Str("host");
diff --git a/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp b/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp
index 736d8d9..19b023f 100644
--- a/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp
+++ b/src/VBox/Main/src-server/freebsd/USBProxyBackendFreeBSD.cpp
@@ -75,9 +75,10 @@ USBProxyBackendFreeBSD::~USBProxyBackendFreeBSD()
*
* @returns S_OK on success and non-fatal failures, some COM error otherwise.
*/
-int USBProxyBackendFreeBSD::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress)
+int USBProxyBackendFreeBSD::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings)
{
- USBProxyBackend::init(pUsbProxyService, strId, strAddress);
+ USBProxyBackend::init(pUsbProxyService, strId, strAddress, fLoadingSettings);
unconst(m_strBackend) = Utf8Str("host");
diff --git a/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp b/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp
index 56bde71..edef13d 100644
--- a/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp
+++ b/src/VBox/Main/src-server/generic/USBProxyBackendUsbIp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2015-2016 Oracle Corporation
+ * Copyright (C) 2015-2017 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -38,6 +38,7 @@
#include <iprt/pipe.h>
#include <iprt/asm.h>
#include <iprt/cdefs.h>
+#include <iprt/time.h>
/** The USB/IP default port to connect to. */
#define USBIP_PORT_DEFAULT 3240
@@ -243,6 +244,8 @@ struct USBProxyBackendUsbIp::Data
PUSBDEVICE *ppNext;
/** Current amount of devices in the list. */
uint32_t cDevicesCur;
+ /** Timestamp of the last time we successfully connected. */
+ uint64_t tsConnectSuccessLast;
};
/**
@@ -279,16 +282,19 @@ USBProxyBackendUsbIp::~USBProxyBackendUsbIp()
*
* @returns S_OK on success and non-fatal failures, some COM error otherwise.
*/
-int USBProxyBackendUsbIp::init(USBProxyService *aUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress)
+int USBProxyBackendUsbIp::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings)
{
int rc = VINF_SUCCESS;
- USBProxyBackend::init(aUsbProxyService, strId, strAddress);
+ USBProxyBackend::init(pUsbProxyService, strId, strAddress, fLoadingSettings);
unconst(m_strBackend) = Utf8Str("USBIP");
m = new Data;
+ m->tsConnectSuccessLast = 0;
+
/* Split address into hostname and port. */
RTCList<RTCString> lstAddress = strAddress.split(":");
if (lstAddress.size() < 1)
@@ -317,9 +323,17 @@ int USBProxyBackendUsbIp::init(USBProxyService *aUsbProxyService, const com::Utf
RTPOLL_EVT_READ, USBIP_POLL_ID_PIPE);
if (RT_SUCCESS(rc))
{
- /* Connect to the USB/IP host. */
+ /*
+ * Connect to the USB/IP host. Be more graceful to connection errors
+ * if we are instantiated while the settings are loaded to let
+ * VBoxSVC start.
+ *
+ * The worker thread keeps trying to connect every few seconds until
+ * either the USB source is removed by the user or the USB server is
+ * reachable.
+ */
rc = reconnect();
- if (RT_SUCCESS(rc))
+ if (RT_SUCCESS(rc) || fLoadingSettings)
rc = start(); /* Start service thread. */
}
@@ -445,12 +459,16 @@ int USBProxyBackendUsbIp::wait(RTMSINTERVAL aMillies)
int rc = VINF_SUCCESS;
bool fDeviceListChangedOrWokenUp = false;
+ /* Don't start any possibly lengthy operation if we are supposed to return immediately again. */
+ if (!aMillies)
+ return VINF_SUCCESS;
+
/* Try to reconnect once when we enter if we lost the connection earlier. */
if (m->hSocket == NIL_RTSOCKET)
- rc = reconnect();
+ reconnect();
/* Query a new device list upon entering. */
- if ( RT_SUCCESS(rc)
+ if ( m->hSocket != NIL_RTSOCKET
&& m->enmRecvState == kUsbIpRecvState_None)
{
rc = startListExportedDevicesReq();
@@ -473,9 +491,9 @@ int USBProxyBackendUsbIp::wait(RTMSINTERVAL aMillies)
uint32_t uIdReady = 0;
uint32_t fEventsRecv = 0;
- /* Limit the waiting time to 1sec so we can either reconnect or get a new device list. */
+ /* Limit the waiting time to 3sec so we can either reconnect or get a new device list. */
if (m->hSocket == NIL_RTSOCKET || m->enmRecvState == kUsbIpRecvState_None)
- msWait = RT_MIN(1000, aMillies);
+ msWait = RT_MIN(3000, aMillies);
rc = RTPoll(m->hPollSet, msWait, &fEventsRecv, &uIdReady);
if (RT_SUCCESS(rc))
@@ -540,10 +558,20 @@ int USBProxyBackendUsbIp::wait(RTMSINTERVAL aMillies)
{
/* Try to reconnect and start a new request if we lost the connection before. */
if (m->hSocket == NIL_RTSOCKET)
+ {
rc = reconnect();
-
- if (RT_SUCCESS(rc))
- rc = startListExportedDevicesReq();
+ if (RT_SUCCESS(rc))
+ rc = startListExportedDevicesReq();
+ else if ( rc == VERR_NET_SHUTDOWN
+ || rc == VERR_BROKEN_PIPE
+ || rc == VERR_NET_CONNECTION_RESET_BY_PEER
+ || rc == VERR_NET_CONNECTION_REFUSED)
+ {
+ if (hasDevListChanged(m->pHead))
+ fDeviceListChangedOrWokenUp = true;
+ rc = VINF_SUCCESS;
+ }
+ }
}
}
}
@@ -705,7 +733,22 @@ int USBProxyBackendUsbIp::reconnect()
m->hSocket = NIL_RTSOCKET;
}
else
+ {
LogFlowFunc(("Connected to host \"%s\"\n", m->pszHost));
+ m->tsConnectSuccessLast = RTTimeMilliTS();
+ }
+ }
+ else if (m->tsConnectSuccessLast + 10 * RT_MS_1SEC < RTTimeMilliTS())
+ {
+ /* Make sure the device list is clear if we failed to reconnect for some time. */
+ RTSemFastMutexRequest(m->hMtxDevices);
+ if (m->pUsbDevicesCur)
+ {
+ freeDeviceList(m->pUsbDevicesCur);
+ m->cUsbDevicesCur = 0;
+ m->pUsbDevicesCur = NULL;
+ }
+ RTSemFastMutexRelease(m->hMtxDevices);
}
LogFlowFunc(("returns rc=%Rrc\n", rc));
@@ -808,14 +851,13 @@ int USBProxyBackendUsbIp::receiveData()
LogFlowFunc(("RTTcpReadNB(%#p, %#p, %zu, %zu) -> %Rrc\n",
m->hSocket, m->pbRecvBuf, m->cbResidualRecv, cbRecvd, rc));
- if (rc == VINF_SUCCESS)
+ if ( rc == VINF_SUCCESS
+ && cbRecvd > 0)
{
- Assert(cbRecvd > 0);
m->cbResidualRecv -= cbRecvd;
m->pbRecvBuf += cbRecvd;
/* In case we received everything for the current state process the data. */
- if ( !m->cbResidualRecv
- && cbRecvd > 0)
+ if (!m->cbResidualRecv)
{
rc = processData();
if ( RT_SUCCESS(rc)
diff --git a/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp b/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp
index 6218576..6cb1d2d 100644
--- a/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp
+++ b/src/VBox/Main/src-server/linux/USBProxyBackendLinux.cpp
@@ -79,9 +79,10 @@ USBProxyBackendLinux::~USBProxyBackendLinux()
*
* @returns VBox status code.
*/
-int USBProxyBackendLinux::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress)
+int USBProxyBackendLinux::init(USBProxyService *pUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings)
{
- USBProxyBackend::init(pUsbProxyService, strId, strAddress);
+ USBProxyBackend::init(pUsbProxyService, strId, strAddress, fLoadingSettings);
unconst(m_strBackend) = Utf8Str("host");
diff --git a/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp b/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp
index c3aab8c..cf7e7fa 100644
--- a/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp
+++ b/src/VBox/Main/src-server/solaris/USBProxyBackendSolaris.cpp
@@ -69,9 +69,10 @@ USBProxyBackendSolaris::~USBProxyBackendSolaris()
*
* @returns VBox status code.
*/
-int USBProxyBackendSolaris::init(USBProxyService *aUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress)
+int USBProxyBackendSolaris::init(USBProxyService *aUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings)
{
- USBProxyBackend::init(aUsbProxyService, strId, strAddress);
+ USBProxyBackend::init(aUsbProxyService, strId, strAddress, fLoadingSettings);
unconst(m_strBackend) = Utf8Str("host");
diff --git a/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp b/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp
index 599af5b..60048bb 100644
--- a/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp
+++ b/src/VBox/Main/src-server/win/USBProxyBackendWindows.cpp
@@ -52,9 +52,10 @@ USBProxyBackendWindows::~USBProxyBackendWindows()
*
* @returns S_OK on success and non-fatal failures, some COM error otherwise.
*/
-int USBProxyBackendWindows::init(USBProxyService *aUsbProxyService, const com::Utf8Str &strId, const com::Utf8Str &strAddress)
+int USBProxyBackendWindows::init(USBProxyService *aUsbProxyService, const com::Utf8Str &strId,
+ const com::Utf8Str &strAddress, bool fLoadingSettings)
{
- USBProxyBackend::init(aUsbProxyService, strId, strAddress);
+ USBProxyBackend::init(aUsbProxyService, strId, strAddress, fLoadingSettings);
unconst(m_strBackend) = Utf8Str("host");
diff --git a/src/VBox/Main/src-server/win/svcmain.cpp b/src/VBox/Main/src-server/win/svcmain.cpp
index 3993bf7..62d52fe 100644
--- a/src/VBox/Main/src-server/win/svcmain.cpp
+++ b/src/VBox/Main/src-server/win/svcmain.cpp
@@ -143,7 +143,7 @@ BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_VirtualBox, VirtualBox)
END_OBJECT_MAP()
-CExeModule _Module;
+CExeModule* g_pModule = NULL;
HWND g_hMainWindow = NULL;
HINSTANCE g_hInstance = NULL;
#define MAIN_WND_CLASS L"VirtualBox Interface"
@@ -190,17 +190,20 @@ LRESULT CALLBACK WinMainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lPara
{
case WM_QUERYENDSESSION:
{
- rc = !_Module.HasActiveConnection();
- if (!rc)
+ if (g_pModule)
{
- /* place the VBoxSVC into system shutdown list */
- ShutdownBlockReasonCreateAPI(hwnd, L"Has active connections.");
- /* decrease a latency of MonitorShutdown loop */
- ASMAtomicXchgU32(&dwTimeOut, 100);
- Log(("VBoxSVCWinMain: VBoxSvc has active connections. bActivity = %d. Loc count = %d\n",
- _Module.bActivity, _Module.GetLockCount()));
+ rc = !g_pModule->HasActiveConnection();
+ if (!rc)
+ {
+ /* place the VBoxSVC into system shutdown list */
+ ShutdownBlockReasonCreateAPI(hwnd, L"Has active connections.");
+ /* decrease a latency of MonitorShutdown loop */
+ ASMAtomicXchgU32(&dwTimeOut, 100);
+ Log(("VBoxSVCWinMain: VBoxSvc has active connections. bActivity = %d. Loc count = %d\n",
+ g_pModule->bActivity, g_pModule->GetLockCount()));
+ }
+ Log(("VBoxSVCWinMain: WM_QUERYENDSESSION msg: %d rc= %d\n", msg, rc));
}
- Log(("VBoxSVCWinMain: WM_QUERYENDSESSION msg: %d rc= %d\n", msg, rc));
} break;
case WM_ENDSESSION:
{
@@ -503,23 +506,26 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpC
int nRet = 0;
HRESULT hRes = com::Initialize(false /*fGui*/, fRun /*fAutoRegUpdate*/);
-
_ASSERTE(SUCCEEDED(hRes));
- _Module.Init(ObjectMap, hInstance, &LIBID_VirtualBox);
- _Module.dwThreadID = GetCurrentThreadId();
+
+ g_pModule = new CExeModule();
+ if(g_pModule == NULL)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "not enough memory to create ExeModule.");
+ g_pModule->Init(ObjectMap, hInstance, &LIBID_VirtualBox);
+ g_pModule->dwThreadID = GetCurrentThreadId();
if (!fRun)
{
#ifndef VBOX_WITH_MIDL_PROXY_STUB /* VBoxProxyStub.dll does all the registration work. */
if (fUnregister)
{
- _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
- nRet = _Module.UnregisterServer(TRUE);
+ g_pModule->UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
+ nRet = g_pModule->UnregisterServer(TRUE);
}
if (fRegister)
{
- _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
- nRet = _Module.RegisterServer(TRUE);
+ g_pModule->UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
+ nRet = g_pModule->RegisterServer(TRUE);
}
#endif
if (pszPipeName)
@@ -546,9 +552,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpC
}
else
{
- _Module.StartMonitor();
+ g_pModule->StartMonitor();
#if _WIN32_WINNT >= 0x0400
- hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
+ hRes = g_pModule->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
_ASSERTE(SUCCEEDED(hRes));
hRes = CoResumeClassObjects();
#else
@@ -574,13 +580,17 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpC
DestroyMainWindow();
- _Module.RevokeClassObjects();
+ g_pModule->RevokeClassObjects();
}
- _Module.Term();
+ g_pModule->Term();
com::Shutdown();
+ if(g_pModule)
+ delete g_pModule;
+ g_pModule = NULL;
+
Log(("SVCMAIN: Returning, COM server process ends.\n"));
return nRet;
}
diff --git a/src/VBox/Main/src-server/xpcom/server.cpp b/src/VBox/Main/src-server/xpcom/server.cpp
index 4bc59c1..6ad44f0 100644
--- a/src/VBox/Main/src-server/xpcom/server.cpp
+++ b/src/VBox/Main/src-server/xpcom/server.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2004-2016 Oracle Corporation
+ * Copyright (C) 2004-2017 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -233,17 +233,28 @@ public:
* possible destruction */
RTCritSectEnter(&sLock);
- nsrefcnt count = 0;
+ nsrefcnt count = 1;
/* sInstance is NULL here if it was deleted immediately after
* creation due to initialization error. See GetInstance(). */
if (sInstance != NULL)
{
- /* Release the guard reference added in GetInstance() */
+ /* Safe way to get current refcount is by first increasing and
+ * then decreasing. Keep in mind that the Release is overloaded
+ * (see VirtualBoxClassFactory::Release) and will start the
+ * timer again if the returned count is 1. It won't do harm,
+ * but also serves no purpose, so stop it ASAP. */
+ sInstance->AddRef();
count = sInstance->Release();
+ if (count == 1)
+ {
+ RTTimerLRStop(sTimer);
+ /* Release the guard reference added in GetInstance() */
+ sInstance->Release();
+ }
}
- if (count == 0)
+ if (count == 1)
{
if (gAutoShutdown || m_fSignal)
{
@@ -261,9 +272,6 @@ public:
* connect after this event has been posted to the main queue
* but before it started to process it. */
LogFlowFunc(("Destruction is canceled (refcnt=%d).\n", count));
- /* Important: restore previous refcount, we decreased it
- * above based on the assumption that the object is unused! */
- sInstance->AddRef();
}
RTCritSectLeave(&sLock);
@@ -407,7 +415,7 @@ public:
nsrefcnt count = sInstance->AddRef();
Assert(count > 1);
- if (count == 2)
+ if (count >= 2)
{
LogFlowFunc(("Another client has requested a reference to VirtualBox, canceling destruction...\n"));
diff --git a/src/VBox/NetworkServices/DHCP/Config.cpp b/src/VBox/NetworkServices/DHCP/Config.cpp
index fcfecd5..4204ae9 100644
--- a/src/VBox/NetworkServices/DHCP/Config.cpp
+++ b/src/VBox/NetworkServices/DHCP/Config.cpp
@@ -340,6 +340,7 @@ int
ConfigurationManager::findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t cbDhcpMsg, RawOption& opt)
{
Assert(uOption != RTNET_DHCP_OPT_PAD);
+ Assert(uOption != RTNET_DHCP_OPT_END);
/*
* Validate the DHCP bits and figure the max size of the options in the vendor field.
@@ -366,6 +367,8 @@ ConfigurationManager::findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t
cbLeft--;
pb++;
}
+ else if (uCur == RTNET_DHCP_OPT_END)
+ break;
else if (cbLeft <= 1)
break;
else
@@ -381,7 +384,7 @@ ConfigurationManager::findOption(uint8_t uOption, PCRTNETBOOTP pDhcpMsg, size_t
return VINF_SUCCESS;
}
pb += cbCur + 2;
- cbLeft -= cbCur - 2;
+ cbLeft -= cbCur + 2;
}
}
diff --git a/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp b/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp
index 7551407..545b8a1 100644
--- a/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp
+++ b/src/VBox/NetworkServices/NAT/VBoxNetLwipNAT.cpp
@@ -688,9 +688,21 @@ VBoxNetLwipNAT::VBoxNetLwipNAT(SOCKET icmpsock4, SOCKET icmpsock6) : VBoxNetBase
VBoxNetLwipNAT::~VBoxNetLwipNAT()
{
- if (m_ProxyOptions.tftp_root != NULL)
+ if (m_ProxyOptions.tftp_root)
{
RTStrFree((char *)m_ProxyOptions.tftp_root);
+ m_ProxyOptions.tftp_root = NULL;
+ }
+ if (m_ProxyOptions.nameservers)
+ {
+ const char **pv = m_ProxyOptions.nameservers;
+ while (*pv)
+ {
+ RTStrFree((char*)*pv);
+ pv++;
+ }
+ RTMemFree(m_ProxyOptions.nameservers);
+ m_ProxyOptions.nameservers = NULL;
}
}
diff --git a/src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp b/src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp
index 8cabcdb..3238a12 100644
--- a/src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp
+++ b/src/VBox/NetworkServices/NetLib/VBoxNetUDP.cpp
@@ -174,7 +174,7 @@ void *VBoxNetUDPMatch(PINTNETBUF pBuf, unsigned uDstPort, PCRTMAC pDstMac, uint3
/*
* We've got a match!
*/
- *pcb = pUdpHdr->uh_ulen - sizeof(*pUdpHdr);
+ *pcb = RT_N2H_U16(pUdpHdr->uh_ulen) - sizeof(*pUdpHdr);
return (void *)(pUdpHdr + 1);
}
diff --git a/src/VBox/RDP/client-1.8.3/Makefile.in b/src/VBox/RDP/client-1.8.3/Makefile.in
index 72dcf95..4bda184 100644
--- a/src/VBox/RDP/client-1.8.3/Makefile.in
+++ b/src/VBox/RDP/client-1.8.3/Makefile.in
@@ -29,7 +29,7 @@ SOUNDOBJ = @SOUNDOBJ@
SCARDOBJ = @SCARDOBJ@
CREDSSPOBJ = @CREDSSPOBJ@
-RDPOBJ = tcp.o asn.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o lspci.o seamless.o ssl.o utils.o Runtime/common/alloc/alloc.o Runtime/common/err/errmsg.o Runtime/common/err/errmsgxpcom.o Runtime/common/err/RTErrConvertFromErrno.o Runtime/common/err/RTErrConvertToErrno.o Runtime/common/misc/sg.o Runtime/common/path/RTPathAppend.o Runtime/common/path/RTPathAppendEx.o Runtim [...]
+RDPOBJ = tcp.o asn.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o lspci.o seamless.o ssl.o utils.o Runtime/common/alloc/alloc.o Runtime/common/err/errmsg.o Runtime/common/err/errmsgxpcom.o Runtime/common/err/RTErrConvertFromErrno.o Runtime/common/err/RTErrConvertToErrno.o Runtime/common/misc/sg.o Runtime/common/path/RTPathAppend.o Runtime/common/path/RTPathAppendEx.o Runtim [...]
X11OBJ = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o ctrl.o
VNCOBJ = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o
diff --git a/src/VBox/RDP/client-1.8.3/Makefile.kmk b/src/VBox/RDP/client-1.8.3/Makefile.kmk
index 0060aa8..82c416d 100644
--- a/src/VBox/RDP/client-1.8.3/Makefile.kmk
+++ b/src/VBox/RDP/client-1.8.3/Makefile.kmk
@@ -266,14 +266,14 @@ rdesktop-src_SOURCES = \
xkeymap.c=>xkeymap.c \
xproto.h=>xproto.h \
xwin.c=>xwin.c \
- $(PATH_OUT)/product-generated.h=>include/product-generated.h \
- $(PATH_OUT)/version-generated.h=>include/version-generated.h \
$(PATH_OUT)/obj/Runtime/errmsgdata.h=>include/errmsgdata.h \
$(PATH_OUT)/obj/Runtime/errmsgvboxcomdata.h=>include/errmsgvboxcomdata.h \
- $(PATH_ROOT)/include/iprt/alloc.h=>include/iprt/alloc.h \
+ $(PATH_OUT)/product-generated.h=>include/product-generated.h \
+ $(PATH_OUT)/version-generated.h=>include/version-generated.h \
$(PATH_ROOT)/include/iprt/alloca.h=>include/iprt/alloca.h \
- $(PATH_ROOT)/include/iprt/asm.h=>include/iprt/asm.h \
+ $(PATH_ROOT)/include/iprt/alloc.h=>include/iprt/alloc.h \
$(PATH_ROOT)/include/iprt/asm-amd64-x86.h=>include/iprt/asm-amd64-x86.h \
+ $(PATH_ROOT)/include/iprt/asm.h=>include/iprt/asm.h \
$(PATH_ROOT)/include/iprt/asm-math.h=>include/iprt/asm-math.h \
$(PATH_ROOT)/include/iprt/assert.h=>include/iprt/assert.h \
$(PATH_ROOT)/include/iprt/avl.h=>include/iprt/avl.h \
@@ -290,8 +290,8 @@ rdesktop-src_SOURCES = \
$(PATH_ROOT)/include/iprt/latin1.h=>include/iprt/latin1.h \
$(PATH_ROOT)/include/iprt/linux/sysfs.h=>include/iprt/linux/sysfs.h \
$(PATH_ROOT)/include/iprt/list.h=>include/iprt/list.h \
- $(PATH_ROOT)/include/iprt/log.h=>include/iprt/log.h \
$(PATH_ROOT)/include/iprt/lockvalidator.h=>include/iprt/lockvalidator.h \
+ $(PATH_ROOT)/include/iprt/log.h=>include/iprt/log.h \
$(PATH_ROOT)/include/iprt/mem.h=>include/iprt/mem.h \
$(PATH_ROOT)/include/iprt/net.h=>include/iprt/net.h \
$(PATH_ROOT)/include/iprt/param.h=>include/iprt/param.h \
@@ -305,8 +305,9 @@ rdesktop-src_SOURCES = \
$(PATH_ROOT)/include/iprt/stdint.h=>include/iprt/stdint.h \
$(PATH_ROOT)/include/iprt/stream.h=>include/iprt/stream.h \
$(PATH_ROOT)/include/iprt/string.h=>include/iprt/string.h \
- $(PATH_ROOT)/include/iprt/time.h=>include/iprt/time.h \
+ $(PATH_ROOT)/include/iprt/symlink.h=>include/iprt/symlink.h \
$(PATH_ROOT)/include/iprt/thread.h=>include/iprt/thread.h \
+ $(PATH_ROOT)/include/iprt/time.h=>include/iprt/time.h \
$(PATH_ROOT)/include/iprt/types.h=>include/iprt/types.h \
$(PATH_ROOT)/include/iprt/uni.h=>include/iprt/uni.h \
$(PATH_ROOT)/include/iprt/utf16.h=>include/iprt/utf16.h \
@@ -316,8 +317,8 @@ rdesktop-src_SOURCES = \
$(PATH_ROOT)/include/VBox/log.h=>include/VBox/log.h \
$(PATH_ROOT)/include/VBox/sup.h=>include/VBox/sup.h \
$(PATH_ROOT)/include/VBox/types.h=>include/VBox/types.h \
- $(PATH_ROOT)/include/VBox/usb.h=>include/VBox/usb.h \
$(PATH_ROOT)/include/VBox/usbfilter.h=>include/VBox/usbfilter.h \
+ $(PATH_ROOT)/include/VBox/usb.h=>include/VBox/usb.h \
$(PATH_ROOT)/include/VBox/usblib.h=>include/VBox/usblib.h \
$(PATH_ROOT)/include/VBox/version.h=>include/VBox/version.h \
$(PATH_ROOT)/include/VBox/vusb.h=>include/VBox/vusb.h \
@@ -341,24 +342,24 @@ rdesktop-src_SOURCES = \
$(PATH_ROOT)/src/VBox/Runtime/common/path/RTPathStripFilename.cpp=>Runtime/common/path/RTPathStripFilename.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/path/RTPathStripTrailingSlash.cpp=>Runtime/common/path/RTPathStripTrailingSlash.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp=>Runtime/common/path/rtPathVolumeSpecLen.cpp \
- $(PATH_ROOT)/src/VBox/Runtime/common/string/RTStrCopy.cpp=>Runtime/common/string/RTStrCopy.cpp \
- $(PATH_ROOT)/src/VBox/Runtime/common/string/RTStrNLen.cpp=>Runtime/common/string/RTStrNLen.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/RTStrCmp.cpp=>Runtime/common/string/RTStrCmp.cpp \
+ $(PATH_ROOT)/src/VBox/Runtime/common/string/RTStrCopy.cpp=>Runtime/common/string/RTStrCopy.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/RTStrNCmp.cpp=>Runtime/common/string/RTStrNCmp.cpp \
+ $(PATH_ROOT)/src/VBox/Runtime/common/string/RTStrNLen.cpp=>Runtime/common/string/RTStrNLen.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/straprintf.cpp=>Runtime/common/string/straprintf.cpp \
- $(PATH_ROOT)/src/VBox/Runtime/common/string/stringalloc.cpp=>Runtime/common/string/stringalloc.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/strformat.cpp=>Runtime/common/string/strformat.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/strformatrt.cpp=>Runtime/common/string/strformatrt.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/strformattype.cpp=>Runtime/common/string/strformattype.cpp \
+ $(PATH_ROOT)/src/VBox/Runtime/common/string/stringalloc.cpp=>Runtime/common/string/stringalloc.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/strprintf.cpp=>Runtime/common/string/strprintf.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/strstrip.cpp=>Runtime/common/string/strstrip.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/strtonum.cpp=>Runtime/common/string/strtonum.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/unidata-flags.cpp=>Runtime/common/string/unidata-flags.cpp \
- $(PATH_ROOT)/src/VBox/Runtime/common/string/unidata-upper.cpp=>Runtime/common/string/unidata-upper.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/unidata-lower.cpp=>Runtime/common/string/unidata-lower.cpp \
+ $(PATH_ROOT)/src/VBox/Runtime/common/string/unidata-upper.cpp=>Runtime/common/string/unidata-upper.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/utf-16.cpp=>Runtime/common/string/utf-16.cpp \
- $(PATH_ROOT)/src/VBox/Runtime/common/string/utf-8.cpp=>Runtime/common/string/utf-8.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/string/utf-8-case.cpp=>Runtime/common/string/utf-8-case.cpp \
+ $(PATH_ROOT)/src/VBox/Runtime/common/string/utf-8.cpp=>Runtime/common/string/utf-8.cpp \
$(PATH_ROOT)/src/VBox/Runtime/common/time/timesysalias.cpp=>Runtime/common/time/timesysalias.cpp \
$(PATH_ROOT)/src/VBox/Runtime/generic/pathhost-generic.cpp=>Runtime/generic/pathhost-generic.cpp \
$(PATH_ROOT)/src/VBox/Runtime/generic/RTPathAbs-generic.cpp=>Runtime/generic/RTPathAbs-generic.cpp \
@@ -388,9 +389,10 @@ rdesktop-src_SOURCES = \
$(PATH_ROOT)/src/VBox/Runtime/r3/posix/fileio-posix.cpp=>Runtime/r3/posix/fileio-posix.cpp \
$(PATH_ROOT)/src/VBox/Runtime/r3/posix/fs2-posix.cpp=>Runtime/r3/posix/fs2-posix.cpp \
$(PATH_ROOT)/src/VBox/Runtime/r3/posix/fs3-posix.cpp=>Runtime/r3/posix/fs3-posix.cpp \
- $(PATH_ROOT)/src/VBox/Runtime/r3/posix/path-posix.cpp=>Runtime/r3/posix/path-posix.cpp \
$(PATH_ROOT)/src/VBox/Runtime/r3/posix/path2-posix.cpp=>Runtime/r3/posix/path2-posix.cpp \
+ $(PATH_ROOT)/src/VBox/Runtime/r3/posix/path-posix.cpp=>Runtime/r3/posix/path-posix.cpp \
$(PATH_ROOT)/src/VBox/Runtime/r3/posix/pipe-posix.cpp=>Runtime/r3/posix/pipe-posix.cpp \
+ $(PATH_ROOT)/src/VBox/Runtime/r3/posix/symlink-posix.cpp=>Runtime/r3/posix/symlink-posix.cpp \
$(PATH_ROOT)/src/VBox/Runtime/r3/posix/thread2-posix.cpp=>Runtime/r3/posix/thread2-posix.cpp \
$(PATH_ROOT)/src/VBox/Runtime/r3/posix/utf8-posix.cpp=>Runtime/r3/posix/utf8-posix.cpp \
$(PATH_ROOT)/src/VBox/Runtime/r3/stream.cpp=>Runtime/r3/stream.cpp
diff --git a/src/VBox/RDP/client-1.8.3/rdesktop.c b/src/VBox/RDP/client-1.8.3/rdesktop.c
index 205713b..f80d1b8 100644
--- a/src/VBox/RDP/client-1.8.3/rdesktop.c
+++ b/src/VBox/RDP/client-1.8.3/rdesktop.c
@@ -63,6 +63,9 @@
#endif
#include "ssl.h"
+#if defined(VBOX) && defined(OPENSSL_MANGLER)
+# include <iprt/initterm.h>
+#endif
/* Reconnect timeout based on approxiamted cookie life-time */
#define RECONNECT_TIMEOUT (3600+600)
@@ -261,7 +264,7 @@ usage(char *program)
rdpsnd_show_help();
#endif
#ifdef WITH_RDPUSB
- fprintf(stderr,
+ fprintf(stderr,
" '-r usb': enable USB redirection\n");
#endif
fprintf(stderr,
@@ -583,6 +586,12 @@ main(int argc, char *argv[])
char *rdpsnd_optarg = NULL;
#endif
+#if defined(VBOX) && defined(OPENSSL_MANGLER)
+ /* Only need RT initialization if building against OpenSSL using
+ * RT synchronization, standalone rdesktop doesn't need this. */
+ RTR3InitExe(argc, &argv, 0);
+#endif
+
#ifdef HAVE_LOCALE_H
/* Set locale according to environment */
locale = setlocale(LC_ALL, "");
@@ -1241,7 +1250,7 @@ main(int argc, char *argv[])
continue;
}
- /* By setting encryption to False here, we have an encrypted login
+ /* By setting encryption to False here, we have an encrypted login
packet but unencrypted transfer of other packets */
if (!g_packet_encryption)
g_encryption_initial = g_encryption = False;
@@ -1820,7 +1829,7 @@ save_licence(unsigned char *data, int length)
sec_hash_sha1_16(ho, hi, g_static_rdesktop_salt_16);
sec_hash_to_string(hash, sizeof(hash), ho, sizeof(ho));
- /* write licence to {sha1}.cal.new, then atomically
+ /* write licence to {sha1}.cal.new, then atomically
rename to {sha1}.cal */
snprintf(path, PATH_MAX, "%s" RDESKTOP_LICENSE_STORE "/%s.cal", home, hash);
path[sizeof(path) - 1] = '\0';
diff --git a/src/VBox/Runtime/common/dbg/dbgas.cpp b/src/VBox/Runtime/common/dbg/dbgas.cpp
index 92c4d2d..9afbdb9 100644
--- a/src/VBox/Runtime/common/dbg/dbgas.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgas.cpp
@@ -341,6 +341,8 @@ static void rtDbgAsDestroy(PRTDBGASINT pDbgAs)
}
pDbgAs->papModules[i] = NULL;
}
+ RTSemRWDestroy(pDbgAs->hLock);
+ pDbgAs->hLock = NIL_RTSEMRW;
RTMemFree(pDbgAs->papModules);
pDbgAs->papModules = NULL;
diff --git a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
index 3adc09c..3f9829b 100644
--- a/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
+++ b/src/VBox/Runtime/common/dbg/dbgmoddwarf.cpp
@@ -2524,12 +2524,19 @@ static int rtDwarfLine_RunProgram(PRTDWARFLINESTATE pLnState, PRTDWARFCURSOR pCu
break;
case DW_LNS_const_add_pc:
- pLnState->Regs.uAddress += (pLnState->Regs.idxOp + 255) / pLnState->Hdr.cMaxOpsPerInstr
- * pLnState->Hdr.cbMinInstr;
- pLnState->Regs.idxOp += (pLnState->Regs.idxOp + 255) % pLnState->Hdr.cMaxOpsPerInstr;
+ {
+ uint8_t u8Adv = (255 - pLnState->Hdr.u8OpcodeBase) / pLnState->Hdr.u8LineRange;
+ if (pLnState->Hdr.cMaxOpsPerInstr <= 1)
+ pLnState->Regs.uAddress += (uint32_t)pLnState->Hdr.cbMinInstr * u8Adv;
+ else
+ {
+ pLnState->Regs.uAddress += (pLnState->Regs.idxOp + u8Adv) / pLnState->Hdr.cMaxOpsPerInstr
+ * pLnState->Hdr.cbMinInstr;
+ pLnState->Regs.idxOp = (pLnState->Regs.idxOp + u8Adv) % pLnState->Hdr.cMaxOpsPerInstr;
+ }
Log2(("%08x: DW_LNS_const_add_pc\n", offOpCode));
break;
-
+ }
case DW_LNS_fixed_advance_pc:
pLnState->Regs.uAddress += rtDwarfCursor_GetUHalf(pCursor, 0);
pLnState->Regs.idxOp = 0;
diff --git a/src/VBox/Runtime/common/misc/circbuf.cpp b/src/VBox/Runtime/common/misc/circbuf.cpp
index 60cb10e..e8ce6eb 100644
--- a/src/VBox/Runtime/common/misc/circbuf.cpp
+++ b/src/VBox/Runtime/common/misc/circbuf.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2011-2016 Oracle Corporation
+ * Copyright (C) 2011-2017 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -147,6 +147,22 @@ RTDECL(bool) RTCircBufIsWriting(PRTCIRCBUF pBuf)
return ASMAtomicReadBool(&pBuf->fWriting);
}
+RTDECL(size_t) RTCircBufOffsetRead(PRTCIRCBUF pBuf)
+{
+ /* Validate input. */
+ AssertPtrReturn(pBuf, 0);
+
+ return ASMAtomicReadZ(&pBuf->offRead);
+}
+
+RTDECL(size_t) RTCircBufOffsetWrite(PRTCIRCBUF pBuf)
+{
+ /* Validate input. */
+ AssertPtrReturn(pBuf, 0);
+
+ return ASMAtomicReadZ(&pBuf->offWrite);
+}
+
RTDECL(void) RTCircBufAcquireReadBlock(PRTCIRCBUF pBuf, size_t cbReqSize, void **ppvStart, size_t *pcbSize)
{
/* Validate input. */
diff --git a/src/VBox/Runtime/common/net/netaddrstr2.cpp b/src/VBox/Runtime/common/net/netaddrstr2.cpp
index beed41c..e3051d0 100644
--- a/src/VBox/Runtime/common/net/netaddrstr2.cpp
+++ b/src/VBox/Runtime/common/net/netaddrstr2.cpp
@@ -152,6 +152,56 @@ RTDECL(bool) RTNetStrIsIPv4AddrAny(const char *pcszAddr)
RT_EXPORT_SYMBOL(RTNetStrIsIPv4AddrAny);
+RTDECL(int) RTNetMaskToPrefixIPv4(PCRTNETADDRIPV4 pMask, int *piPrefix)
+{
+ AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
+
+ if (pMask->u == 0)
+ {
+ if (piPrefix != NULL)
+ *piPrefix = 0;
+ return VINF_SUCCESS;
+ }
+
+ const uint32_t uMask = RT_N2H_U32(pMask->u);
+
+ uint32_t uPrefixMask = UINT32_C(0xffffffff);
+ int iPrefixLen = 32;
+
+ while (iPrefixLen > 0) {
+ if (uMask == uPrefixMask)
+ {
+ if (piPrefix != NULL)
+ *piPrefix = iPrefixLen;
+ return VINF_SUCCESS;
+ }
+
+ --iPrefixLen;
+ uPrefixMask <<= 1;
+ }
+
+ return VERR_INVALID_PARAMETER;
+}
+RT_EXPORT_SYMBOL(RTNetMaskToPrefixIPv4);
+
+
+RTDECL(int) RTNetPrefixToMaskIPv4(int iPrefix, PRTNETADDRIPV4 pMask)
+{
+ AssertReturn(pMask != NULL, VERR_INVALID_PARAMETER);
+
+ if (RT_UNLIKELY(iPrefix < 0 || 32 < iPrefix))
+ return VERR_INVALID_PARAMETER;
+
+ if (RT_LIKELY(iPrefix != 0))
+ pMask->u = RT_H2N_U32(UINT32_C(0xffffffff) << (32 - iPrefix));
+ else /* avoid UB in the shift */
+ pMask->u = 0;
+
+ return VINF_SUCCESS;
+}
+RT_EXPORT_SYMBOL(RTNetPrefixToMaskIPv4);
+
+
static int rtNetStrToHexGroup(const char *pcszValue, char **ppszNext,
uint16_t *pu16)
{
diff --git a/src/VBox/Runtime/common/string/RTUtf16NLen.cpp b/src/VBox/Runtime/common/string/RTUtf16NLen.cpp
index e5e529c..c4c0500 100644
--- a/src/VBox/Runtime/common/string/RTUtf16NLen.cpp
+++ b/src/VBox/Runtime/common/string/RTUtf16NLen.cpp
@@ -35,7 +35,7 @@
RTDECL(size_t) RTUtf16NLen(PCRTUTF16 pwszString, size_t cwcMax)
{
PCRTUTF16 pwszStart = pwszString;
- while (cwcMax-- > 0 && pwszString != '\0')
+ while (cwcMax-- > 0 && *pwszString != '\0')
pwszString++;
return pwszString - pwszStart;
}
diff --git a/src/VBox/Runtime/common/zip/tarcmd.cpp b/src/VBox/Runtime/common/zip/tarcmd.cpp
index 400df51..bfea75f 100644
--- a/src/VBox/Runtime/common/zip/tarcmd.cpp
+++ b/src/VBox/Runtime/common/zip/tarcmd.cpp
@@ -946,11 +946,11 @@ static void rtZipTarUsage(const char *pszProgName)
" Directory prefix to give the members added to the archive.\n"
" --file-mode-and-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
" Restrict the access mode of regular and special files.\n"
- " --file-mode-and-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
+ " --file-mode-or-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
" Include the given access mode for regular and special files.\n"
" --dir-mode-and-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
" Restrict the access mode of directories.\n"
- " --dir-mode-and-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
+ " --dir-mode-or-mask <octal-mode> (-A, -C, -d, -r, -u, -x)\n"
" Include the given access mode for directories.\n"
" --read-ahead (-x)\n"
" Enabled read ahead thread when extracting files.\n"
diff --git a/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c b/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
index c2adfce..8202c1a 100644
--- a/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
+++ b/src/VBox/Runtime/r0drv/linux/semmutex-r0drv-linux.c
@@ -206,7 +206,7 @@ static int rtSemMutexLinuxRequestSleep(PRTSEMMUTEXINTERNAL pThis, RTMSINTERVAL c
break;
/* Go to sleep. */
- set_task_state(pSelf, fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+ set_current_state(fInterruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
spin_unlock_irq(&pThis->Spinlock);
lTimeout = schedule_timeout(lTimeout);
diff --git a/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h b/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
index d5e92ac..5a7ccb2 100644
--- a/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
+++ b/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h
@@ -103,6 +103,10 @@
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
# include <linux/sched/rt.h>
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
+# include <linux/sched/signal.h>
+# include <linux/sched/types.h>
+#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 7)
# include <linux/jiffies.h>
#endif
diff --git a/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp b/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp
index 3cacc35..38ac8e1 100644
--- a/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp
+++ b/src/VBox/Runtime/r3/posix/ldrNative-posix.cpp
@@ -109,6 +109,11 @@ DECLCALLBACK(int) rtldrNativeGetSymbol(PRTLDRMODINTERNAL pMod, const char *pszSy
DECLCALLBACK(int) rtldrNativeClose(PRTLDRMODINTERNAL pMod)
{
PRTLDRMODNATIVE pModNative = (PRTLDRMODNATIVE)pMod;
+#ifdef __SANITIZE_ADDRESS__
+ /* If we are compiled with enabled address sanitizer (gcc/llvm), don't
+ * unload the module to prevent <unknown module> in the stack trace */
+ pModNative->fFlags |= RTLDRLOAD_FLAGS_NO_UNLOAD;
+#endif
if ( (pModNative->fFlags & RTLDRLOAD_FLAGS_NO_UNLOAD)
|| !dlclose((void *)pModNative->hNative))
{
diff --git a/src/VBox/Runtime/r3/xml.cpp b/src/VBox/Runtime/r3/xml.cpp
index b5f1b04..3859fbe 100644
--- a/src/VBox/Runtime/r3/xml.cpp
+++ b/src/VBox/Runtime/r3/xml.cpp
@@ -31,6 +31,7 @@
#include <iprt/dir.h>
#include <iprt/file.h>
#include <iprt/err.h>
+#include <iprt/log.h>
#include <iprt/param.h>
#include <iprt/path.h>
#include <iprt/cpp/lock.h>
@@ -1690,15 +1691,36 @@ ElementNode *Document::createRootElement(const char *pcszRootElementName,
//
////////////////////////////////////////////////////////////////////////////////
+static void xmlParserBaseGenericError(void *pCtx, const char *pszMsg, ...)
+{
+ NOREF(pCtx);
+ va_list args;
+ va_start(args, pszMsg);
+ RTLogRelPrintfV(pszMsg, args);
+ va_end(args);
+}
+
+static void xmlParserBaseStructuredError(void *pCtx, xmlErrorPtr error)
+{
+ NOREF(pCtx);
+ /* we expect that there is always a trailing NL */
+ LogRel(("XML error at '%s' line %d: %s", error->file, error->line, error->message));
+}
+
XmlParserBase::XmlParserBase()
{
m_ctxt = xmlNewParserCtxt();
if (m_ctxt == NULL)
throw std::bad_alloc();
+ /* per-thread so it must be here */
+ xmlSetGenericErrorFunc(NULL, xmlParserBaseGenericError);
+ xmlSetStructuredErrorFunc(NULL, xmlParserBaseStructuredError);
}
XmlParserBase::~XmlParserBase()
{
+ xmlSetStructuredErrorFunc(NULL, NULL);
+ xmlSetGenericErrorFunc(NULL, NULL);
xmlFreeParserCtxt (m_ctxt);
m_ctxt = NULL;
}
diff --git a/src/VBox/Runtime/testcase/tstLdr-4.cpp b/src/VBox/Runtime/testcase/tstLdr-4.cpp
index 5ff4ccc..846c1c3 100644
--- a/src/VBox/Runtime/testcase/tstLdr-4.cpp
+++ b/src/VBox/Runtime/testcase/tstLdr-4.cpp
@@ -79,6 +79,8 @@ static DECLCALLBACK(int) testGetImport(RTLDRMOD hLdrMod, const char *pszModule,
*pValue = (uintptr_t)0;
else if (!strcmp(pszSymbol, "MyPrintf") || !strcmp(pszSymbol, "_MyPrintf"))
*pValue = (uintptr_t)RTPrintf;
+ else if (!strcmp(pszSymbol, "SomeImportFunction") || !strcmp(pszSymbol, "_SomeImportFunction"))
+ *pValue = (uintptr_t)0;
else
{
RTPrintf("tstLdr-4: Unexpected import '%s'!\n", pszSymbol);
@@ -127,7 +129,11 @@ static int testLdrOne(const char *pszFilename)
for (i = 0; i < RT_ELEMENTS(aLoads); i++)
{
if (!strncmp(aLoads[i].pszName, RT_STR_TUPLE("kLdr-")))
+ {
rc = RTLdrOpenkLdr(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod);
+ if (rc == VERR_ELF_EXE_NOT_SUPPORTED)
+ continue;
+ }
else
rc = RTLdrOpen(pszFilename, 0, RTLDRARCH_WHATEVER, &aLoads[i].hLdrMod);
if (RT_FAILURE(rc))
@@ -174,6 +180,9 @@ static int testLdrOne(const char *pszFilename)
{
for (i = 0; i < RT_ELEMENTS(aLoads); i += 1)
{
+ /* VERR_ELF_EXE_NOT_SUPPORTED in the previous loop? */
+ if (!aLoads[i].hLdrMod)
+ continue; /* VERR_ELF_EXE_NOT_SUPPORTED in the previous loop */
/* get the pointer. */
RTUINTPTR Value;
rc = RTLdrGetSymbolEx(aLoads[i].hLdrMod, aLoads[i].pvBits, (uintptr_t)aLoads[i].pvBits,
diff --git a/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp b/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp
index c9c2c5f..ba079b4 100644
--- a/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp
+++ b/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp
@@ -222,11 +222,15 @@ void tstASMCpuId(void)
RTTestIPrintf(RTTESTLVL_ALWAYS, "%08x %08x %08x %08x %08x%s\n",
iStd, s.uEAX, s.uEBX, s.uECX, s.uEDX, iStd <= cFunctions ? "" : "*");
- /* Leaf 04 and leaf 0d output depend on the initial value of ECX
+ /* Some leafs output depend on the initial value of ECX.
* The same seems to apply to invalid standard functions */
if (iStd > cFunctions)
continue;
- if (iStd != 0x04 && iStd != 0x07 && iStd != 0x0b && iStd != 0x0d)
+ if ( iStd != 0x04 /* Deterministic Cache Parameters Leaf */
+ && iStd != 0x07 /* Structured Extended Feature Flags */
+ && iStd != 0x0b /* Extended Topology Enumeration Leafs */
+ && iStd != 0x0d /* Extended State Enumeration Leafs */
+ && iStd != 0x14 /* Trace Enumeration Leafs */)
{
u32 = ASMCpuId_EAX(iStd);
CHECKVAL(u32, s.uEAX, "%x");
diff --git a/src/VBox/Runtime/testcase/tstRTNetIPv4.cpp b/src/VBox/Runtime/testcase/tstRTNetIPv4.cpp
index c2f73ab..08a2351 100644
--- a/src/VBox/Runtime/testcase/tstRTNetIPv4.cpp
+++ b/src/VBox/Runtime/testcase/tstRTNetIPv4.cpp
@@ -111,6 +111,120 @@
#define NOT_ANY(String) CHECKANY((String), false)
+#define CHECKMASK(_mask, _rcExpected, _iExpectedPrefix) \
+ do { \
+ /* const */ RTNETADDRIPV4 Mask; \
+ int iExpectedPrefix = (_iExpectedPrefix); \
+ int iPrefix; \
+ const int rcExpected = (_rcExpected); \
+ int rc2; \
+ \
+ Mask.u = RT_H2N_U32_C(UINT32_C(_mask)); \
+ rc2 = RTNetMaskToPrefixIPv4(&Mask, &iPrefix); \
+ \
+ if (rcExpected == VINF_SUCCESS) \
+ { \
+ if (rc2 != rcExpected) \
+ { \
+ /* unexpected failure */ \
+ RTTestIFailed("at line %d: mask %RTnaipv4:" \
+ " expected prefix length %d got %Rrc\n", \
+ __LINE__, Mask.u, \
+ iExpectedPrefix, rc2); \
+ } \
+ else if (iPrefix != iExpectedPrefix) \
+ { \
+ /* unexpected result */ \
+ RTTestIFailed("at line %d: mask %RTnaipv4:" \
+ " expected prefix length %d got %d\n", \
+ __LINE__, Mask.u, \
+ iExpectedPrefix, iPrefix); \
+ } \
+ } \
+ else /* expect failure */ \
+ { \
+ if (rc2 == VINF_SUCCESS) \
+ { \
+ /* unexpected success */ \
+ RTTestIFailed("at line %d: mask %RTnaipv4:" \
+ " expected %Rrc got prefix length %d\n", \
+ __LINE__, Mask.u, \
+ rcExpected, iPrefix); \
+ } \
+ else if (rc2 != rcExpected) \
+ { \
+ /* unexpected error */ \
+ RTTestIFailed("at line %d: mask %RTnaipv4:" \
+ " expected %Rrc got %Rrc\n", \
+ __LINE__, Mask.u, \
+ rcExpected, rc2); \
+ } \
+ } \
+ } while (0)
+
+#define CHECKPREFIX(_prefix, _rcExpected, _mask) \
+ do { \
+ const int iPrefix = (_prefix); \
+ RTNETADDRIPV4 ExpectedMask, Mask; \
+ const int rcExpected = (_rcExpected); \
+ int rc2; \
+ \
+ ExpectedMask.u = RT_H2N_U32_C(UINT32_C(_mask)); \
+ rc2 = RTNetPrefixToMaskIPv4(iPrefix, &Mask); \
+ \
+ if (rcExpected == VINF_SUCCESS) \
+ { \
+ if (rc2 != rcExpected) \
+ { \
+ /* unexpected failure */ \
+ RTTestIFailed("at line %d: prefix %d:" \
+ " expected mask %RTnaipv4 got %Rrc\n", \
+ __LINE__, iPrefix, \
+ ExpectedMask.u, rc2); \
+ } \
+ else if (Mask.u != ExpectedMask.u) \
+ { \
+ /* unexpected result */ \
+ RTTestIFailed("at line %d: prefix %d:" \
+ " expected mask %RTnaipv4 got %RTnaipv4\n", \
+ __LINE__, iPrefix, \
+ ExpectedMask.u, Mask.u); \
+ } \
+ } \
+ else /* expect failure */ \
+ { \
+ if (rc2 == VINF_SUCCESS) \
+ { \
+ /* unexpected success */ \
+ RTTestIFailed("at line %d: prefix %d:" \
+ " expected %Rrc got mask %RTnaipv4\n", \
+ __LINE__, iPrefix, \
+ rcExpected, Mask.u); \
+ } \
+ else if (rc2 != rcExpected) \
+ { \
+ /* unexpected error */ \
+ RTTestIFailed("at line %d: prefix %d:" \
+ " expected %Rrc got %Rrc\n", \
+ __LINE__, iPrefix, \
+ rcExpected, rc2); \
+ } \
+ } \
+ } while (0)
+
+#define GOODMASK(_mask, _prefix) \
+ do { \
+ CHECKMASK(_mask, VINF_SUCCESS, _prefix); \
+ CHECKPREFIX(_prefix, VINF_SUCCESS, _mask); \
+ } while (0)
+
+#define BADMASK(_mask) \
+ CHECKMASK(_mask, VERR_INVALID_PARAMETER, -1)
+
+#define BADPREFIX(_prefix) \
+ CHECKPREFIX(_prefix, VERR_INVALID_PARAMETER, 0)
+
+
int main()
{
RTTEST hTest;
@@ -152,5 +266,48 @@ int main()
NOT_ANY("1.1.1.1"); /* good address, but not INADDR_ANY */
NOT_ANY("0.0.0.0x"); /* bad address */
+
+ /*
+ * The mask <-> prefix table is small so we can test it all.
+ */
+ GOODMASK(0x00000000, 0); /* 0.0.0.0 */
+ GOODMASK(0x80000000, 1); /* 128.0.0.0 */
+ GOODMASK(0xc0000000, 2); /* 192.0.0.0 */
+ GOODMASK(0xe0000000, 3); /* 224.0.0.0 */
+ GOODMASK(0xf0000000, 4); /* 240.0.0.0 */
+ GOODMASK(0xf8000000, 5); /* 248.0.0.0 */
+ GOODMASK(0xfc000000, 6); /* 252.0.0.0 */
+ GOODMASK(0xfe000000, 7); /* 254.0.0.0 */
+ GOODMASK(0xff000000, 8); /* 255.0.0.0 */
+ GOODMASK(0xff800000, 9); /* 255.128.0.0 */
+ GOODMASK(0xffc00000, 10); /* 255.192.0.0 */
+ GOODMASK(0xffe00000, 11); /* 255.224.0.0 */
+ GOODMASK(0xfff00000, 12); /* 255.240.0.0 */
+ GOODMASK(0xfff80000, 13); /* 255.248.0.0 */
+ GOODMASK(0xfffc0000, 14); /* 255.252.0.0 */
+ GOODMASK(0xfffe0000, 15); /* 255.254.0.0 */
+ GOODMASK(0xffff0000, 16); /* 255.255.0.0 */
+ GOODMASK(0xffff8000, 17); /* 255.255.128.0 */
+ GOODMASK(0xffffc000, 18); /* 255.255.192.0 */
+ GOODMASK(0xffffe000, 19); /* 255.255.224.0 */
+ GOODMASK(0xfffff000, 20); /* 255.255.240.0 */
+ GOODMASK(0xfffff800, 21); /* 255.255.248.0 */
+ GOODMASK(0xfffffc00, 22); /* 255.255.252.0 */
+ GOODMASK(0xfffffe00, 23); /* 255.255.254.0 */
+ GOODMASK(0xffffff00, 24); /* 255.255.255.0 */
+ GOODMASK(0xffffff80, 25); /* 255.255.255.128 */
+ GOODMASK(0xffffffc0, 26); /* 255.255.255.192 */
+ GOODMASK(0xffffffe0, 27); /* 255.255.255.224 */
+ GOODMASK(0xfffffff0, 28); /* 255.255.255.240 */
+ GOODMASK(0xfffffff8, 29); /* 255.255.255.248 */
+ GOODMASK(0xfffffffc, 30); /* 255.255.255.252 */
+ GOODMASK(0xfffffffe, 31); /* 255.255.255.254 */
+ GOODMASK(0xffffffff, 32); /* 255.255.255.255 */
+
+ BADMASK(0x01020304);
+
+ BADPREFIX(-1);
+ BADPREFIX(33);
+
return RTTestSummaryAndDestroy(hTest);
}
diff --git a/src/VBox/Storage/testcase/vbox-img.cpp b/src/VBox/Storage/testcase/vbox-img.cpp
index 678b57a..0657def 100644
--- a/src/VBox/Storage/testcase/vbox-img.cpp
+++ b/src/VBox/Storage/testcase/vbox-img.cpp
@@ -1097,6 +1097,7 @@ static int handleInfo(HandlerArg *a)
/* Open the image */
rc = VDOpen(pDisk, pszFormat, pszFilename, VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY, NULL);
+ RTStrFree(pszFormat);
if (RT_FAILURE(rc))
return errorRuntime("Error while opening the image: %Rrf (%Rrc)\n", rc, rc);
@@ -1256,6 +1257,7 @@ static int handleCompact(HandlerArg *a)
/* Open the image */
rc = VDOpen(pDisk, pszFormat, pszFilename, VD_OPEN_FLAGS_NORMAL, NULL);
+ RTStrFree(pszFormat);
if (RT_FAILURE(rc))
return errorRuntime("Error while opening the image: %Rrf (%Rrc)\n", rc, rc);
diff --git a/src/VBox/VMM/VMMAll/EMAll.cpp b/src/VBox/VMM/VMMAll/EMAll.cpp
index 1ec7196..c7bfc0a 100644
--- a/src/VBox/VMM/VMMAll/EMAll.cpp
+++ b/src/VBox/VMM/VMMAll/EMAll.cpp
@@ -262,6 +262,52 @@ VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx)
/**
+ * Unhalts and wakes up the given CPU.
+ *
+ * This is an API for assisting the KVM hypercall API in implementing KICK_CPU.
+ * It sets VMCPU_FF_UNHALT for @a pVCpuDst and makes sure it is woken up. If
+ * the CPU isn't currently in a halt, the next HLT instruction it executes will
+ * be affected.
+ *
+ * @returns GVMMR0SchedWakeUpEx result or VINF_SUCCESS depending on context.
+ * @param pVM The cross context VM structure.
+ * @param pVCpuDst The cross context virtual CPU structure of the
+ * CPU to unhalt and wake up. This is usually not the
+ * same as the caller.
+ * @thread EMT
+ */
+VMM_INT_DECL(int) EMUnhaltAndWakeUp(PVM pVM, PVMCPU pVCpuDst)
+{
+ /*
+ * Flag the current(/next) HLT to unhalt immediately.
+ */
+ VMCPU_FF_SET(pVCpuDst, VMCPU_FF_UNHALT);
+
+ /*
+ * Wake up the EMT (technically should be abstracted by VMM/VMEmt, but
+ * just do it here for now).
+ */
+#ifdef IN_RING0
+ /* We might be here with preemption disabled or enabled (i.e. depending on
+ thread-context hooks being used), so don't try obtaining the GVMMR0 used
+ lock here. See @bugref{7270#c148}. */
+ int rc = GVMMR0SchedWakeUpEx(pVM, pVCpuDst->idCpu, false /* fTakeUsedLock */);
+ AssertRC(rc);
+
+#elif defined(IN_RING3)
+ int rc = SUPR3CallVMMR0(pVM->pVMR0, pVCpuDst->idCpu, VMMR0_DO_GVMM_SCHED_WAKE_UP, NULL /* pvArg */);
+ AssertRC(rc);
+
+#else
+ /* Nothing to do for raw-mode, shouldn't really be used by raw-mode guests anyway. */
+ Assert(pVM->cCpus == 1); NOREF(pVM);
+ int rc = VINF_SUCCESS;
+#endif
+ return rc;
+}
+
+
+/**
* Locks REM execution to a single VCPU.
*
* @param pVM The cross context VM structure.
diff --git a/src/VBox/VMM/VMMAll/GIMAllKvm.cpp b/src/VBox/VMM/VMMAll/GIMAllKvm.cpp
index 9fe604e..9e51985 100644
--- a/src/VBox/VMM/VMMAll/GIMAllKvm.cpp
+++ b/src/VBox/VMM/VMMAll/GIMAllKvm.cpp
@@ -102,21 +102,8 @@ VMM_INT_DECL(VBOXSTRICTRC) gimKvmHypercall(PVMCPU pVCpu, PCPUMCTX pCtx)
{
if (uHyperArg1 < pVM->cCpus)
{
- PVMCPU pVCpuTarget = &pVM->aCpus[uHyperArg1]; /** ASSUMES pVCpu index == ApicId of the VCPU. */
- VMCPU_FF_SET(pVCpuTarget, VMCPU_FF_UNHALT);
-#ifdef IN_RING0
- /*
- * We might be here with preemption disabled or enabled (i.e. depending on thread-context hooks
- * being used), so don't try obtaining the GVMMR0 used lock here. See @bugref{7270#c148}.
- */
- GVMMR0SchedWakeUpEx(pVM, pVCpuTarget->idCpu, false /* fTakeUsedLock */);
-#elif defined(IN_RING3)
- int rc2 = SUPR3CallVMMR0(pVM->pVMR0, pVCpuTarget->idCpu, VMMR0_DO_GVMM_SCHED_WAKE_UP, NULL /* pvArg */);
- AssertRC(rc2);
-#elif defined(IN_RC)
- /* Nothing to do for raw-mode, shouldn't really be used by raw-mode guests anyway. */
- Assert(pVM->cCpus == 1);
-#endif
+ PVMCPU pVCpuDst = &pVM->aCpus[uHyperArg1]; /* ASSUMES pVCpu index == ApicId of the VCPU. */
+ EMUnhaltAndWakeUp(pVM, pVCpuDst);
uHyperRet = KVM_HYPERCALL_RET_SUCCESS;
}
else
diff --git a/src/VBox/VMM/VMMAll/IEMAll.cpp b/src/VBox/VMM/VMMAll/IEMAll.cpp
index c1615f9..988f2a6 100644
--- a/src/VBox/VMM/VMMAll/IEMAll.cpp
+++ b/src/VBox/VMM/VMMAll/IEMAll.cpp
@@ -921,6 +921,7 @@ DECLINLINE(void) iemUninitExec(PVMCPU pVCpu)
#endif
#ifdef VBOX_STRICT
# ifdef IEM_WITH_CODE_TLB
+ NOREF(pVCpu);
# else
pVCpu->iem.s.cbOpcode = 0;
# endif
@@ -1476,9 +1477,6 @@ IEM_STATIC void iemOpcodeFetchBytesJmp(PVMCPU pVCpu, size_t cbDst, void *pvDst)
{
#ifdef IN_RING3
//__debugbreak();
-#else
- longjmp(*CTX_SUFF(pVCpu->iem.s.pJmpBuf), VERR_INTERNAL_ERROR);
-#endif
for (;;)
{
Assert(cbDst <= 8);
@@ -1746,6 +1744,10 @@ IEM_STATIC void iemOpcodeFetchBytesJmp(PVMCPU pVCpu, size_t cbDst, void *pvDst)
cbDst -= cbMaxRead;
pvDst = (uint8_t *)pvDst + cbMaxRead;
}
+#else
+ RT_NOREF(pvDst, cbDst);
+ longjmp(*CTX_SUFF(pVCpu->iem.s.pJmpBuf), VERR_INTERNAL_ERROR);
+#endif
}
#else
@@ -4342,7 +4344,7 @@ iemRaiseXcptOrIntInProtMode(PVMCPU pVCpu,
return rcStrict;
Log(("iemRaiseXcptOrIntInProtMode: vec=%#x P=%u DPL=%u DT=%u:%u A=%u %04x:%04x%04x\n",
u8Vector, Idte.Gate.u1Present, Idte.Gate.u2Dpl, Idte.Gate.u1DescType, Idte.Gate.u4Type,
- Idte.Gate.u4ParmCount, Idte.Gate.u16Sel, Idte.Gate.u16OffsetHigh, Idte.Gate.u16OffsetLow));
+ Idte.Gate.u5ParmCount, Idte.Gate.u16Sel, Idte.Gate.u16OffsetHigh, Idte.Gate.u16OffsetLow));
/*
* Check the descriptor type, DPL and such.
@@ -4552,6 +4554,15 @@ iemRaiseXcptOrIntInProtMode(PVMCPU pVCpu,
if (rcStrict != VINF_SUCCESS)
return rcStrict;
+ /* If the new SS is 16-bit, we are only going to use SP, not ESP. */
+ if (!DescSS.Legacy.Gen.u1DefBig)
+ {
+ Log(("iemRaiseXcptOrIntInProtMode: Forcing ESP=%#x to 16 bits\n", uNewEsp));
+ uNewEsp = (uint16_t)uNewEsp;
+ }
+
+ Log7(("iemRaiseXcptOrIntInProtMode: New SS=%#x ESP=%#x (from TSS); current SS=%#x ESP=%#x\n", NewSS, uNewEsp, pCtx->ss.Sel, pCtx->esp));
+
/* Check that there is sufficient space for the stack frame. */
uint32_t cbLimitSS = X86DESC_LIMIT_G(&DescSS.Legacy);
uint8_t const cbStackFrame = !(fEfl & X86_EFL_VM)
@@ -4570,7 +4581,7 @@ iemRaiseXcptOrIntInProtMode(PVMCPU pVCpu,
}
else
{
- if ( uNewEsp - 1 > (DescSS.Legacy.Gen.u4Type & X86_DESC_DB ? UINT32_MAX : UINT32_C(0xffff))
+ if ( uNewEsp - 1 > (DescSS.Legacy.Gen.u1DefBig ? UINT32_MAX : UINT16_MAX)
|| uNewEsp - cbStackFrame < cbLimitSS + UINT32_C(1))
{
Log(("RaiseXcptOrIntInProtMode: %#x - SS=%#x ESP=%#x cbStackFrame=%#x (expand down) is out of bounds -> #GP\n",
@@ -5243,14 +5254,6 @@ DECL_NO_INLINE(IEM_STATIC, VBOXSTRICTRC) iemRaiseSelectorNotPresentWithErr(PVMCP
}
-/** \#NP(seg) - 0b. */
-DECL_NO_INLINE(IEM_STATIC, VBOXSTRICTRC) iemRaiseSelectorNotPresentBySegReg(PVMCPU pVCpu, uint32_t iSegReg)
-{
- return iemRaiseXcptOrInt(pVCpu, 0, X86_XCPT_NP, IEM_XCPT_FLAGS_T_CPU_XCPT | IEM_XCPT_FLAGS_ERR,
- iemSRegFetchU16(pVCpu, iSegReg) & ~X86_SEL_RPL, 0);
-}
-
-
/** \#NP(sel) - 0b. */
DECL_NO_INLINE(IEM_STATIC, VBOXSTRICTRC) iemRaiseSelectorNotPresentBySelector(PVMCPU pVCpu, uint16_t uSel)
{
@@ -7406,7 +7409,12 @@ iemMemSegCheckWriteAccessEx(PVMCPU pVCpu, PCCPUMSELREGHID pHid, uint8_t iSegReg,
else
{
if (!pHid->Attr.n.u1Present)
- return iemRaiseSelectorNotPresentBySegReg(pVCpu, iSegReg);
+ {
+ uint16_t uSel = iemSRegFetchU16(pVCpu, iSegReg);
+ AssertRelease(uSel == 0);
+ Log(("iemMemSegCheckWriteAccessEx: %#x (index %u) - bad selector -> #GP\n", uSel, iSegReg));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
if ( ( (pHid->Attr.n.u4Type & X86_SEL_TYPE_CODE)
|| !(pHid->Attr.n.u4Type & X86_SEL_TYPE_WRITE) )
@@ -7439,7 +7447,12 @@ iemMemSegCheckReadAccessEx(PVMCPU pVCpu, PCCPUMSELREGHID pHid, uint8_t iSegReg,
else
{
if (!pHid->Attr.n.u1Present)
- return iemRaiseSelectorNotPresentBySegReg(pVCpu, iSegReg);
+ {
+ uint16_t uSel = iemSRegFetchU16(pVCpu, iSegReg);
+ AssertRelease(uSel == 0);
+ Log(("iemMemSegCheckReadAccessEx: %#x (index %u) - bad selector -> #GP\n", uSel, iSegReg));
+ return iemRaiseGeneralProtectionFault0(pVCpu);
+ }
if ((pHid->Attr.n.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
return iemRaiseSelectorInvalidAccess(pVCpu, iSegReg, IEM_ACCESS_DATA_R);
@@ -7595,7 +7608,8 @@ iemMemPageTranslateAndCheckAccess(PVMCPU pVCpu, RTGCPTR GCPtrMem, uint32_t fAcce
/* Write to read only memory? */
if ( (fAccess & IEM_ACCESS_TYPE_WRITE)
&& !(fFlags & X86_PTE_RW)
- && ( pVCpu->iem.s.uCpl != 0
+ && ( (pVCpu->iem.s.uCpl == 3
+ && !(fAccess & IEM_ACCESS_WHAT_SYS))
|| (IEM_GET_CTX(pVCpu)->cr0 & X86_CR0_WP)))
{
Log(("iemMemPageTranslateAndCheckAccess: GCPtrMem=%RGv - read-only page -> #PF\n", GCPtrMem));
@@ -10249,7 +10263,21 @@ iemMemFetchSelDescWithErr(PVMCPU pVCpu, PIEMSELDESC pDesc, uint16_t uSel, uint8_
* Read the legacy descriptor and maybe the long mode extensions if
* required.
*/
- VBOXSTRICTRC rcStrict = iemMemFetchSysU64(pVCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
+ VBOXSTRICTRC rcStrict;
+ if (IEM_GET_TARGET_CPU(pVCpu) > IEMTARGETCPU_286)
+ rcStrict = iemMemFetchSysU64(pVCpu, &pDesc->Legacy.u, UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK));
+ else
+ {
+ rcStrict = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[0], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 0);
+ if (rcStrict != VINF_SUCCESS)
+ return rcStrict;
+ rcStrict = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[1], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 2);
+ if (rcStrict != VINF_SUCCESS)
+ return rcStrict;
+ rcStrict = iemMemFetchSysU16(pVCpu, &pDesc->Legacy.au16[2], UINT8_MAX, GCPtrBase + (uSel & X86_SEL_MASK) + 4);
+ pDesc->Legacy.au16[3] = 0;
+ }
+
if (rcStrict == VINF_SUCCESS)
{
if ( !IEM_IS_LONG_MODE(pVCpu)
@@ -10402,6 +10430,11 @@ IEM_STATIC VBOXSTRICTRC iemMemMarkSelDescAccessed(PVMCPU pVCpu, uint16_t uSel)
if ((pVCpu)->iem.s.CTX_SUFF(pCtx)->cr0 & (X86_CR0_EM | X86_CR0_TS)) \
return iemRaiseDeviceNotAvailable(pVCpu); \
} while (0)
+#define IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE() \
+ do { \
+ if (((pVCpu)->iem.s.CTX_SUFF(pCtx)->cr0 & (X86_CR0_MP | X86_CR0_TS)) == (X86_CR0_MP | X86_CR0_TS)) \
+ return iemRaiseDeviceNotAvailable(pVCpu); \
+ } while (0)
#define IEM_MC_MAYBE_RAISE_FPU_XCPT() \
do { \
if ((pVCpu)->iem.s.CTX_SUFF(pCtx)->CTX_SUFF(pXState)->x87.FSW & X86_FSW_ES) \
@@ -14092,7 +14125,8 @@ VMMDECL(VBOXSTRICTRC) IEMExecLots(PVMCPU pVCpu, uint32_t *pcInstructions)
| VMCPU_FF_SELM_SYNC_LDT
# endif
| VMCPU_FF_INHIBIT_INTERRUPTS
- | VMCPU_FF_BLOCK_NMIS ));
+ | VMCPU_FF_BLOCK_NMIS
+ | VMCPU_FF_UNHALT ));
if (RT_LIKELY( ( !fCpu
|| ( !(fCpu & ~(VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC))
diff --git a/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp b/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp
index 53f85eb..4d5989e 100644
--- a/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp
+++ b/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp
@@ -525,7 +525,7 @@ IEM_DECL_IMPL_DEF(void, iemAImpl_test_u64,(uint64_t *puDst, uint64_t uSrc, uint3
IEM_DECL_IMPL_DEF(void, iemAImpl_add_u64_locked,(uint64_t *puDst, uint64_t uSrc, uint32_t *pfEFlags))
{
- DO_LOCKED_BIN_OP_U64(adc);
+ DO_LOCKED_BIN_OP_U64(add);
}
diff --git a/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h b/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
index 23abe43..bde6c6e 100644
--- a/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
+++ b/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
@@ -1330,7 +1330,7 @@ IEM_CIMPL_DEF_4(iemCImpl_BranchCallGate, uint16_t, uSel, IEMBRANCH, enmBranch, I
}
/* Only used outside of long mode. */
- cbWords = pDesc->Legacy.Gate.u4ParmCount;
+ cbWords = pDesc->Legacy.Gate.u5ParmCount;
/* If EFER.LMA is 0, there's extra work to do. */
if (!IEM_IS_LONG_MODE(pVCpu))
@@ -2295,6 +2295,7 @@ IEM_CIMPL_DEF_2(iemCImpl_retf, IEMMODE, enmEffOpSize, uint16_t, cbPop)
uNewOuterRsp = uPtrFrame.pu64[0];
uNewOuterSs = uPtrFrame.pu16[4];
}
+ uPtrFrame.pu8 -= cbPop; /* Put uPtrFrame back the way it was. */
rcStrict = iemMemStackPopDoneSpecial(pVCpu, uPtrFrame.pv);
if (RT_LIKELY(rcStrict == VINF_SUCCESS))
{ /* extremely likely */ }
@@ -2421,7 +2422,6 @@ IEM_CIMPL_DEF_2(iemCImpl_retf, IEMMODE, enmEffOpSize, uint16_t, cbPop)
}
/* commit */
- pCtx->rsp = uNewRsp;
if (enmEffOpSize == IEMMODE_16BIT)
pCtx->rip = uNewRip & UINT16_MAX; /** @todo Testcase: When exactly does this occur? With call it happens prior to the limit check according to Intel... */
else
@@ -3003,6 +3003,7 @@ IEM_CIMPL_DEF_5(iemCImpl_iret_prot_v8086, PCPUMCTX, pCtx, uint32_t, uNewEip, uin
RTTraceBufAddMsgF(pVCpu->CTX_SUFF(pVM)->CTX_SUFF(hTraceBuf), "iret/p/v %04x:%08x -> %04x:%04x %x %04x:%04x",
pCtx->cs.Sel, pCtx->eip, uNewCs, uNewEip, uNewFlags, uNewSs, uNewEsp);
#endif
+ Log7(("iemCImpl_iret_prot_v8086: %04x:%08x -> %04x:%04x %x %04x:%04x\n", pCtx->cs.Sel, pCtx->eip, uNewCs, uNewEip, uNewFlags, uNewSs, uNewEsp));
IEMMISC_SET_EFL(pVCpu, pCtx, uNewFlags);
iemCImplCommonV8086LoadSeg(&pCtx->cs, uNewCs);
@@ -3141,7 +3142,7 @@ IEM_CIMPL_DEF_1(iemCImpl_iret_prot, IEMMODE, enmEffOpSize)
{ /* extremely likely */ }
else
return rcStrict;
- Log7(("iemCImpl_iret_prot: uNewCs=%#06x uNewEip=%#010x uNewFlags=%#x uNewRsp=%#18llx\n", uNewCs, uNewEip, uNewFlags, uNewRsp));
+ Log7(("iemCImpl_iret_prot: uNewCs=%#06x uNewEip=%#010x uNewFlags=%#x uNewRsp=%#18llx uCpl=%u\n", uNewCs, uNewEip, uNewFlags, uNewRsp, pVCpu->iem.s.uCpl));
/*
* We're hopefully not returning to V8086 mode...
diff --git a/src/VBox/VMM/VMMAll/IEMAllInstructions.cpp.h b/src/VBox/VMM/VMMAll/IEMAllInstructions.cpp.h
index 8911267..dbcd827 100644
--- a/src/VBox/VMM/VMMAll/IEMAllInstructions.cpp.h
+++ b/src/VBox/VMM/VMMAll/IEMAllInstructions.cpp.h
@@ -4909,7 +4909,7 @@ FNIEMOP_DEF_1(iemOpCommonBit_Ev_Gv, PCIEMOPBINSIZES, pImpl)
IEM_MC_ASSIGN(i16AddrAdj, u16Src);
IEM_MC_AND_ARG_U16(u16Src, 0x0f);
IEM_MC_SAR_LOCAL_S16(i16AddrAdj, 4);
- IEM_MC_SAR_LOCAL_S16(i16AddrAdj, 1);
+ IEM_MC_SHL_LOCAL_S16(i16AddrAdj, 1);
IEM_MC_ADD_LOCAL_S16_TO_EFF_ADDR(GCPtrEffDst, i16AddrAdj);
IEM_MC_FETCH_EFLAGS(EFlags);
@@ -6805,7 +6805,19 @@ FNIEMOP_DEF_1(iemOp_Grp9_cmpxchg8b_Mq, uint8_t, bRm)
/** Opcode REX.W 0x0f 0xc7 !11/1. */
-FNIEMOP_UD_STUB_1(iemOp_Grp9_cmpxchg16b_Mdq, uint8_t, bRm);
+FNIEMOP_DEF_1(iemOp_Grp9_cmpxchg16b_Mdq, uint8_t, bRm)
+{
+ IEMOP_MNEMONIC("cmpxchg16b Mdq");
+ if (IEM_GET_GUEST_CPU_FEATURES(pVCpu)->fMovCmpXchg16b)
+ {
+ RT_NOREF(bRm);
+ IEMOP_BITCH_ABOUT_STUB();
+ return VERR_IEM_INSTR_NOT_IMPLEMENTED;
+ }
+ Log(("cmpxchg16b -> #UD\n"));
+ return IEMOP_RAISE_INVALID_OPCODE();
+}
+
/** Opcode 0x0f 0xc7 11/6. */
FNIEMOP_UD_STUB_1(iemOp_Grp9_rdrand_Rv, uint8_t, bRm);
@@ -6837,7 +6849,7 @@ FNIEMOP_DEF(iemOp_Grp9)
if ( (bRm & X86_MODRM_MOD_MASK) == (3 << X86_MODRM_MOD_SHIFT)
|| (pVCpu->iem.s.fPrefixes & (IEM_OP_PRF_SIZE_OP | IEM_OP_PRF_REPZ))) /** @todo Testcase: AMD seems to express a different idea here wrt prefixes. */
return IEMOP_RAISE_INVALID_OPCODE();
- if (bRm & IEM_OP_PRF_SIZE_REX_W)
+ if (pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SIZE_REX_W)
return FNIEMOP_CALL_1(iemOp_Grp9_cmpxchg16b_Mdq, bRm);
return FNIEMOP_CALL_1(iemOp_Grp9_cmpxchg8b_Mq, bRm);
case 6:
@@ -11177,7 +11189,7 @@ FNIEMOP_DEF(iemOp_wait)
IEMOP_HLP_DONE_DECODING_NO_LOCK_PREFIX();
IEM_MC_BEGIN(0, 0);
- IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE();
+ IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE();
IEM_MC_MAYBE_RAISE_FPU_XCPT();
IEM_MC_ADVANCE_RIP();
IEM_MC_END();
diff --git a/src/VBox/VMM/VMMAll/PGMAllBth.h b/src/VBox/VMM/VMMAll/PGMAllBth.h
index 2db679f..6498462 100644
--- a/src/VBox/VMM/VMMAll/PGMAllBth.h
+++ b/src/VBox/VMM/VMMAll/PGMAllBth.h
@@ -1209,21 +1209,33 @@ PGM_BTH_DECL(int, InvalidatePage)(PVMCPU pVCpu, RTGCPTR GCPtrPage)
* (Guessing that it is frequent for a shadow PDE to not be present, do this first.)
*/
# if PGM_SHW_TYPE == PGM_TYPE_32BIT
- const unsigned iPDDst = (GCPtrPage >> SHW_PD_SHIFT) & SHW_PD_MASK;
+ const unsigned iPDDst = (uint32_t)GCPtrPage >> SHW_PD_SHIFT;
PX86PDE pPdeDst = pgmShwGet32BitPDEPtr(pVCpu, GCPtrPage);
/* Fetch the pgm pool shadow descriptor. */
PPGMPOOLPAGE pShwPde = pVCpu->pgm.s.CTX_SUFF(pShwPageCR3);
+# ifdef IN_RING3 /* Possible we didn't resync yet when called from REM. */
+ if (!pShwPde)
+ {
+ STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePageSkipped));
+ return VINF_SUCCESS;
+ }
+# else
Assert(pShwPde);
+# endif
# elif PGM_SHW_TYPE == PGM_TYPE_PAE
- const unsigned iPdpt = (GCPtrPage >> X86_PDPT_SHIFT);
+ const unsigned iPdpt = (uint32_t)GCPtrPage >> X86_PDPT_SHIFT;
PX86PDPT pPdptDst = pgmShwGetPaePDPTPtr(pVCpu);
/* If the shadow PDPE isn't present, then skip the invalidate. */
+# ifdef IN_RING3 /* Possible we didn't resync yet when called from REM. */
+ if (!pPdptDst || !pPdptDst->a[iPdpt].n.u1Present)
+# else
if (!pPdptDst->a[iPdpt].n.u1Present)
+# endif
{
- Assert(!(pPdptDst->a[iPdpt].u & PGM_PLXFLAGS_MAPPING));
+ Assert(!pPdptDst || !(pPdptDst->a[iPdpt].u & PGM_PLXFLAGS_MAPPING));
STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,InvalidatePageSkipped));
PGM_INVL_PG(pVCpu, GCPtrPage);
return VINF_SUCCESS;
@@ -1288,7 +1300,7 @@ PGM_BTH_DECL(int, InvalidatePage)(PVMCPU pVCpu, RTGCPTR GCPtrPage)
*/
# if PGM_GST_TYPE == PGM_TYPE_32BIT
PGSTPD pPDSrc = pgmGstGet32bitPDPtr(pVCpu);
- const unsigned iPDSrc = GCPtrPage >> GST_PD_SHIFT;
+ const unsigned iPDSrc = (uint32_t)GCPtrPage >> GST_PD_SHIFT;
GSTPDE PdeSrc = pPDSrc->a[iPDSrc];
# else /* PGM_GST_TYPE != PGM_TYPE_32BIT */
unsigned iPDSrc = 0;
@@ -3366,7 +3378,7 @@ PGM_BTH_DECL(int, PrefetchPage)(PVMCPU pVCpu, RTGCPTR GCPtrPage)
int rc = VINF_SUCCESS;
# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
# if PGM_GST_TYPE == PGM_TYPE_32BIT
- const unsigned iPDSrc = GCPtrPage >> GST_PD_SHIFT;
+ const unsigned iPDSrc = (uint32_t)GCPtrPage >> GST_PD_SHIFT;
PGSTPD pPDSrc = pgmGstGet32bitPDPtr(pVCpu);
# elif PGM_GST_TYPE == PGM_TYPE_PAE
unsigned iPDSrc;
@@ -3528,7 +3540,7 @@ PGM_BTH_DECL(int, VerifyAccessSyncPage)(PVMCPU pVCpu, RTGCPTR GCPtrPage, unsigne
* PGMGstGetPage call. */
# if PGM_WITH_PAGING(PGM_GST_TYPE, PGM_SHW_TYPE)
# if PGM_GST_TYPE == PGM_TYPE_32BIT
- const unsigned iPDSrc = GCPtrPage >> GST_PD_SHIFT;
+ const unsigned iPDSrc = (uint32_t)GCPtrPage >> GST_PD_SHIFT;
PGSTPD pPDSrc = pgmGstGet32bitPDPtr(pVCpu);
# elif PGM_GST_TYPE == PGM_TYPE_PAE
diff --git a/src/VBox/VMM/VMMAll/PGMAllPool.cpp b/src/VBox/VMM/VMMAll/PGMAllPool.cpp
index 0dfb512..8e541e4 100644
--- a/src/VBox/VMM/VMMAll/PGMAllPool.cpp
+++ b/src/VBox/VMM/VMMAll/PGMAllPool.cpp
@@ -736,11 +736,21 @@ DECLINLINE(bool) pgmPoolMonitorIsForking(PPGMPOOL pPool, PDISCPUSTATE pDis, unsi
* @param pRegFrame Trap register frame.
* @param pDis The disassembly info for the faulting instruction.
* @param pvFault The fault address.
+ * @param pPage The pool page being accessed.
*
* @remark The REP prefix check is left to the caller because of STOSD/W.
*/
-DECLINLINE(bool) pgmPoolMonitorIsReused(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pDis, RTGCPTR pvFault)
+DECLINLINE(bool) pgmPoolMonitorIsReused(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pDis, RTGCPTR pvFault,
+ PPGMPOOLPAGE pPage)
{
+ /* Locked (CR3, PDPTR*4) should not be reusable. Considering them as
+ such may cause loops booting tst-ubuntu-15_10-64-efi, ++. */
+ if (pPage->cLocked)
+ {
+ Log2(("pgmRZPoolMonitorIsReused: %RGv (%p) can't have been resued, because it's locked!\n", pvFault, pPage));
+ return false;
+ }
+
#ifndef IN_RC
/** @todo could make this general, faulting close to rsp should be a safe reuse heuristic. */
if ( HMHasPendingIrq(pVM)
@@ -1187,7 +1197,7 @@ DECLEXPORT(VBOXSTRICTRC) pgmPoolAccessPfHandler(PVM pVM, PVMCPU pVCpu, RTGCUINT
if ( ( pPage->cModifications < cMaxModifications /** @todo \#define */ /** @todo need to check that it's not mapping EIP. */ /** @todo adjust this! */
|| pgmPoolIsPageLocked(pPage)
)
- && !(fReused = pgmPoolMonitorIsReused(pVM, pVCpu, pRegFrame, pDis, pvFault))
+ && !(fReused = pgmPoolMonitorIsReused(pVM, pVCpu, pRegFrame, pDis, pvFault, pPage))
&& !pgmPoolMonitorIsForking(pPool, pDis, GCPhysFault & PAGE_OFFSET_MASK))
{
/*
@@ -1288,7 +1298,7 @@ DECLEXPORT(VBOXSTRICTRC) pgmPoolAccessPfHandler(PVM pVM, PVMCPU pVCpu, RTGCUINT
&& !fForcedFlush
&& (pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_PAE_PT || pPage->enmKind == PGMPOOLKIND_PAE_PT_FOR_32BIT_PT)
&& ( fNotReusedNotForking
- || ( !pgmPoolMonitorIsReused(pVM, pVCpu, pRegFrame, pDis, pvFault)
+ || ( !pgmPoolMonitorIsReused(pVM, pVCpu, pRegFrame, pDis, pvFault, pPage)
&& !pgmPoolMonitorIsForking(pPool, pDis, GCPhysFault & PAGE_OFFSET_MASK))
)
)
@@ -5447,7 +5457,6 @@ void pgmR3PoolReset(PVM pVM)
pPage->iModifiedPrev = NIL_PGMPOOL_IDX;
pPage->iMonitoredNext = NIL_PGMPOOL_IDX;
pPage->iMonitoredPrev = NIL_PGMPOOL_IDX;
- pPage->cModifications = 0;
pPage->GCPhys = NIL_RTGCPHYS;
pPage->enmKind = PGMPOOLKIND_FREE;
pPage->enmAccess = PGMPOOLACCESS_DONTCARE;
@@ -5461,8 +5470,12 @@ void pgmR3PoolReset(PVM pVM)
pPage->fCached = false;
pPage->fReusedFlushPending = false;
pPage->iUserHead = NIL_PGMPOOL_USER_INDEX;
+ pPage->cPresent = 0;
+ pPage->iFirstPresent = NIL_PGMPOOL_PRESENT_INDEX;
+ pPage->cModifications = 0;
pPage->iAgeNext = NIL_PGMPOOL_IDX;
pPage->iAgePrev = NIL_PGMPOOL_IDX;
+ pPage->idxDirtyEntry = 0;
pPage->GCPtrLastAccessHandlerRip = NIL_RTGCPTR;
pPage->GCPtrLastAccessHandlerFault = NIL_RTGCPTR;
pPage->cLastAccessHandler = 0;
diff --git a/src/VBox/VMM/VMMR0/HMR0.cpp b/src/VBox/VMM/VMMR0/HMR0.cpp
index bc970be..2ee79d1 100644
--- a/src/VBox/VMM/VMMR0/HMR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMR0.cpp
@@ -388,9 +388,13 @@ static int hmR0InitIntel(uint32_t u32FeaturesECX, uint32_t u32FeaturesEDX)
* Read all relevant registers and MSRs.
*/
g_HmR0.vmx.u64HostCr4 = ASMGetCR4();
- g_HmR0.vmx.u64HostSmmMonitorCtl = ASMRdMsr(MSR_IA32_SMM_MONITOR_CTL);
g_HmR0.vmx.u64HostEfer = ASMRdMsr(MSR_K6_EFER);
g_HmR0.vmx.Msrs.u64BasicInfo = ASMRdMsr(MSR_IA32_VMX_BASIC_INFO);
+ /* KVM workaround: Intel SDM section 34.15.5 describes that MSR_IA32_SMM_MONITOR_CTL
+ * depends on bit 49 of MSR_IA32_VMX_BASIC_INFO while table 35-2 says that this MSR
+ * is available if either VMX or SMX is supported. */
+ if (MSR_IA32_VMX_BASIC_INFO_VMCS_DUAL_MON(g_HmR0.vmx.Msrs.u64BasicInfo))
+ g_HmR0.vmx.u64HostSmmMonitorCtl = ASMRdMsr(MSR_IA32_SMM_MONITOR_CTL);
g_HmR0.vmx.Msrs.VmxPinCtls.u = ASMRdMsr(MSR_IA32_VMX_PINBASED_CTLS);
g_HmR0.vmx.Msrs.VmxProcCtls.u = ASMRdMsr(MSR_IA32_VMX_PROCBASED_CTLS);
g_HmR0.vmx.Msrs.VmxExit.u = ASMRdMsr(MSR_IA32_VMX_EXIT_CTLS);
diff --git a/src/VBox/VMM/VMMR0/HMVMXR0.cpp b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
index d61c2ab..2ea22f0 100644
--- a/src/VBox/VMM/VMMR0/HMVMXR0.cpp
+++ b/src/VBox/VMM/VMMR0/HMVMXR0.cpp
@@ -7152,9 +7152,9 @@ static int hmR0VmxLeave(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fSaveGuestState)
/* Restore host FPU state if necessary and resync on next R0 reentry .*/
if (CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu))
{
- if (fSaveGuestState)
+ /* We shouldn't reload CR0 without saving it first. */
+ if (!fSaveGuestState)
{
- /* We shouldn't reload CR0 without saving it first. */
int rc = hmR0VmxSaveGuestCR0(pVCpu, pMixedCtx);
AssertRCReturn(rc, rc);
}
@@ -11609,6 +11609,7 @@ HMVMX_EXIT_DECL hmR0VmxExitVmcall(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIEN
#else
/* Aggressive state sync. for now. */
int rc = hmR0VmxSaveGuestRip(pVCpu, pMixedCtx);
+ rc |= hmR0VmxSaveGuestRflags(pVCpu,pMixedCtx); /* For CPL checks in gimHvHypercall() & gimKvmHypercall() */
rc |= hmR0VmxSaveGuestSegmentRegs(pVCpu, pMixedCtx); /* For long-mode checks in gimKvmHypercall(). */
AssertRCReturn(rc, rc);
#endif
@@ -12144,9 +12145,18 @@ HMVMX_EXIT_DECL hmR0VmxExitWrmsr(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT
{
switch (pMixedCtx->ecx)
{
- case MSR_IA32_SYSENTER_CS: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR); break;
- case MSR_IA32_SYSENTER_EIP: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR); break;
- case MSR_IA32_SYSENTER_ESP: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR); break;
+ case MSR_IA32_SYSENTER_CS:
+ HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_CS_MSR);
+ HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_CS_MSR);
+ break;
+ case MSR_IA32_SYSENTER_EIP:
+ HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_EIP_MSR);
+ HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_EIP_MSR);
+ break;
+ case MSR_IA32_SYSENTER_ESP:
+ HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
+ HMVMXCPU_GST_SET_UPDATED(pVCpu, HMVMX_UPDATED_GUEST_SYSENTER_ESP_MSR);
+ break;
case MSR_K8_FS_BASE: /* no break */
case MSR_K8_GS_BASE: HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS); break;
case MSR_K6_EFER: /* already handled above */ break;
diff --git a/src/VBox/VMM/VMMR3/CFGM.cpp b/src/VBox/VMM/VMMR3/CFGM.cpp
index 77510a2..5276a82 100644
--- a/src/VBox/VMM/VMMR3/CFGM.cpp
+++ b/src/VBox/VMM/VMMR3/CFGM.cpp
@@ -1040,10 +1040,6 @@ VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM)
UPDATERC();
rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
UPDATERC();
- rc = CFGMR3InsertInteger(pCfg, "RamSize", 128U * _1M);
- UPDATERC();
- rc = CFGMR3InsertInteger(pCfg, "RamHoleSize", 512U * _1M);
- UPDATERC();
rc = CFGMR3InsertString(pCfg, "BootDevice0", "IDE");
UPDATERC();
rc = CFGMR3InsertString(pCfg, "BootDevice1", "NONE");
@@ -1205,8 +1201,6 @@ VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM)
UPDATERC();
rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */
UPDATERC();
- rc = CFGMR3InsertInteger(pCfg, "RamSize", 128U * _1M);
- UPDATERC();
/*
diff --git a/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp b/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
index 789dbef..c264db7 100644
--- a/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
+++ b/src/VBox/VMM/VMMR3/CPUMR3CpuId.cpp
@@ -1629,6 +1629,7 @@ int cpumR3CpuIdExplodeFeatures(PCCPUMCPUIDLEAF paLeaves, uint32_t cLeaves, PCPUM
pFeatures->fSysEnter = RT_BOOL(pStd1Leaf->uEdx & X86_CPUID_FEATURE_EDX_SEP);
pFeatures->fHypervisorPresent = RT_BOOL(pStd1Leaf->uEcx & X86_CPUID_FEATURE_ECX_HVP);
pFeatures->fMonitorMWait = RT_BOOL(pStd1Leaf->uEcx & X86_CPUID_FEATURE_ECX_MONITOR);
+ pFeatures->fMovCmpXchg16b = RT_BOOL(pStd1Leaf->uEcx & X86_CPUID_FEATURE_ECX_CX16);
/* Structured extended features. */
PCCPUMCPUIDLEAF const pSxfLeaf0 = cpumR3CpuIdFindLeafEx(paLeaves, cLeaves, 7, 0);
@@ -5223,7 +5224,7 @@ int cpumR3LoadCpuIdInner(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, PCPUMCPUID
CPUID_GST_FEATURE_RET(Std, uEdx, X86_CPUID_FEATURE_EDX_SSE); // -> EMU
CPUID_GST_FEATURE_RET(Std, uEdx, X86_CPUID_FEATURE_EDX_SSE2); // -> EMU
CPUID_GST_FEATURE_RET(Std, uEdx, X86_CPUID_FEATURE_EDX_SS); // -> EMU?
- CPUID_GST_FEATURE_RET(Std, uEdx, X86_CPUID_FEATURE_EDX_HTT); // -> EMU?
+ CPUID_GST_FEATURE_IGN(Std, uEdx, X86_CPUID_FEATURE_EDX_HTT); // -> EMU?
CPUID_GST_FEATURE_RET(Std, uEdx, X86_CPUID_FEATURE_EDX_TM); // -> EMU?
CPUID_GST_FEATURE_RET(Std, uEdx, RT_BIT_32(30) /*JMPE/IA64*/); // -> EMU
CPUID_GST_FEATURE_RET(Std, uEdx, X86_CPUID_FEATURE_EDX_PBE); // -> EMU?
diff --git a/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp b/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp
index 6c9e778..3250800 100644
--- a/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp
+++ b/src/VBox/VMM/VMMR3/DBGFAddrSpace.cpp
@@ -232,7 +232,6 @@ int dbgfR3AsInit(PUVM pUVM)
AssertRCReturn(rc, rc);
rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
AssertRCReturn(rc, rc);
- RTDbgAsRetain(hDbgAs);
pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_GLOBAL)] = hDbgAs;
RTDbgAsRetain(hDbgAs);
@@ -242,14 +241,12 @@ int dbgfR3AsInit(PUVM pUVM)
AssertRCReturn(rc, rc);
rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
AssertRCReturn(rc, rc);
- RTDbgAsRetain(hDbgAs);
pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_PHYS)] = hDbgAs;
rc = RTDbgAsCreate(&hDbgAs, 0, RTRCPTR_MAX, "HyperRawMode");
AssertRCReturn(rc, rc);
rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
AssertRCReturn(rc, rc);
- RTDbgAsRetain(hDbgAs);
pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC)] = hDbgAs;
RTDbgAsRetain(hDbgAs);
pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_RC_AND_GC_GLOBAL)] = hDbgAs;
@@ -258,7 +255,6 @@ int dbgfR3AsInit(PUVM pUVM)
AssertRCReturn(rc, rc);
rc = DBGFR3AsAdd(pUVM, hDbgAs, NIL_RTPROCESS);
AssertRCReturn(rc, rc);
- RTDbgAsRetain(hDbgAs);
pUVM->dbgf.s.ahAsAliases[DBGF_AS_ALIAS_2_INDEX(DBGF_AS_R0)] = hDbgAs;
return VINF_SUCCESS;
@@ -307,6 +303,12 @@ void dbgfR3AsTerm(PUVM pUVM)
RTDbgAsRelease(pUVM->dbgf.s.ahAsAliases[i]);
pUVM->dbgf.s.ahAsAliases[i] = NIL_RTDBGAS;
}
+
+ /*
+ * Release the reference to the debugging config.
+ */
+ rc = RTDbgCfgRelease(pUVM->dbgf.s.hDbgCfg);
+ AssertRC(rc);
}
diff --git a/src/VBox/VMM/VMMR3/EM.cpp b/src/VBox/VMM/VMMR3/EM.cpp
index 8031695..c1e651d 100644
--- a/src/VBox/VMM/VMMR3/EM.cpp
+++ b/src/VBox/VMM/VMMR3/EM.cpp
@@ -479,7 +479,9 @@ VMMR3_INT_DECL(void) EMR3Relocate(PVM pVM)
*/
VMMR3_INT_DECL(void) EMR3ResetCpu(PVMCPU pVCpu)
{
+ /* Reset scheduling state. */
pVCpu->em.s.fForceRAW = false;
+ VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_UNHALT);
/* VMR3ResetFF may return VINF_EM_RESET or VINF_EM_SUSPEND, so transition
out of the HALTED state here so that enmPrevState doesn't end up as
@@ -1344,7 +1346,7 @@ static VBOXSTRICTRC emR3ExecuteIemThenRem(PVM pVM, PVMCPU pVCpu, bool *pfFFDone)
* Check for pending actions.
*/
if ( VM_FF_IS_PENDING(pVM, VM_FF_ALL_REM_MASK)
- || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_ALL_REM_MASK))
+ || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_ALL_REM_MASK & ~VMCPU_FF_UNHALT))
return VINF_SUCCESS;
}
@@ -1899,23 +1901,8 @@ int emR3ForcedActions(PVM pVM, PVMCPU pVCpu, int rc)
}
}
- /*
- * Forced unhalting of EMT.
- */
- if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_UNHALT))
- {
- VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_UNHALT);
- if (rc == VINF_EM_HALT)
- rc = VINF_EM_RESCHEDULE;
- else
- {
- rc2 = VINF_EM_RESCHEDULE;
- UPDATE_RC();
- }
- }
-
/* check that we got them all */
- Assert(!(VMCPU_FF_NORMAL_PRIORITY_MASK & ~(VMCPU_FF_REQUEST | VMCPU_FF_UNHALT)));
+ Assert(!(VMCPU_FF_NORMAL_PRIORITY_MASK & ~VMCPU_FF_REQUEST));
}
/*
@@ -2214,7 +2201,7 @@ VMMR3_INT_DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
&& rc != VINF_EM_TERMINATE
&& rc != VINF_EM_OFF
&& ( VM_FF_IS_PENDING(pVM, VM_FF_ALL_REM_MASK)
- || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_ALL_REM_MASK)))
+ || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_ALL_REM_MASK & ~VMCPU_FF_UNHALT)))
{
rc = emR3ForcedActions(pVM, pVCpu, rc);
VBOXVMM_EM_FF_ALL_RET(pVCpu, rc);
@@ -2486,9 +2473,10 @@ VMMR3_INT_DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
{
VBOXVMM_EM_STATE_CHANGED(pVCpu, enmOldState, enmNewState, rc);
- /* Clear MWait flags. */
+ /* Clear MWait flags and the unhalt FF. */
if ( enmOldState == EMSTATE_HALTED
- && (pVCpu->em.s.MWait.fWait & EMMWAIT_FLAG_ACTIVE)
+ && ( (pVCpu->em.s.MWait.fWait & EMMWAIT_FLAG_ACTIVE)
+ || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_UNHALT))
&& ( enmNewState == EMSTATE_RAW
|| enmNewState == EMSTATE_HM
|| enmNewState == EMSTATE_REM
@@ -2498,8 +2486,16 @@ VMMR3_INT_DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu)
|| enmNewState == EMSTATE_DEBUG_GUEST_IEM
|| enmNewState == EMSTATE_DEBUG_GUEST_REM) )
{
- LogFlow(("EMR3ExecuteVM: Clearing MWAIT\n"));
- pVCpu->em.s.MWait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0);
+ if (pVCpu->em.s.MWait.fWait & EMMWAIT_FLAG_ACTIVE)
+ {
+ LogFlow(("EMR3ExecuteVM: Clearing MWAIT\n"));
+ pVCpu->em.s.MWait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0);
+ }
+ if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_UNHALT))
+ {
+ LogFlow(("EMR3ExecuteVM: Clearing UNHALT\n"));
+ VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_UNHALT);
+ }
}
}
else
diff --git a/src/VBox/VMM/VMMR3/MMHyper.cpp b/src/VBox/VMM/VMMR3/MMHyper.cpp
index 81450a9..ac34619 100644
--- a/src/VBox/VMM/VMMR3/MMHyper.cpp
+++ b/src/VBox/VMM/VMMR3/MMHyper.cpp
@@ -1042,6 +1042,8 @@ VMMR3DECL(int) MMR3HyperAllocOnceNoRelEx(PVM pVM, size_t cb, unsigned uAlignment
paPages,
MMR3HeapAPrintf(pVM, MM_TAG_MM, "alloc once (%s)", mmGetTagName(enmTag)),
&GCPtr);
+ /* not needed anymore */
+ RTMemTmpFree(paPages);
if (RT_SUCCESS(rc))
{
*ppv = pvPages;
diff --git a/src/VBox/VMM/VMMR3/PDMAsyncCompletionFile.cpp b/src/VBox/VMM/VMMR3/PDMAsyncCompletionFile.cpp
index cf482be..749b0f2 100644
--- a/src/VBox/VMM/VMMR3/PDMAsyncCompletionFile.cpp
+++ b/src/VBox/VMM/VMMR3/PDMAsyncCompletionFile.cpp
@@ -538,6 +538,7 @@ static void pdmacFileAioMgrDestroy(PPDMASYNCCOMPLETIONEPCLASSFILE pEpClassFile,
/* Free the resources. */
RTCritSectDelete(&pAioMgr->CritSectBlockingEvent);
RTSemEventDestroy(pAioMgr->EventSem);
+ RTSemEventDestroy(pAioMgr->EventSemBlock);
if (pAioMgr->enmMgrType != PDMACEPFILEMGRTYPE_SIMPLE)
pdmacFileAioMgrNormalDestroy(pAioMgr);
@@ -1152,6 +1153,8 @@ static DECLCALLBACK(int) pdmacFileEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)
/* Destroy the locked ranges tree now. */
RTAvlrFileOffsetDestroy(pEpFile->AioMgr.pTreeRangesLocked, pdmacFileEpRangesLockedDestroy, NULL);
+ RTMemFree(pEpFile->AioMgr.pTreeRangesLocked);
+ pEpFile->AioMgr.pTreeRangesLocked = NULL;
RTFileClose(pEpFile->hFile);
diff --git a/src/VBox/VMM/VMMR3/PDMBlkCache.cpp b/src/VBox/VMM/VMMR3/PDMBlkCache.cpp
index 47b7ace..0e10012 100644
--- a/src/VBox/VMM/VMMR3/PDMBlkCache.cpp
+++ b/src/VBox/VMM/VMMR3/PDMBlkCache.cpp
@@ -1445,6 +1445,8 @@ VMMR3DECL(void) PDMR3BlkCacheRelease(PPDMBLKCACHE pBlkCache)
pdmBlkCacheLockLeave(pCache);
+ RTMemFree(pBlkCache->pTree);
+ pBlkCache->pTree = NULL;
RTSemRWDestroy(pBlkCache->SemRWEntries);
#ifdef VBOX_WITH_STATISTICS
diff --git a/src/VBox/VMM/VMMR3/PGM.cpp b/src/VBox/VMM/VMMR3/PGM.cpp
index fb989ab..1ecbd72 100644
--- a/src/VBox/VMM/VMMR3/PGM.cpp
+++ b/src/VBox/VMM/VMMR3/PGM.cpp
@@ -2545,6 +2545,7 @@ VMMR3DECL(void) PGMR3ResetCpu(PVM pVM, PVMCPU pVCpu)
{
int rc = PGM_GST_PFN(Exit, pVCpu)(pVCpu);
AssertRC(rc);
+ pVCpu->pgm.s.GCPhysCR3 = NIL_RTGCPHYS;
rc = PGMR3ChangeMode(pVM, pVCpu, PGMMODE_REAL);
AssertRC(rc);
@@ -2599,6 +2600,7 @@ VMMR3_INT_DECL(void) PGMR3Reset(PVM pVM)
PVMCPU pVCpu = &pVM->aCpus[i];
int rc = PGM_GST_PFN(Exit, pVCpu)(pVCpu);
AssertReleaseRC(rc);
+ pVCpu->pgm.s.GCPhysCR3 = NIL_RTGCPHYS;
}
#ifdef DEBUG
@@ -3509,6 +3511,7 @@ VMMR3DECL(int) PGMR3ChangeMode(PVM pVM, PVMCPU pVCpu, PGMMODE enmGuestMode)
return rc;
}
}
+ pVCpu->pgm.s.GCPhysCR3 = NIL_RTGCPHYS;
/*
* Load new paging mode data.
@@ -3679,7 +3682,7 @@ VMMR3DECL(int) PGMR3ChangeMode(PVM pVM, PVMCPU pVCpu, PGMMODE enmGuestMode)
#ifdef VBOX_WITH_64_BITS_GUESTS
case PGMMODE_AMD64_NX:
case PGMMODE_AMD64:
- GCPhysCR3 = CPUMGetGuestCR3(pVCpu) & UINT64_C(0xfffffffffffff000); /** @todo define this mask! */
+ GCPhysCR3 = CPUMGetGuestCR3(pVCpu) & X86_CR3_AMD64_PAGE_MASK;
rc = PGM_GST_NAME_AMD64(Enter)(pVCpu, GCPhysCR3);
switch (pVCpu->pgm.s.enmShadowMode)
{
@@ -3708,6 +3711,9 @@ VMMR3DECL(int) PGMR3ChangeMode(PVM pVM, PVMCPU pVCpu, PGMMODE enmGuestMode)
break;
}
+ /* Set the new guest CR3. */
+ pVCpu->pgm.s.GCPhysCR3 = GCPhysCR3;
+
/* status codes. */
AssertRC(rc);
AssertRC(rc2);
diff --git a/src/VBox/VMM/include/GIMHvInternal.h b/src/VBox/VMM/include/GIMHvInternal.h
index 13c443f..8febf13 100644
--- a/src/VBox/VMM/include/GIMHvInternal.h
+++ b/src/VBox/VMM/include/GIMHvInternal.h
@@ -441,17 +441,17 @@ AssertCompile(MSR_GIM_HV_RANGE11_START <= MSR_GIM_HV_RANGE11_END);
/** An open-source operating system. */
#define MSR_GIM_HV_GUEST_OS_ID_IS_OPENSOURCE(a) RT_BOOL((a) & RT_BIT_64(63))
/** Vendor ID. */
-#define MSR_GIM_HV_GUEST_OS_ID_VENDOR(a) (((a) >> 48) & 0xfff)
+#define MSR_GIM_HV_GUEST_OS_ID_VENDOR(a) (uint32_t)(((a) >> 48) & 0xfff)
/** Guest OS variant, depending on the vendor ID. */
-#define MSR_GIM_HV_GUEST_OS_ID_OS_VARIANT(a) (((a) >> 40) & 0xff)
+#define MSR_GIM_HV_GUEST_OS_ID_OS_VARIANT(a) (uint32_t)(((a) >> 40) & 0xff)
/** Guest OS major version. */
-#define MSR_GIM_HV_GUEST_OS_ID_MAJOR_VERSION(a) (((a) >> 32) & 0xff)
+#define MSR_GIM_HV_GUEST_OS_ID_MAJOR_VERSION(a) (uint32_t)(((a) >> 32) & 0xff)
/** Guest OS minor version. */
-#define MSR_GIM_HV_GUEST_OS_ID_MINOR_VERSION(a) (((a) >> 24) & 0xff)
+#define MSR_GIM_HV_GUEST_OS_ID_MINOR_VERSION(a) (uint32_t)(((a) >> 24) & 0xff)
/** Guest OS service version (e.g. service pack number in case of Windows). */
-#define MSR_GIM_HV_GUEST_OS_ID_SERVICE_VERSION(a) (((a) >> 16) & 0xff)
+#define MSR_GIM_HV_GUEST_OS_ID_SERVICE_VERSION(a) (uint32_t)(((a) >> 16) & 0xff)
/** Guest OS build number. */
-#define MSR_GIM_HV_GUEST_OS_ID_BUILD(a) ((a) & 0xffff)
+#define MSR_GIM_HV_GUEST_OS_ID_BUILD(a) (uint32_t)((a) & 0xffff)
/** @} */
/** @name Hyper-V MSR - APIC-assist page (MSR_GIM_HV_APIC_ASSIST_PAGE).
diff --git a/src/VBox/VMM/testcase/tstAnimate.cpp b/src/VBox/VMM/testcase/tstAnimate.cpp
index 3ecc63d..9dc8d40 100644
--- a/src/VBox/VMM/testcase/tstAnimate.cpp
+++ b/src/VBox/VMM/testcase/tstAnimate.cpp
@@ -412,8 +412,6 @@ static DECLCALLBACK(int) cfgmR3CreateDefault(PUVM pUVM, PVM pVM, void *pvUser)
UPDATERC();
rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
UPDATERC();
- rc = CFGMR3InsertInteger(pCfg, "RamSize", cbMem);
- UPDATERC();
rc = CFGMR3InsertString(pCfg, "BootDevice0", "IDE");
UPDATERC();
rc = CFGMR3InsertString(pCfg, "BootDevice1", "NONE");
@@ -446,7 +444,6 @@ static DECLCALLBACK(int) cfgmR3CreateDefault(PUVM pUVM, PVM pVM, void *pvUser)
rc = CFGMR3InsertNode(pDev, "0", &pInst); UPDATERC();
rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ UPDATERC();
rc = CFGMR3InsertNode(pInst, "Config", &pCfg); UPDATERC();
- rc = CFGMR3InsertInteger(pCfg, "RamSize", cbMem); UPDATERC();
rc = CFGMR3InsertInteger(pCfg, "IOAPIC", fIOAPIC); UPDATERC();
rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 7); UPDATERC();
rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); UPDATERC();
diff --git a/src/VBox/VMM/testcase/tstIEMCheckMc.cpp b/src/VBox/VMM/testcase/tstIEMCheckMc.cpp
index 549eafe..1a3902b 100644
--- a/src/VBox/VMM/testcase/tstIEMCheckMc.cpp
+++ b/src/VBox/VMM/testcase/tstIEMCheckMc.cpp
@@ -328,6 +328,7 @@ IEMOPMEDIAF2 g_iemAImpl_pcmpeqd;
#define IEM_MC_SET_RIP_U64(a_u64NewIP) CHK_TYPE(uint64_t, a_u64NewIP)
#define IEM_MC_RAISE_DIVIDE_ERROR() return VERR_TRPM_ACTIVE_TRAP
#define IEM_MC_MAYBE_RAISE_DEVICE_NOT_AVAILABLE() do {} while (0)
+#define IEM_MC_MAYBE_RAISE_WAIT_DEVICE_NOT_AVAILABLE() do {} while (0)
#define IEM_MC_MAYBE_RAISE_FPU_XCPT() do {} while (0)
#define IEM_MC_MAYBE_RAISE_MMX_RELATED_XCPT() do {} while (0)
#define IEM_MC_MAYBE_RAISE_MMX_RELATED_XCPT_CHECK_SSE_OR_MMXEXT() do {} while (0)
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c
index 3711c3e..54aed10 100644
--- a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c
@@ -42,10 +42,10 @@ BS3_CMN_DEF(void, Bs3Trap16SetGate,(uint8_t iIdt, uint8_t bType, uint8_t bDpl, u
pIdte->Gate.u16OffsetLow = (uint16_t)off;
pIdte->Gate.u16OffsetHigh = 0;
pIdte->Gate.u16Sel = uSel;
- pIdte->Gate.u4ParmCount = cParams;
+ pIdte->Gate.u5ParmCount = cParams;
pIdte->Gate.u4Type = bType;
pIdte->Gate.u2Dpl = bDpl;
- pIdte->Gate.u4Reserved = 0;
+ pIdte->Gate.u3Reserved = 0;
pIdte->Gate.u1DescType = 0; /* system */
pIdte->Gate.u1Present = 1;
}
diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c
index 6b95e1b..a7c74c5 100644
--- a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c
+++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c
@@ -42,10 +42,10 @@ BS3_CMN_DEF(void, Bs3Trap32SetGate,(uint8_t iIdt, uint8_t bType, uint8_t bDpl, u
pIdte->Gate.u16OffsetLow = (uint16_t)off;
pIdte->Gate.u16OffsetHigh = (uint16_t)(off >> 16);
pIdte->Gate.u16Sel = uSel;
- pIdte->Gate.u4ParmCount = cParams;
+ pIdte->Gate.u5ParmCount = cParams;
pIdte->Gate.u4Type = bType;
pIdte->Gate.u2Dpl = bDpl;
- pIdte->Gate.u4Reserved = 0;
+ pIdte->Gate.u3Reserved = 0;
pIdte->Gate.u1DescType = 0; /* system */
pIdte->Gate.u1Present = 1;
}
diff --git a/src/libs/Makefile.kmk b/src/libs/Makefile.kmk
index 994dff6..0eca838 100644
--- a/src/libs/Makefile.kmk
+++ b/src/libs/Makefile.kmk
@@ -59,12 +59,12 @@ endif
if !defined(VBOX_ONLY_SDK) \
&& ( "$(SDK_VBOX_OPENSSL_INCS)" == "$(SDK_VBOX_OPENSSL_VBOX_DEFAULT_INCS)" \
|| defined(VBOX_WITH_EXTPACK_PUEL_BUILD))
- include $(PATH_SUB_CURRENT)/openssl-1.1.0c/Makefile.kmk
+ include $(PATH_SUB_CURRENT)/openssl-1.1.0e/Makefile.kmk
endif
# libjpeg for VRDP video redirection and ExtPack's DrvHostWebcam
if defined(VBOX_WITH_VRDP) || defined(VBOX_WITH_EXTPACK_PUEL)
- include $(PATH_SUB_CURRENT)/jpeg-8a/Makefile.kmk
+ include $(PATH_SUB_CURRENT)/jpeg-9b/Makefile.kmk
endif
# Main related things - XPCOM and XSLT.
@@ -87,8 +87,8 @@ if defined(VBOX_WITH_MAIN) \
endif
if !defined(VBOX_ONLY_EXTPACKS_USE_IMPLIBS)
- ifeq ($(SDK_VBOX_LIBXML2_INCS),$(PATH_ROOT)/src/libs/libxml2-2.9.2/include)
- include $(PATH_SUB_CURRENT)/libxml2-2.9.2/Makefile.kmk
+ ifeq ($(SDK_VBOX_LIBXML2_INCS),$(PATH_ROOT)/src/libs/libxml2-2.9.4/include)
+ include $(PATH_SUB_CURRENT)/libxml2-2.9.4/Makefile.kmk
endif
endif
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c b/src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c
index cf48d23..65b67a0 100644
--- a/src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c
+++ b/src/libs/xpcom18a4/nsprpub/pr/src/io/prlayer.c
@@ -667,9 +667,10 @@ retry:
if ((NULL != names) && (length >= identity))
{
/* what we did is still okay */
- memcpy(
- names, identity_cache.name,
- identity_cache.length * sizeof(char*));
+ if (identity_cache.length)
+ memcpy(
+ names, identity_cache.name,
+ identity_cache.length * sizeof(char*));
old = identity_cache.name;
identity_cache.name = names;
identity_cache.length = length;
diff --git a/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp
index 9439a57..f68f2d5 100644
--- a/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp
+++ b/src/libs/xpcom18a4/xpcom/base/nsExceptionService.cpp
@@ -44,8 +44,8 @@
#include "prlock.h"
static const PRUintn BAD_TLS_INDEX = (PRUintn) -1;
-#define CHECK_SERVICE_USE_OK() if (!lock) return NS_ERROR_NOT_INITIALIZED
-#define CHECK_MANAGER_USE_OK() if (!mService || !nsExceptionService::lock) return NS_ERROR_NOT_INITIALIZED
+#define CHECK_SERVICE_USE_OK() if (tlsIndex == BAD_TLS_INDEX) return NS_ERROR_NOT_INITIALIZED
+#define CHECK_MANAGER_USE_OK() if (!mService || nsExceptionService::tlsIndex == BAD_TLS_INDEX) return NS_ERROR_NOT_INITIALIZED
// A key for our registered module providers hashtable
class nsProviderKey : public nsHashKey {
@@ -224,7 +224,9 @@ void nsExceptionService::ThreadDestruct( void *data )
void nsExceptionService::Shutdown()
{
- PR_SetThreadPrivate(tlsIndex, nsnull);
+ PRUintn tmp = tlsIndex;
+ tlsIndex = BAD_TLS_INDEX;
+ PR_SetThreadPrivate(tmp, nsnull);
mProviders.Reset();
if (lock) {
DropAllThreads();
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-virtualbox/virtualbox.git
More information about the Pkg-virtualbox-commits
mailing list