From 0cc911f974075c78578851c7cccd420855227f00 Mon Sep 17 00:00:00 2001 From: chayleaf Date: Wed, 3 Jul 2024 19:43:27 +0700 Subject: [PATCH] split osu-wine into a separate flake --- flake.lock | 57 +- flake.nix | 4 + pkgs/default.nix | 2 +- .../audio-revert/mmdevapi/Makefile.in | 9 - .../audio-revert/mmdevapi/audiovolume.c | 320 - pkgs/osu-wine/audio-revert/mmdevapi/devenum.c | 1627 ----- pkgs/osu-wine/audio-revert/mmdevapi/main.c | 470 -- .../osu-wine/audio-revert/mmdevapi/mmdevapi.h | 76 - .../audio-revert/mmdevapi/mmdevapi.spec | 21 - .../mmdevapi/mmdevapi_classes.idl | 28 - .../audio-revert/mmdevapi/spatialaudio.c | 976 --- .../audio-revert/mmdevapi/tests/Makefile.in | 10 - .../audio-revert/mmdevapi/tests/capture.c | 1055 --- .../audio-revert/mmdevapi/tests/dependency.c | 98 - .../audio-revert/mmdevapi/tests/mmdevenum.c | 484 -- .../audio-revert/mmdevapi/tests/propstore.c | 254 - .../audio-revert/mmdevapi/tests/render.c | 2425 ------- .../mmdevapi/tests/spatialaudio.c | 506 -- pkgs/osu-wine/audio-revert/mmdevapi/unixlib.h | 336 - .../audio-revert/winealsa.drv/Makefile.in | 11 - .../osu-wine/audio-revert/winealsa.drv/alsa.c | 2899 --------- .../audio-revert/winealsa.drv/alsamidi.c | 1877 ------ .../osu-wine/audio-revert/winealsa.drv/midi.c | 157 - .../audio-revert/winealsa.drv/mmdevdrv.c | 2484 -------- .../audio-revert/winealsa.drv/mmdevdrv.c.orig | 2475 ------- .../audio-revert/winealsa.drv/unixlib.h | 32 - .../winealsa.drv/winealsa.drv.spec | 11 - .../winecoreaudio.drv/Makefile.in | 11 - .../winecoreaudio.drv/coreaudio.c | 2030 ------ .../winecoreaudio.drv/coreaudio.h | 36 - .../audio-revert/winecoreaudio.drv/coremidi.c | 1614 ----- .../audio-revert/winecoreaudio.drv/midi.c | 226 - .../audio-revert/winecoreaudio.drv/mmdevdrv.c | 2414 ------- .../audio-revert/winecoreaudio.drv/unixlib.h | 36 - .../winecoreaudio.drv/winecoreaudio.drv.spec | 10 - .../audio-revert/wineoss.drv/Makefile.in | 14 - pkgs/osu-wine/audio-revert/wineoss.drv/midi.c | 176 - .../audio-revert/wineoss.drv/midipatch.c | 293 - .../osu-wine/audio-revert/wineoss.drv/mmaux.c | 57 - .../audio-revert/wineoss.drv/mmdevdrv.c | 2385 ------- pkgs/osu-wine/audio-revert/wineoss.drv/oss.c | 2055 ------ .../audio-revert/wineoss.drv/ossmidi.c | 2177 ------- .../audio-revert/wineoss.drv/unixlib.h | 32 - .../audio-revert/wineoss.drv/wineoss.drv.spec | 11 - .../audio-revert/winepulse.drv/Makefile.in | 9 - .../audio-revert/winepulse.drv/mmdevdrv.c | 5663 ----------------- .../winepulse.drv/winepulse.drv.spec | 11 - pkgs/osu-wine/default.nix | 64 - pkgs/osu-wine/osu-wine.nix | 35 - pkgs/osu-wine/packages.nix | 57 - .../patches/0001-add-wine-unicode-again.patch | 207 - ...Set-default-DCT-algorithm-to-fastest.patch | 24 - .../patches/0001-revert-staging-alt-tab.patch | 253 - ...Implement-thread-priorities-on-Linux.patch | 292 - .../patches/0002-midi-fixed-revert.patch | 17 - .../0002-revert-mscvrt-ify-modules.patch | 198 - ...lback-to-RTKIT-for-thread-priorities.patch | 145 - ...p-THREAD_PRIORITY_IDLE-to-SCHED_IDLE.patch | 30 - ...ic-audio-priority-from-oglf-patchset.patch | 12 - ...er-IEEE-float-for-Direct-Sound-defau.patch | 36 - ...ait-for-low-level-hook-result-when-q.patch | 60 - .../9999-diffs-8bpp-copy-support.patch | 55 - .../9999-diffs-hide-wine-version.patch | 54 - ...-diffs-use-clock_nanosleep-for-delay.patch | 46 - .../patches/9999-map-import-crash-fix.patch | 13 - .../display-cache-less-frequent-update.patch | 82 - ...drv-Bypass-compositor-in-fullscreen-.patch | 70 - ...u-alt-tab-on-certain-window-managers.patch | 28 - ...drv-Add-OpenGL-latency-reduction-cod.patch | 324 - ...Implement-NtFlushProcessWriteBuffers.patch | 319 - .../patches/revert-x11-gnome-fix.patch | 27 - pkgs/osu-wine/sources.nix | 177 - 72 files changed, 61 insertions(+), 40528 deletions(-) delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/Makefile.in delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/audiovolume.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/devenum.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/main.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi.h delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi.spec delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi_classes.idl delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/spatialaudio.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/tests/Makefile.in delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/tests/capture.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/tests/dependency.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/tests/mmdevenum.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/tests/propstore.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/tests/render.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/tests/spatialaudio.c delete mode 100644 pkgs/osu-wine/audio-revert/mmdevapi/unixlib.h delete mode 100644 pkgs/osu-wine/audio-revert/winealsa.drv/Makefile.in delete mode 100644 pkgs/osu-wine/audio-revert/winealsa.drv/alsa.c delete mode 100644 pkgs/osu-wine/audio-revert/winealsa.drv/alsamidi.c delete mode 100644 pkgs/osu-wine/audio-revert/winealsa.drv/midi.c delete mode 100644 pkgs/osu-wine/audio-revert/winealsa.drv/mmdevdrv.c delete mode 100644 pkgs/osu-wine/audio-revert/winealsa.drv/mmdevdrv.c.orig delete mode 100644 pkgs/osu-wine/audio-revert/winealsa.drv/unixlib.h delete mode 100644 pkgs/osu-wine/audio-revert/winealsa.drv/winealsa.drv.spec delete mode 100644 pkgs/osu-wine/audio-revert/winecoreaudio.drv/Makefile.in delete mode 100644 pkgs/osu-wine/audio-revert/winecoreaudio.drv/coreaudio.c delete mode 100644 pkgs/osu-wine/audio-revert/winecoreaudio.drv/coreaudio.h delete mode 100644 pkgs/osu-wine/audio-revert/winecoreaudio.drv/coremidi.c delete mode 100644 pkgs/osu-wine/audio-revert/winecoreaudio.drv/midi.c delete mode 100644 pkgs/osu-wine/audio-revert/winecoreaudio.drv/mmdevdrv.c delete mode 100644 pkgs/osu-wine/audio-revert/winecoreaudio.drv/unixlib.h delete mode 100644 pkgs/osu-wine/audio-revert/winecoreaudio.drv/winecoreaudio.drv.spec delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/Makefile.in delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/midi.c delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/midipatch.c delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/mmaux.c delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/mmdevdrv.c delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/oss.c delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/ossmidi.c delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/unixlib.h delete mode 100644 pkgs/osu-wine/audio-revert/wineoss.drv/wineoss.drv.spec delete mode 100644 pkgs/osu-wine/audio-revert/winepulse.drv/Makefile.in delete mode 100644 pkgs/osu-wine/audio-revert/winepulse.drv/mmdevdrv.c delete mode 100644 pkgs/osu-wine/audio-revert/winepulse.drv/winepulse.drv.spec delete mode 100644 pkgs/osu-wine/default.nix delete mode 100644 pkgs/osu-wine/osu-wine.nix delete mode 100644 pkgs/osu-wine/packages.nix delete mode 100644 pkgs/osu-wine/patches/0001-add-wine-unicode-again.patch delete mode 100644 pkgs/osu-wine/patches/0001-libs-libjpeg-Set-default-DCT-algorithm-to-fastest.patch delete mode 100644 pkgs/osu-wine/patches/0001-revert-staging-alt-tab.patch delete mode 100644 pkgs/osu-wine/patches/0001-server-Implement-thread-priorities-on-Linux.patch delete mode 100644 pkgs/osu-wine/patches/0002-midi-fixed-revert.patch delete mode 100644 pkgs/osu-wine/patches/0002-revert-mscvrt-ify-modules.patch delete mode 100644 pkgs/osu-wine/patches/0002-server-Fallback-to-RTKIT-for-thread-priorities.patch delete mode 100644 pkgs/osu-wine/patches/0003-server-Map-THREAD_PRIORITY_IDLE-to-SCHED_IDLE.patch delete mode 100644 pkgs/osu-wine/patches/0003-thread-characteristic-audio-priority-from-oglf-patchset.patch delete mode 100644 pkgs/osu-wine/patches/9989-misc-ps0126-devenum-Register-IEEE-float-for-Direct-Sound-defau.patch delete mode 100644 pkgs/osu-wine/patches/9989-misc-ps0171-server-Don-t-wait-for-low-level-hook-result-when-q.patch delete mode 100644 pkgs/osu-wine/patches/9999-diffs-8bpp-copy-support.patch delete mode 100644 pkgs/osu-wine/patches/9999-diffs-hide-wine-version.patch delete mode 100644 pkgs/osu-wine/patches/9999-diffs-use-clock_nanosleep-for-delay.patch delete mode 100644 pkgs/osu-wine/patches/9999-map-import-crash-fix.patch delete mode 100644 pkgs/osu-wine/patches/display-cache-less-frequent-update.patch delete mode 100644 pkgs/osu-wine/patches/ps0071-p0002-winex11.drv-Bypass-compositor-in-fullscreen-.patch delete mode 100644 pkgs/osu-wine/patches/ps0128-HACK-Fix-osu-alt-tab-on-certain-window-managers.patch delete mode 100644 pkgs/osu-wine/patches/ps0417-p0002-winex11.drv-Add-OpenGL-latency-reduction-cod.patch delete mode 100644 pkgs/osu-wine/patches/ps0741-ntdll-Implement-NtFlushProcessWriteBuffers.patch delete mode 100644 pkgs/osu-wine/patches/revert-x11-gnome-fix.patch delete mode 100644 pkgs/osu-wine/sources.nix diff --git a/flake.lock b/flake.lock index e6f5ca1..b50ab94 100644 --- a/flake.lock +++ b/flake.lock @@ -285,6 +285,24 @@ "inputs": { "systems": "systems_3" }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_4" + }, "locked": { "lastModified": 1705309234, "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", @@ -700,6 +718,27 @@ "type": "github" } }, + "osu-wine": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1720010227, + "narHash": "sha256-ADhjhE6UMjcCgjycONnabDqJ7WR2O4SpoAYvmScLwgc=", + "owner": "chayleaf", + "repo": "osu-wine.nix", + "rev": "1406bb2c6ee6eaa8c1433516ef5d324eb651c3fc", + "type": "github" + }, + "original": { + "owner": "chayleaf", + "repo": "osu-wine.nix", + "type": "github" + } + }, "root": { "inputs": { "coop-fd": "coop-fd", @@ -718,12 +757,13 @@ "notlua": "notlua", "notnft": "notnft", "nur": "nur", + "osu-wine": "osu-wine", "rust-overlay": "rust-overlay" } }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils", + "flake-utils": "flake-utils_2", "nixpkgs": [ "nixpkgs" ] @@ -833,6 +873,21 @@ "type": "github" } }, + "systems_4": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, "treefmt-nix": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index 0829736..e6fcb58 100644 --- a/flake.nix +++ b/flake.nix @@ -17,6 +17,10 @@ url = "github:chayleaf/mobile-nixos/fix-op6-modem"; flake = false; }; + osu-wine = { + url = "github:chayleaf/osu-wine.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; impermanence.url = "github:nix-community/impermanence"; nur.url = "github:nix-community/NUR"; rust-overlay = { diff --git a/pkgs/default.nix b/pkgs/default.nix index 03c688c..959bf35 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -19,6 +19,7 @@ in { inherit (inputs.nix-gaming.packages.${pkgs.system}) faf-client osu-lazer-bin; + inherit (inputs.osu-wine.packages.${pkgs.system}) osu-wine; matrix-appservice-discord = pkgs.callPackage ./matrix-appservice-discord { inherit (pkgs) matrix-appservice-discord; }; openssh = pkgs.openssh.overrideAttrs (old: rec { @@ -54,7 +55,6 @@ in patches = [ ./looking-glass.patch ]; }); mobile-config-firefox = callPackage ./mobile-config-firefox { }; - osu-wine = callPackage ./osu-wine { }; ping-exporter = callPackage ./ping-exporter { }; proton-ge = pkgs.stdenvNoCC.mkDerivation { inherit (sources.proton-ge) pname version src; diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/Makefile.in b/pkgs/osu-wine/audio-revert/mmdevapi/Makefile.in deleted file mode 100644 index 612bc79..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/Makefile.in +++ /dev/null @@ -1,9 +0,0 @@ -MODULE = mmdevapi.dll -IMPORTS = uuid ole32 oleaut32 user32 advapi32 - -SOURCES = \ - audiovolume.c \ - devenum.c \ - main.c \ - mmdevapi_classes.idl \ - spatialaudio.c diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/audiovolume.c b/pkgs/osu-wine/audio-revert/mmdevapi/audiovolume.c deleted file mode 100644 index bbaba77..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/audiovolume.c +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2010 Maarten Lankhorst for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS - -#include - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "wine/debug.h" - -#include "ole2.h" -#include "mmdeviceapi.h" -#include "mmsystem.h" -#include "dsound.h" -#include "audioclient.h" -#include "endpointvolume.h" -#include "audiopolicy.h" -#include "spatialaudioclient.h" - -#include "mmdevapi.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); - -typedef struct AEVImpl { - IAudioEndpointVolumeEx IAudioEndpointVolumeEx_iface; - LONG ref; - float master_vol; - BOOL mute; -} AEVImpl; - -static inline AEVImpl *impl_from_IAudioEndpointVolumeEx(IAudioEndpointVolumeEx *iface) -{ - return CONTAINING_RECORD(iface, AEVImpl, IAudioEndpointVolumeEx_iface); -} - -static void AudioEndpointVolume_Destroy(AEVImpl *This) -{ - HeapFree(GetProcessHeap(), 0, This); -} - -static HRESULT WINAPI AEV_QueryInterface(IAudioEndpointVolumeEx *iface, REFIID riid, void **ppv) -{ - AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); - TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv); - if (!ppv) - return E_POINTER; - *ppv = NULL; - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioEndpointVolume) || - IsEqualIID(riid, &IID_IAudioEndpointVolumeEx)) { - *ppv = &This->IAudioEndpointVolumeEx_iface; - } - else - return E_NOINTERFACE; - IUnknown_AddRef((IUnknown *)*ppv); - return S_OK; -} - -static ULONG WINAPI AEV_AddRef(IAudioEndpointVolumeEx *iface) -{ - AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); - ULONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) new ref %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AEV_Release(IAudioEndpointVolumeEx *iface) -{ - AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); - ULONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) new ref %lu\n", This, ref); - if (!ref) - AudioEndpointVolume_Destroy(This); - return ref; -} - -static HRESULT WINAPI AEV_RegisterControlChangeNotify(IAudioEndpointVolumeEx *iface, IAudioEndpointVolumeCallback *notify) -{ - TRACE("(%p)->(%p)\n", iface, notify); - if (!notify) - return E_POINTER; - FIXME("stub\n"); - return S_OK; -} - -static HRESULT WINAPI AEV_UnregisterControlChangeNotify(IAudioEndpointVolumeEx *iface, IAudioEndpointVolumeCallback *notify) -{ - TRACE("(%p)->(%p)\n", iface, notify); - if (!notify) - return E_POINTER; - FIXME("stub\n"); - return S_OK; -} - -static HRESULT WINAPI AEV_GetChannelCount(IAudioEndpointVolumeEx *iface, UINT *count) -{ - TRACE("(%p)->(%p)\n", iface, count); - if (!count) - return E_POINTER; - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_SetMasterVolumeLevel(IAudioEndpointVolumeEx *iface, float leveldb, const GUID *ctx) -{ - AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); - - TRACE("(%p)->(%f,%s)\n", iface, leveldb, debugstr_guid(ctx)); - - if(leveldb < -100.f || leveldb > 0.f) - return E_INVALIDARG; - - This->master_vol = leveldb; - - return S_OK; -} - -static HRESULT WINAPI AEV_SetMasterVolumeLevelScalar(IAudioEndpointVolumeEx *iface, float level, const GUID *ctx) -{ - TRACE("(%p)->(%f,%s)\n", iface, level, debugstr_guid(ctx)); - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_GetMasterVolumeLevel(IAudioEndpointVolumeEx *iface, float *leveldb) -{ - AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); - - TRACE("(%p)->(%p)\n", iface, leveldb); - - if (!leveldb) - return E_POINTER; - - *leveldb = This->master_vol; - - return S_OK; -} - -static HRESULT WINAPI AEV_GetMasterVolumeLevelScalar(IAudioEndpointVolumeEx *iface, float *level) -{ - TRACE("(%p)->(%p)\n", iface, level); - if (!level) - return E_POINTER; - FIXME("stub\n"); - *level = 1.0; - return S_OK; -} - -static HRESULT WINAPI AEV_SetChannelVolumeLevel(IAudioEndpointVolumeEx *iface, UINT chan, float leveldb, const GUID *ctx) -{ - TRACE("(%p)->(%f,%s)\n", iface, leveldb, debugstr_guid(ctx)); - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_SetChannelVolumeLevelScalar(IAudioEndpointVolumeEx *iface, UINT chan, float level, const GUID *ctx) -{ - TRACE("(%p)->(%u,%f,%s)\n", iface, chan, level, debugstr_guid(ctx)); - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_GetChannelVolumeLevel(IAudioEndpointVolumeEx *iface, UINT chan, float *leveldb) -{ - TRACE("(%p)->(%u,%p)\n", iface, chan, leveldb); - if (!leveldb) - return E_POINTER; - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_GetChannelVolumeLevelScalar(IAudioEndpointVolumeEx *iface, UINT chan, float *level) -{ - TRACE("(%p)->(%u,%p)\n", iface, chan, level); - if (!level) - return E_POINTER; - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_SetMute(IAudioEndpointVolumeEx *iface, BOOL mute, const GUID *ctx) -{ - AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); - HRESULT ret; - - TRACE("(%p)->(%u,%s)\n", iface, mute, debugstr_guid(ctx)); - - ret = This->mute == mute ? S_FALSE : S_OK; - - This->mute = mute; - - return ret; -} - -static HRESULT WINAPI AEV_GetMute(IAudioEndpointVolumeEx *iface, BOOL *mute) -{ - AEVImpl *This = impl_from_IAudioEndpointVolumeEx(iface); - - TRACE("(%p)->(%p)\n", iface, mute); - - if (!mute) - return E_POINTER; - - *mute = This->mute; - - return S_OK; -} - -static HRESULT WINAPI AEV_GetVolumeStepInfo(IAudioEndpointVolumeEx *iface, UINT *stepsize, UINT *stepcount) -{ - TRACE("(%p)->(%p,%p)\n", iface, stepsize, stepcount); - if (!stepsize && !stepcount) - return E_POINTER; - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_VolumeStepUp(IAudioEndpointVolumeEx *iface, const GUID *ctx) -{ - TRACE("(%p)->(%s)\n", iface, debugstr_guid(ctx)); - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_VolumeStepDown(IAudioEndpointVolumeEx *iface, const GUID *ctx) -{ - TRACE("(%p)->(%s)\n", iface, debugstr_guid(ctx)); - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_QueryHardwareSupport(IAudioEndpointVolumeEx *iface, DWORD *mask) -{ - TRACE("(%p)->(%p)\n", iface, mask); - if (!mask) - return E_POINTER; - FIXME("stub\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI AEV_GetVolumeRange(IAudioEndpointVolumeEx *iface, float *mindb, float *maxdb, float *inc) -{ - TRACE("(%p)->(%p,%p,%p)\n", iface, mindb, maxdb, inc); - - if (!mindb || !maxdb || !inc) - return E_POINTER; - - *mindb = -100.f; - *maxdb = 0.f; - *inc = 1.f; - - return S_OK; -} - -static HRESULT WINAPI AEV_GetVolumeRangeChannel(IAudioEndpointVolumeEx *iface, UINT chan, float *mindb, float *maxdb, float *inc) -{ - TRACE("(%p)->(%p,%p,%p)\n", iface, mindb, maxdb, inc); - if (!mindb || !maxdb || !inc) - return E_POINTER; - FIXME("stub\n"); - return E_NOTIMPL; -} - -static const IAudioEndpointVolumeExVtbl AEVImpl_Vtbl = { - AEV_QueryInterface, - AEV_AddRef, - AEV_Release, - AEV_RegisterControlChangeNotify, - AEV_UnregisterControlChangeNotify, - AEV_GetChannelCount, - AEV_SetMasterVolumeLevel, - AEV_SetMasterVolumeLevelScalar, - AEV_GetMasterVolumeLevel, - AEV_GetMasterVolumeLevelScalar, - AEV_SetChannelVolumeLevel, - AEV_SetChannelVolumeLevelScalar, - AEV_GetChannelVolumeLevel, - AEV_GetChannelVolumeLevelScalar, - AEV_SetMute, - AEV_GetMute, - AEV_GetVolumeStepInfo, - AEV_VolumeStepUp, - AEV_VolumeStepDown, - AEV_QueryHardwareSupport, - AEV_GetVolumeRange, - AEV_GetVolumeRangeChannel -}; - -HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolumeEx **ppv) -{ - AEVImpl *This; - - *ppv = NULL; - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); - if (!This) - return E_OUTOFMEMORY; - This->IAudioEndpointVolumeEx_iface.lpVtbl = &AEVImpl_Vtbl; - This->ref = 1; - - *ppv = &This->IAudioEndpointVolumeEx_iface; - return S_OK; -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/devenum.c b/pkgs/osu-wine/audio-revert/mmdevapi/devenum.c deleted file mode 100644 index 69e13a4..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/devenum.c +++ /dev/null @@ -1,1627 +0,0 @@ -/* - * Copyright 2009 Maarten Lankhorst - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include - -#define NONAMELESSUNION -#define COBJMACROS -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "wine/debug.h" -#include "wine/list.h" - -#include "initguid.h" -#include "ole2.h" -#include "mmdeviceapi.h" -#include "dshow.h" -#include "dsound.h" -#include "audioclient.h" -#include "endpointvolume.h" -#include "audiopolicy.h" -#include "spatialaudioclient.h" - -#include "mmdevapi.h" -#include "devpkey.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); - -static HKEY key_render; -static HKEY key_capture; - -typedef struct MMDevPropStoreImpl -{ - IPropertyStore IPropertyStore_iface; - LONG ref; - MMDevice *parent; - DWORD access; -} MMDevPropStore; - -typedef struct MMDevEnumImpl -{ - IMMDeviceEnumerator IMMDeviceEnumerator_iface; - LONG ref; -} MMDevEnumImpl; - -static MMDevice *MMDevice_def_rec, *MMDevice_def_play; -static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl; -static const IMMDeviceCollectionVtbl MMDevColVtbl; -static const IMMDeviceVtbl MMDeviceVtbl; -static const IPropertyStoreVtbl MMDevPropVtbl; -static const IMMEndpointVtbl MMEndpointVtbl; - -static MMDevEnumImpl enumerator; -static struct list device_list = LIST_INIT(device_list); -static IMMDevice info_device; - -typedef struct MMDevColImpl -{ - IMMDeviceCollection IMMDeviceCollection_iface; - LONG ref; - EDataFlow flow; - DWORD state; -} MMDevColImpl; - -typedef struct IPropertyBagImpl { - IPropertyBag IPropertyBag_iface; - GUID devguid; -} IPropertyBagImpl; - -static const IPropertyBagVtbl PB_Vtbl; - -static HRESULT MMDevPropStore_Create(MMDevice *This, DWORD access, IPropertyStore **ppv); - -static inline MMDevPropStore *impl_from_IPropertyStore(IPropertyStore *iface) -{ - return CONTAINING_RECORD(iface, MMDevPropStore, IPropertyStore_iface); -} - -static inline MMDevEnumImpl *impl_from_IMMDeviceEnumerator(IMMDeviceEnumerator *iface) -{ - return CONTAINING_RECORD(iface, MMDevEnumImpl, IMMDeviceEnumerator_iface); -} - -static inline MMDevColImpl *impl_from_IMMDeviceCollection(IMMDeviceCollection *iface) -{ - return CONTAINING_RECORD(iface, MMDevColImpl, IMMDeviceCollection_iface); -} - -static inline IPropertyBagImpl *impl_from_IPropertyBag(IPropertyBag *iface) -{ - return CONTAINING_RECORD(iface, IPropertyBagImpl, IPropertyBag_iface); -} - -static const WCHAR propkey_formatW[] = L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X},%d"; - -static HRESULT MMDevPropStore_OpenPropKey(const GUID *guid, DWORD flow, HKEY *propkey) -{ - WCHAR buffer[39]; - LONG ret; - HKEY key; - StringFromGUID2(guid, buffer, 39); - if ((ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, buffer, 0, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, &key)) != ERROR_SUCCESS) - { - WARN("Opening key %s failed with %lu\n", debugstr_w(buffer), ret); - return E_FAIL; - } - ret = RegOpenKeyExW(key, L"Properties", 0, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, propkey); - RegCloseKey(key); - if (ret != ERROR_SUCCESS) - { - WARN("Opening key Properties failed with %lu\n", ret); - return E_FAIL; - } - return S_OK; -} - -static HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv) -{ - WCHAR buffer[80]; - const GUID *id = &key->fmtid; - DWORD type, size; - HRESULT hr = S_OK; - HKEY regkey; - LONG ret; - - hr = MMDevPropStore_OpenPropKey(devguid, flow, ®key); - if (FAILED(hr)) - return hr; - wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3, - id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], - id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid ); - ret = RegGetValueW(regkey, NULL, buffer, RRF_RT_ANY, &type, NULL, &size); - if (ret != ERROR_SUCCESS) - { - WARN("Reading %s returned %ld\n", debugstr_w(buffer), ret); - RegCloseKey(regkey); - pv->vt = VT_EMPTY; - return S_OK; - } - - switch (type) - { - case REG_SZ: - { - pv->vt = VT_LPWSTR; - pv->pwszVal = CoTaskMemAlloc(size); - if (!pv->pwszVal) - hr = E_OUTOFMEMORY; - else - RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_SZ, NULL, (BYTE*)pv->pwszVal, &size); - break; - } - case REG_DWORD: - { - pv->vt = VT_UI4; - RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_DWORD, NULL, (BYTE*)&pv->ulVal, &size); - break; - } - case REG_BINARY: - { - pv->vt = VT_BLOB; - pv->blob.cbSize = size; - pv->blob.pBlobData = CoTaskMemAlloc(size); - if (!pv->blob.pBlobData) - hr = E_OUTOFMEMORY; - else - RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, (BYTE*)pv->blob.pBlobData, &size); - break; - } - default: - ERR("Unknown/unhandled type: %lu\n", type); - PropVariantClear(pv); - break; - } - RegCloseKey(regkey); - return hr; -} - -static HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, REFPROPVARIANT pv) -{ - WCHAR buffer[80]; - const GUID *id = &key->fmtid; - HRESULT hr; - HKEY regkey; - LONG ret; - - hr = MMDevPropStore_OpenPropKey(devguid, flow, ®key); - if (FAILED(hr)) - return hr; - wsprintfW( buffer, propkey_formatW, id->Data1, id->Data2, id->Data3, - id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], - id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7], key->pid ); - switch (pv->vt) - { - case VT_UI4: - { - ret = RegSetValueExW(regkey, buffer, 0, REG_DWORD, (const BYTE*)&pv->ulVal, sizeof(DWORD)); - break; - } - case VT_BLOB: - { - ret = RegSetValueExW(regkey, buffer, 0, REG_BINARY, pv->blob.pBlobData, pv->blob.cbSize); - TRACE("Blob %p %lu\n", pv->blob.pBlobData, pv->blob.cbSize); - - break; - } - case VT_LPWSTR: - { - ret = RegSetValueExW(regkey, buffer, 0, REG_SZ, (const BYTE*)pv->pwszVal, sizeof(WCHAR)*(1+lstrlenW(pv->pwszVal))); - break; - } - default: - ret = 0; - FIXME("Unhandled type %u\n", pv->vt); - hr = E_INVALIDARG; - break; - } - RegCloseKey(regkey); - TRACE("Writing %s returned %lu\n", debugstr_w(buffer), ret); - return hr; -} - -static HRESULT set_driver_prop_value(GUID *id, const EDataFlow flow, const PROPERTYKEY *prop) -{ - HRESULT hr; - PROPVARIANT pv; - - if (!drvs.pGetPropValue) - return E_NOTIMPL; - - hr = drvs.pGetPropValue(id, prop, &pv); - - if (SUCCEEDED(hr)) - { - MMDevice_SetPropValue(id, flow, prop, &pv); - PropVariantClear(&pv); - } - - return hr; -} - -struct product_name_overrides -{ - const WCHAR *id; - const WCHAR *product; -}; - -static const struct product_name_overrides product_name_overrides[] = -{ - /* Sony controllers */ - { .id = L"VID_054C&PID_0CE6", .product = L"Wireless Controller" }, -}; - -static const WCHAR *find_product_name_override(const WCHAR *device_id) -{ - const WCHAR *match_id = wcschr( device_id, '\\' ) + 1; - DWORD i; - - for (i = 0; i < ARRAY_SIZE(product_name_overrides); ++i) - if (!wcsnicmp( product_name_overrides[i].id, match_id, 17 )) - return product_name_overrides[i].product; - - return NULL; -} - -/* Creates or updates the state of a device - * If GUID is null, a random guid will be assigned - * and the device will be created - */ -static MMDevice *MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault) -{ - HKEY key, root; - MMDevice *device, *cur = NULL; - WCHAR guidstr[39]; - - static const PROPERTYKEY deviceinterface_key = { - {0x233164c8, 0x1b2c, 0x4c7d, {0xbc, 0x68, 0xb6, 0x71, 0x68, 0x7a, 0x25, 0x67}}, 1 - }; - - static const PROPERTYKEY devicepath_key = { - {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2 - }; - - LIST_FOR_EACH_ENTRY(device, &device_list, MMDevice, entry) - { - if (device->flow == flow && IsEqualGUID(&device->devguid, id)){ - cur = device; - break; - } - } - - if(!cur){ - /* No device found, allocate new one */ - cur = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cur)); - if (!cur) - return NULL; - - cur->IMMDevice_iface.lpVtbl = &MMDeviceVtbl; - cur->IMMEndpoint_iface.lpVtbl = &MMEndpointVtbl; - - InitializeCriticalSection(&cur->crst); - cur->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MMDevice.crst"); - - list_add_tail(&device_list, &cur->entry); - }else if(cur->ref > 0) - WARN("Modifying an MMDevice with postitive reference count!\n"); - - HeapFree(GetProcessHeap(), 0, cur->drv_id); - cur->drv_id = name; - - cur->flow = flow; - cur->state = state; - cur->devguid = *id; - - StringFromGUID2(&cur->devguid, guidstr, ARRAY_SIZE(guidstr)); - - if (flow == eRender) - root = key_render; - else - root = key_capture; - - if (RegCreateKeyExW(root, guidstr, 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &key, NULL) == ERROR_SUCCESS) - { - HKEY keyprop; - RegSetValueExW(key, L"DeviceState", 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD)); - if (!RegCreateKeyExW(key, L"Properties", 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &keyprop, NULL)) - { - PROPVARIANT pv; - - pv.vt = VT_LPWSTR; - pv.pwszVal = name; - - if (SUCCEEDED(set_driver_prop_value(id, flow, &devicepath_key))) { - PROPVARIANT pv2; - - PropVariantInit(&pv2); - - if (SUCCEEDED(MMDevice_GetPropValue(id, flow, &devicepath_key, &pv2)) && pv2.vt == VT_LPWSTR) { - const WCHAR *override; - if ((override = find_product_name_override(pv2.pwszVal)) != NULL) - pv.pwszVal = (WCHAR*) override; - } - - PropVariantClear(&pv2); - } - - MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); - MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_FriendlyName, &pv); - MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv); - - pv.pwszVal = guidstr; - MMDevice_SetPropValue(id, flow, &deviceinterface_key, &pv); - - if (FAILED(set_driver_prop_value(id, flow, &PKEY_AudioEndpoint_FormFactor))) - { - pv.vt = VT_UI4; - pv.ulVal = (flow == eCapture) ? Microphone : Speakers; - - MMDevice_SetPropValue(id, flow, &PKEY_AudioEndpoint_FormFactor, &pv); - } - - if (flow != eCapture) - { - PROPVARIANT pv2; - - PropVariantInit(&pv2); - - /* make read-write by not overwriting if already set */ - if (FAILED(MMDevice_GetPropValue(id, flow, &PKEY_AudioEndpoint_PhysicalSpeakers, &pv2)) || pv2.vt != VT_UI4) - set_driver_prop_value(id, flow, &PKEY_AudioEndpoint_PhysicalSpeakers); - - PropVariantClear(&pv2); - } - - RegCloseKey(keyprop); - } - RegCloseKey(key); - } - - if (setdefault) - { - if (flow == eRender) - MMDevice_def_play = cur; - else - MMDevice_def_rec = cur; - } - return cur; -} - -HRESULT load_devices_from_reg(void) -{ - DWORD i = 0; - HKEY root, cur; - LONG ret; - DWORD curflow; - - ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, - L"Software\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio", 0, NULL, 0, - KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &root, NULL); - if (ret == ERROR_SUCCESS) - ret = RegCreateKeyExW(root, L"Capture", 0, NULL, 0, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, NULL, &key_capture, NULL); - if (ret == ERROR_SUCCESS) - ret = RegCreateKeyExW(root, L"Render", 0, NULL, 0, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, NULL, &key_render, NULL); - RegCloseKey(root); - cur = key_capture; - curflow = eCapture; - if (ret != ERROR_SUCCESS) - { - RegCloseKey(key_capture); - key_render = key_capture = NULL; - WARN("Couldn't create key: %lu\n", ret); - return E_FAIL; - } - - do { - WCHAR guidvalue[39]; - GUID guid; - DWORD len; - PROPVARIANT pv = { VT_EMPTY }; - - len = ARRAY_SIZE(guidvalue); - ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL); - if (ret == ERROR_NO_MORE_ITEMS) - { - if (cur == key_capture) - { - cur = key_render; - curflow = eRender; - i = 0; - continue; - } - break; - } - if (ret != ERROR_SUCCESS) - continue; - if (SUCCEEDED(CLSIDFromString(guidvalue, &guid)) - && SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv)) - && pv.vt == VT_LPWSTR) - { - DWORD size_bytes = (lstrlenW(pv.pwszVal) + 1) * sizeof(WCHAR); - WCHAR *name = HeapAlloc(GetProcessHeap(), 0, size_bytes); - memcpy(name, pv.pwszVal, size_bytes); - MMDevice_Create(name, &guid, curflow, - DEVICE_STATE_NOTPRESENT, FALSE); - CoTaskMemFree(pv.pwszVal); - } - } while (1); - - return S_OK; -} - -static HRESULT set_format(MMDevice *dev) -{ - HRESULT hr; - IAudioClient *client; - WAVEFORMATEX *fmt; - PROPVARIANT pv = { VT_EMPTY }; - - hr = drvs.pGetAudioEndpoint(&dev->devguid, &dev->IMMDevice_iface, &client); - if(FAILED(hr)) - return hr; - - hr = IAudioClient_GetMixFormat(client, &fmt); - if(FAILED(hr)){ - IAudioClient_Release(client); - return hr; - } - - IAudioClient_Release(client); - - pv.vt = VT_BLOB; - pv.blob.cbSize = sizeof(WAVEFORMATEX) + fmt->cbSize; - pv.blob.pBlobData = (BYTE*)fmt; - MMDevice_SetPropValue(&dev->devguid, dev->flow, - &PKEY_AudioEngine_DeviceFormat, &pv); - MMDevice_SetPropValue(&dev->devguid, dev->flow, - &PKEY_AudioEngine_OEMFormat, &pv); - CoTaskMemFree(fmt); - - return S_OK; -} - -HRESULT load_driver_devices(EDataFlow flow) -{ - WCHAR **ids; - GUID *guids; - UINT num, def, i; - HRESULT hr; - - if(!drvs.pGetEndpointIDs) - return S_OK; - - hr = drvs.pGetEndpointIDs(flow, &ids, &guids, &num, &def); - if(FAILED(hr)) - return hr; - - for(i = 0; i < num; ++i){ - MMDevice *dev; - dev = MMDevice_Create(ids[i], &guids[i], flow, DEVICE_STATE_ACTIVE, - def == i); - set_format(dev); - } - - HeapFree(GetProcessHeap(), 0, guids); - HeapFree(GetProcessHeap(), 0, ids); - - return S_OK; -} - -static void MMDevice_Destroy(MMDevice *This) -{ - TRACE("Freeing %s\n", debugstr_w(This->drv_id)); - list_remove(&This->entry); - This->crst.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->crst); - HeapFree(GetProcessHeap(), 0, This->drv_id); - HeapFree(GetProcessHeap(), 0, This); -} - -static inline MMDevice *impl_from_IMMDevice(IMMDevice *iface) -{ - return CONTAINING_RECORD(iface, MMDevice, IMMDevice_iface); -} - -static HRESULT WINAPI MMDevice_QueryInterface(IMMDevice *iface, REFIID riid, void **ppv) -{ - MMDevice *This = impl_from_IMMDevice(iface); - TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - if (IsEqualIID(riid, &IID_IUnknown) - || IsEqualIID(riid, &IID_IMMDevice)) - *ppv = &This->IMMDevice_iface; - else if (IsEqualIID(riid, &IID_IMMEndpoint)) - *ppv = &This->IMMEndpoint_iface; - if (*ppv) - { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI MMDevice_AddRef(IMMDevice *iface) -{ - MMDevice *This = impl_from_IMMDevice(iface); - LONG ref; - - ref = InterlockedIncrement(&This->ref); - TRACE("Refcount now %li\n", ref); - return ref; -} - -static ULONG WINAPI MMDevice_Release(IMMDevice *iface) -{ - MMDevice *This = impl_from_IMMDevice(iface); - LONG ref; - - ref = InterlockedDecrement(&This->ref); - TRACE("Refcount now %li\n", ref); - return ref; -} - -static HRESULT WINAPI MMDevice_Activate(IMMDevice *iface, REFIID riid, DWORD clsctx, PROPVARIANT *params, void **ppv) -{ - HRESULT hr = E_NOINTERFACE; - MMDevice *This = impl_from_IMMDevice(iface); - - TRACE("(%p)->(%s, %lx, %p, %p)\n", iface, debugstr_guid(riid), clsctx, params, ppv); - - if (!ppv) - return E_POINTER; - - if (IsEqualIID(riid, &IID_IAudioClient) || - IsEqualIID(riid, &IID_IAudioClient2) || - IsEqualIID(riid, &IID_IAudioClient3)){ - hr = drvs.pGetAudioEndpoint(&This->devguid, iface, (IAudioClient**)ppv); - }else if (IsEqualIID(riid, &IID_IAudioEndpointVolume) || - IsEqualIID(riid, &IID_IAudioEndpointVolumeEx)) - hr = AudioEndpointVolume_Create(This, (IAudioEndpointVolumeEx**)ppv); - else if (IsEqualIID(riid, &IID_IAudioSessionManager) - || IsEqualIID(riid, &IID_IAudioSessionManager2)) - { - hr = drvs.pGetAudioSessionManager(iface, (IAudioSessionManager2**)ppv); - } - else if (IsEqualIID(riid, &IID_IBaseFilter)) - { - if (This->flow == eRender) - hr = CoCreateInstance(&CLSID_DSoundRender, NULL, clsctx, riid, ppv); - else - ERR("Not supported for recording?\n"); - if (SUCCEEDED(hr)) - { - IPersistPropertyBag *ppb; - hr = IUnknown_QueryInterface((IUnknown*)*ppv, &IID_IPersistPropertyBag, (void **)&ppb); - if (SUCCEEDED(hr)) - { - /* ::Load cannot assume the interface stays alive after the function returns, - * so just create the interface on the stack, saves a lot of complicated code */ - IPropertyBagImpl bag = { { &PB_Vtbl } }; - bag.devguid = This->devguid; - hr = IPersistPropertyBag_Load(ppb, &bag.IPropertyBag_iface, NULL); - IPersistPropertyBag_Release(ppb); - if (FAILED(hr)) - IBaseFilter_Release((IBaseFilter*)*ppv); - } - else - { - FIXME("Wine doesn't support IPersistPropertyBag on DSoundRender yet, ignoring..\n"); - hr = S_OK; - } - } - } - else if (IsEqualIID(riid, &IID_IDeviceTopology)) - { - FIXME("IID_IDeviceTopology unsupported\n"); - } - else if (IsEqualIID(riid, &IID_IDirectSound) - || IsEqualIID(riid, &IID_IDirectSound8)) - { - if (This->flow == eRender) - hr = CoCreateInstance(&CLSID_DirectSound8, NULL, clsctx, riid, ppv); - if (SUCCEEDED(hr)) - { - hr = IDirectSound_Initialize((IDirectSound*)*ppv, &This->devguid); - if (FAILED(hr)) - IDirectSound_Release((IDirectSound*)*ppv); - } - } - else if (IsEqualIID(riid, &IID_IDirectSoundCapture)) - { - if (This->flow == eCapture) - hr = CoCreateInstance(&CLSID_DirectSoundCapture8, NULL, clsctx, riid, ppv); - if (SUCCEEDED(hr)) - { - hr = IDirectSoundCapture_Initialize((IDirectSoundCapture*)*ppv, &This->devguid); - if (FAILED(hr)) - IDirectSoundCapture_Release((IDirectSoundCapture*)*ppv); - } - } - else if (IsEqualIID(riid, &IID_ISpatialAudioClient)) - { - hr = SpatialAudioClient_Create(iface, (ISpatialAudioClient**)ppv); - } - else - ERR("Invalid/unknown iid %s\n", debugstr_guid(riid)); - - if (FAILED(hr)) - *ppv = NULL; - - TRACE("Returning %08lx\n", hr); - return hr; -} - -static HRESULT WINAPI MMDevice_OpenPropertyStore(IMMDevice *iface, DWORD access, IPropertyStore **ppv) -{ - MMDevice *This = impl_from_IMMDevice(iface); - TRACE("(%p)->(%lx,%p)\n", This, access, ppv); - - if (!ppv) - return E_POINTER; - return MMDevPropStore_Create(This, access, ppv); -} - -static HRESULT WINAPI MMDevice_GetId(IMMDevice *iface, WCHAR **itemid) -{ - MMDevice *This = impl_from_IMMDevice(iface); - WCHAR *str; - GUID *id = &This->devguid; - - TRACE("(%p)->(%p)\n", This, itemid); - if (!itemid) - return E_POINTER; - *itemid = str = CoTaskMemAlloc(56 * sizeof(WCHAR)); - if (!str) - return E_OUTOFMEMORY; - wsprintfW(str, L"{0.0.%u.00000000}.{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", - This->flow, id->Data1, id->Data2, id->Data3, - id->Data4[0], id->Data4[1], id->Data4[2], id->Data4[3], - id->Data4[4], id->Data4[5], id->Data4[6], id->Data4[7]); - TRACE("returning %s\n", wine_dbgstr_w(str)); - return S_OK; -} - -static HRESULT WINAPI MMDevice_GetState(IMMDevice *iface, DWORD *state) -{ - MMDevice *This = impl_from_IMMDevice(iface); - TRACE("(%p)->(%p)\n", iface, state); - - if (!state) - return E_POINTER; - *state = This->state; - return S_OK; -} - -static const IMMDeviceVtbl MMDeviceVtbl = -{ - MMDevice_QueryInterface, - MMDevice_AddRef, - MMDevice_Release, - MMDevice_Activate, - MMDevice_OpenPropertyStore, - MMDevice_GetId, - MMDevice_GetState -}; - -static inline MMDevice *impl_from_IMMEndpoint(IMMEndpoint *iface) -{ - return CONTAINING_RECORD(iface, MMDevice, IMMEndpoint_iface); -} - -static HRESULT WINAPI MMEndpoint_QueryInterface(IMMEndpoint *iface, REFIID riid, void **ppv) -{ - MMDevice *This = impl_from_IMMEndpoint(iface); - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - return IMMDevice_QueryInterface(&This->IMMDevice_iface, riid, ppv); -} - -static ULONG WINAPI MMEndpoint_AddRef(IMMEndpoint *iface) -{ - MMDevice *This = impl_from_IMMEndpoint(iface); - TRACE("(%p)\n", This); - return IMMDevice_AddRef(&This->IMMDevice_iface); -} - -static ULONG WINAPI MMEndpoint_Release(IMMEndpoint *iface) -{ - MMDevice *This = impl_from_IMMEndpoint(iface); - TRACE("(%p)\n", This); - return IMMDevice_Release(&This->IMMDevice_iface); -} - -static HRESULT WINAPI MMEndpoint_GetDataFlow(IMMEndpoint *iface, EDataFlow *flow) -{ - MMDevice *This = impl_from_IMMEndpoint(iface); - TRACE("(%p)->(%p)\n", This, flow); - if (!flow) - return E_POINTER; - *flow = This->flow; - return S_OK; -} - -static const IMMEndpointVtbl MMEndpointVtbl = -{ - MMEndpoint_QueryInterface, - MMEndpoint_AddRef, - MMEndpoint_Release, - MMEndpoint_GetDataFlow -}; - -static HRESULT MMDevCol_Create(IMMDeviceCollection **ppv, EDataFlow flow, DWORD state) -{ - MMDevColImpl *This; - - This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - *ppv = NULL; - if (!This) - return E_OUTOFMEMORY; - This->IMMDeviceCollection_iface.lpVtbl = &MMDevColVtbl; - This->ref = 1; - This->flow = flow; - This->state = state; - *ppv = &This->IMMDeviceCollection_iface; - return S_OK; -} - -static void MMDevCol_Destroy(MMDevColImpl *This) -{ - HeapFree(GetProcessHeap(), 0, This); -} - -static HRESULT WINAPI MMDevCol_QueryInterface(IMMDeviceCollection *iface, REFIID riid, void **ppv) -{ - MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - if (IsEqualIID(riid, &IID_IUnknown) - || IsEqualIID(riid, &IID_IMMDeviceCollection)) - *ppv = &This->IMMDeviceCollection_iface; - else - *ppv = NULL; - if (!*ppv) - return E_NOINTERFACE; - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI MMDevCol_AddRef(IMMDeviceCollection *iface) -{ - MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); - LONG ref = InterlockedIncrement(&This->ref); - TRACE("Refcount now %li\n", ref); - return ref; -} - -static ULONG WINAPI MMDevCol_Release(IMMDeviceCollection *iface) -{ - MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); - LONG ref = InterlockedDecrement(&This->ref); - TRACE("Refcount now %li\n", ref); - if (!ref) - MMDevCol_Destroy(This); - return ref; -} - -static HRESULT WINAPI MMDevCol_GetCount(IMMDeviceCollection *iface, UINT *numdevs) -{ - MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); - MMDevice *cur; - - TRACE("(%p)->(%p)\n", This, numdevs); - if (!numdevs) - return E_POINTER; - - *numdevs = 0; - LIST_FOR_EACH_ENTRY(cur, &device_list, MMDevice, entry) - { - if ((cur->flow == This->flow || This->flow == eAll) - && (cur->state & This->state)) - ++(*numdevs); - } - return S_OK; -} - -static HRESULT WINAPI MMDevCol_Item(IMMDeviceCollection *iface, UINT n, IMMDevice **dev) -{ - MMDevColImpl *This = impl_from_IMMDeviceCollection(iface); - MMDevice *cur; - DWORD i = 0; - - TRACE("(%p)->(%u, %p)\n", This, n, dev); - if (!dev) - return E_POINTER; - - LIST_FOR_EACH_ENTRY(cur, &device_list, MMDevice, entry) - { - if ((cur->flow == This->flow || This->flow == eAll) - && (cur->state & This->state) - && i++ == n) - { - *dev = &cur->IMMDevice_iface; - IMMDevice_AddRef(*dev); - return S_OK; - } - } - WARN("Could not obtain item %u\n", n); - *dev = NULL; - return E_INVALIDARG; -} - -static const IMMDeviceCollectionVtbl MMDevColVtbl = -{ - MMDevCol_QueryInterface, - MMDevCol_AddRef, - MMDevCol_Release, - MMDevCol_GetCount, - MMDevCol_Item -}; - -HRESULT MMDevEnum_Create(REFIID riid, void **ppv) -{ - return IMMDeviceEnumerator_QueryInterface(&enumerator.IMMDeviceEnumerator_iface, riid, ppv); -} - -void MMDevEnum_Free(void) -{ - MMDevice *device, *next; - LIST_FOR_EACH_ENTRY_SAFE(device, next, &device_list, MMDevice, entry) - MMDevice_Destroy(device); - RegCloseKey(key_render); - RegCloseKey(key_capture); - key_render = key_capture = NULL; -} - -static HRESULT WINAPI MMDevEnum_QueryInterface(IMMDeviceEnumerator *iface, REFIID riid, void **ppv) -{ - MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - if (IsEqualIID(riid, &IID_IUnknown) - || IsEqualIID(riid, &IID_IMMDeviceEnumerator)) - *ppv = &This->IMMDeviceEnumerator_iface; - else - *ppv = NULL; - if (!*ppv) - return E_NOINTERFACE; - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI MMDevEnum_AddRef(IMMDeviceEnumerator *iface) -{ - MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); - LONG ref = InterlockedIncrement(&This->ref); - TRACE("Refcount now %li\n", ref); - return ref; -} - -static ULONG WINAPI MMDevEnum_Release(IMMDeviceEnumerator *iface) -{ - MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); - LONG ref = InterlockedDecrement(&This->ref); - TRACE("Refcount now %li\n", ref); - return ref; -} - -static HRESULT WINAPI MMDevEnum_EnumAudioEndpoints(IMMDeviceEnumerator *iface, EDataFlow flow, DWORD mask, IMMDeviceCollection **devices) -{ - MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); - TRACE("(%p)->(%u,%lu,%p)\n", This, flow, mask, devices); - if (!devices) - return E_POINTER; - *devices = NULL; - if (flow >= EDataFlow_enum_count) - return E_INVALIDARG; - if (mask & ~DEVICE_STATEMASK_ALL) - return E_INVALIDARG; - return MMDevCol_Create(devices, flow, mask); -} - -static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *iface, EDataFlow flow, ERole role, IMMDevice **device) -{ - MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); - WCHAR reg_key[256]; - HKEY key; - HRESULT hr; - - TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device); - - if (!device) - return E_POINTER; - - if((flow != eRender && flow != eCapture) || - (role != eConsole && role != eMultimedia && role != eCommunications)){ - WARN("Unknown flow (%u) or role (%u)\n", flow, role); - return E_INVALIDARG; - } - - *device = NULL; - - if(!drvs.module_name[0]) - return E_NOTFOUND; - - lstrcpyW(reg_key, drv_keyW); - lstrcatW(reg_key, L"\\"); - lstrcatW(reg_key, drvs.module_name); - - if(RegOpenKeyW(HKEY_CURRENT_USER, reg_key, &key) == ERROR_SUCCESS){ - const WCHAR *reg_x_name, *reg_vx_name; - WCHAR def_id[256]; - DWORD size = sizeof(def_id), state; - - if(flow == eRender){ - reg_x_name = L"DefaultOutput"; - reg_vx_name = L"DefaultVoiceOutput"; - }else{ - reg_x_name = L"DefaultInput"; - reg_vx_name = L"DefaultVoiceInput"; - } - - if(role == eCommunications && - RegQueryValueExW(key, reg_vx_name, 0, NULL, - (BYTE*)def_id, &size) == ERROR_SUCCESS){ - hr = IMMDeviceEnumerator_GetDevice(iface, def_id, device); - if(SUCCEEDED(hr)){ - if(SUCCEEDED(IMMDevice_GetState(*device, &state)) && - state == DEVICE_STATE_ACTIVE){ - RegCloseKey(key); - return S_OK; - } - } - - TRACE("Unable to find voice device %s\n", wine_dbgstr_w(def_id)); - } - - if(RegQueryValueExW(key, reg_x_name, 0, NULL, - (BYTE*)def_id, &size) == ERROR_SUCCESS){ - hr = IMMDeviceEnumerator_GetDevice(iface, def_id, device); - if(SUCCEEDED(hr)){ - if(SUCCEEDED(IMMDevice_GetState(*device, &state)) && - state == DEVICE_STATE_ACTIVE){ - RegCloseKey(key); - return S_OK; - } - } - - TRACE("Unable to find device %s\n", wine_dbgstr_w(def_id)); - } - - RegCloseKey(key); - } - - if (flow == eRender) - *device = &MMDevice_def_play->IMMDevice_iface; - else - *device = &MMDevice_def_rec->IMMDevice_iface; - - if (!*device) - return E_NOTFOUND; - IMMDevice_AddRef(*device); - return S_OK; -} - -static HRESULT WINAPI MMDevEnum_GetDevice(IMMDeviceEnumerator *iface, const WCHAR *name, IMMDevice **device) -{ - MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); - MMDevice *impl; - IMMDevice *dev = NULL; - - TRACE("(%p)->(%s,%p)\n", This, debugstr_w(name), device); - - if(!name || !device) - return E_POINTER; - - if(!lstrcmpW(name, L"Wine info device")){ - *device = &info_device; - return S_OK; - } - - LIST_FOR_EACH_ENTRY(impl, &device_list, MMDevice, entry) - { - HRESULT hr; - WCHAR *str; - dev = &impl->IMMDevice_iface; - hr = IMMDevice_GetId(dev, &str); - if (FAILED(hr)) - { - WARN("GetId failed: %08lx\n", hr); - continue; - } - - if (str && !lstrcmpW(str, name)) - { - CoTaskMemFree(str); - IMMDevice_AddRef(dev); - *device = dev; - return S_OK; - } - CoTaskMemFree(str); - } - TRACE("Could not find device %s\n", debugstr_w(name)); - return E_INVALIDARG; -} - -struct NotificationClientWrapper { - IMMNotificationClient *client; - struct list entry; -}; - -static struct list g_notif_clients = LIST_INIT(g_notif_clients); -static HANDLE g_notif_thread; - -static CRITICAL_SECTION g_notif_lock; -static CRITICAL_SECTION_DEBUG g_notif_lock_debug = -{ - 0, 0, &g_notif_lock, - { &g_notif_lock_debug.ProcessLocksList, &g_notif_lock_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": g_notif_lock") } -}; -static CRITICAL_SECTION g_notif_lock = { &g_notif_lock_debug, -1, 0, 0, 0, 0 }; - -static void notify_clients(EDataFlow flow, ERole role, const WCHAR *id) -{ - struct NotificationClientWrapper *wrapper; - LIST_FOR_EACH_ENTRY(wrapper, &g_notif_clients, - struct NotificationClientWrapper, entry) - IMMNotificationClient_OnDefaultDeviceChanged(wrapper->client, flow, - role, id); - - /* Windows 7 treats changes to eConsole as changes to eMultimedia */ - if(role == eConsole) - notify_clients(flow, eMultimedia, id); -} - -static BOOL notify_if_changed(EDataFlow flow, ERole role, HKEY key, - const WCHAR *val_name, WCHAR *old_val, IMMDevice *def_dev) -{ - WCHAR new_val[64], *id; - DWORD size; - HRESULT hr; - - size = sizeof(new_val); - if(RegQueryValueExW(key, val_name, 0, NULL, - (BYTE*)new_val, &size) != ERROR_SUCCESS){ - if(old_val[0] != 0){ - /* set by user -> system default */ - if(def_dev){ - hr = IMMDevice_GetId(def_dev, &id); - if(FAILED(hr)){ - ERR("GetId failed: %08lx\n", hr); - return FALSE; - } - }else - id = NULL; - - notify_clients(flow, role, id); - old_val[0] = 0; - CoTaskMemFree(id); - - return TRUE; - } - - /* system default -> system default, noop */ - return FALSE; - } - - if(!lstrcmpW(old_val, new_val)){ - /* set by user -> same value */ - return FALSE; - } - - if(new_val[0] != 0){ - /* set by user -> different value */ - notify_clients(flow, role, new_val); - memcpy(old_val, new_val, sizeof(new_val)); - return TRUE; - } - - /* set by user -> system default */ - if(def_dev){ - hr = IMMDevice_GetId(def_dev, &id); - if(FAILED(hr)){ - ERR("GetId failed: %08lx\n", hr); - return FALSE; - } - }else - id = NULL; - - notify_clients(flow, role, id); - old_val[0] = 0; - CoTaskMemFree(id); - - return TRUE; -} - -static DWORD WINAPI notif_thread_proc(void *user) -{ - HKEY key; - WCHAR reg_key[256]; - WCHAR out_name[64], vout_name[64], in_name[64], vin_name[64]; - DWORD size; - - SetThreadDescription(GetCurrentThread(), L"wine_mmdevapi_notification"); - - lstrcpyW(reg_key, drv_keyW); - lstrcatW(reg_key, L"\\"); - lstrcatW(reg_key, drvs.module_name); - - if(RegCreateKeyExW(HKEY_CURRENT_USER, reg_key, 0, NULL, 0, - MAXIMUM_ALLOWED, NULL, &key, NULL) != ERROR_SUCCESS){ - ERR("RegCreateKeyEx failed: %lu\n", GetLastError()); - return 1; - } - - size = sizeof(out_name); - if(RegQueryValueExW(key, L"DefaultOutput", 0, NULL, (BYTE*)out_name, &size) != ERROR_SUCCESS) - out_name[0] = 0; - - size = sizeof(vout_name); - if(RegQueryValueExW(key, L"DefaultVoiceOutput", 0, NULL, (BYTE*)vout_name, &size) != ERROR_SUCCESS) - vout_name[0] = 0; - - size = sizeof(in_name); - if(RegQueryValueExW(key, L"DefaultInput", 0, NULL, (BYTE*)in_name, &size) != ERROR_SUCCESS) - in_name[0] = 0; - - size = sizeof(vin_name); - if(RegQueryValueExW(key, L"DefaultVoiceInput", 0, NULL, (BYTE*)vin_name, &size) != ERROR_SUCCESS) - vin_name[0] = 0; - - while(1){ - if(RegNotifyChangeKeyValue(key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, - NULL, FALSE) != ERROR_SUCCESS){ - ERR("RegNotifyChangeKeyValue failed: %lu\n", GetLastError()); - RegCloseKey(key); - g_notif_thread = NULL; - return 1; - } - - EnterCriticalSection(&g_notif_lock); - - notify_if_changed(eRender, eConsole, key, L"DefaultOutput", - out_name, &MMDevice_def_play->IMMDevice_iface); - notify_if_changed(eRender, eCommunications, key, L"DefaultVoiceOutput", - vout_name, &MMDevice_def_play->IMMDevice_iface); - notify_if_changed(eCapture, eConsole, key, L"DefaultInput", - in_name, &MMDevice_def_rec->IMMDevice_iface); - notify_if_changed(eCapture, eCommunications, key, L"DefaultVoiceInput", - vin_name, &MMDevice_def_rec->IMMDevice_iface); - - LeaveCriticalSection(&g_notif_lock); - } - - RegCloseKey(key); - - g_notif_thread = NULL; - - return 0; -} - -static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client) -{ - MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); - struct NotificationClientWrapper *wrapper; - - TRACE("(%p)->(%p)\n", This, client); - - if(!client) - return E_POINTER; - - wrapper = HeapAlloc(GetProcessHeap(), 0, sizeof(*wrapper)); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->client = client; - - EnterCriticalSection(&g_notif_lock); - - list_add_tail(&g_notif_clients, &wrapper->entry); - - if(!g_notif_thread){ - g_notif_thread = CreateThread(NULL, 0, notif_thread_proc, NULL, 0, NULL); - if(!g_notif_thread) - ERR("CreateThread failed: %lu\n", GetLastError()); - } - - LeaveCriticalSection(&g_notif_lock); - - return S_OK; -} - -static HRESULT WINAPI MMDevEnum_UnregisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client) -{ - MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface); - struct NotificationClientWrapper *wrapper; - - TRACE("(%p)->(%p)\n", This, client); - - if(!client) - return E_POINTER; - - EnterCriticalSection(&g_notif_lock); - - LIST_FOR_EACH_ENTRY(wrapper, &g_notif_clients, struct NotificationClientWrapper, entry){ - if(wrapper->client == client){ - list_remove(&wrapper->entry); - HeapFree(GetProcessHeap(), 0, wrapper); - LeaveCriticalSection(&g_notif_lock); - return S_OK; - } - } - - LeaveCriticalSection(&g_notif_lock); - - return E_NOTFOUND; -} - -static const IMMDeviceEnumeratorVtbl MMDevEnumVtbl = -{ - MMDevEnum_QueryInterface, - MMDevEnum_AddRef, - MMDevEnum_Release, - MMDevEnum_EnumAudioEndpoints, - MMDevEnum_GetDefaultAudioEndpoint, - MMDevEnum_GetDevice, - MMDevEnum_RegisterEndpointNotificationCallback, - MMDevEnum_UnregisterEndpointNotificationCallback -}; - -static MMDevEnumImpl enumerator = -{ - {&MMDevEnumVtbl}, - 1, -}; - -static HRESULT MMDevPropStore_Create(MMDevice *parent, DWORD access, IPropertyStore **ppv) -{ - MMDevPropStore *This; - if (access != STGM_READ - && access != STGM_WRITE - && access != STGM_READWRITE) - { - WARN("Invalid access %08lx\n", access); - return E_INVALIDARG; - } - This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - *ppv = &This->IPropertyStore_iface; - if (!This) - return E_OUTOFMEMORY; - This->IPropertyStore_iface.lpVtbl = &MMDevPropVtbl; - This->ref = 1; - This->parent = parent; - This->access = access; - return S_OK; -} - -static void MMDevPropStore_Destroy(MMDevPropStore *This) -{ - HeapFree(GetProcessHeap(), 0, This); -} - -static HRESULT WINAPI MMDevPropStore_QueryInterface(IPropertyStore *iface, REFIID riid, void **ppv) -{ - MMDevPropStore *This = impl_from_IPropertyStore(iface); - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - if (IsEqualIID(riid, &IID_IUnknown) - || IsEqualIID(riid, &IID_IPropertyStore)) - *ppv = &This->IPropertyStore_iface; - else - *ppv = NULL; - if (!*ppv) - return E_NOINTERFACE; - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI MMDevPropStore_AddRef(IPropertyStore *iface) -{ - MMDevPropStore *This = impl_from_IPropertyStore(iface); - LONG ref = InterlockedIncrement(&This->ref); - TRACE("Refcount now %li\n", ref); - return ref; -} - -static ULONG WINAPI MMDevPropStore_Release(IPropertyStore *iface) -{ - MMDevPropStore *This = impl_from_IPropertyStore(iface); - LONG ref = InterlockedDecrement(&This->ref); - TRACE("Refcount now %li\n", ref); - if (!ref) - MMDevPropStore_Destroy(This); - return ref; -} - -static HRESULT WINAPI MMDevPropStore_GetCount(IPropertyStore *iface, DWORD *nprops) -{ - MMDevPropStore *This = impl_from_IPropertyStore(iface); - WCHAR buffer[50]; - DWORD i = 0; - HKEY propkey; - HRESULT hr; - - TRACE("(%p)->(%p)\n", iface, nprops); - if (!nprops) - return E_POINTER; - hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey); - if (FAILED(hr)) - return hr; - *nprops = 0; - do { - DWORD len = ARRAY_SIZE(buffer); - if (RegEnumValueW(propkey, i, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) - break; - i++; - } while (1); - RegCloseKey(propkey); - TRACE("Returning %li\n", i); - *nprops = i; - return S_OK; -} - -static HRESULT WINAPI MMDevPropStore_GetAt(IPropertyStore *iface, DWORD prop, PROPERTYKEY *key) -{ - MMDevPropStore *This = impl_from_IPropertyStore(iface); - WCHAR buffer[50]; - DWORD len = ARRAY_SIZE(buffer); - HRESULT hr; - HKEY propkey; - - TRACE("(%p)->(%lu,%p)\n", iface, prop, key); - if (!key) - return E_POINTER; - - hr = MMDevPropStore_OpenPropKey(&This->parent->devguid, This->parent->flow, &propkey); - if (FAILED(hr)) - return hr; - - if (RegEnumValueW(propkey, prop, buffer, &len, NULL, NULL, NULL, NULL) != ERROR_SUCCESS - || len <= 39) - { - WARN("GetAt %lu failed\n", prop); - return E_INVALIDARG; - } - RegCloseKey(propkey); - buffer[38] = 0; - CLSIDFromString(buffer, &key->fmtid); - key->pid = wcstol(&buffer[39], NULL, 10); - return S_OK; -} - -static HRESULT WINAPI MMDevPropStore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *pv) -{ - MMDevPropStore *This = impl_from_IPropertyStore(iface); - HRESULT hres; - TRACE("(%p)->(\"%s,%lu\", %p)\n", This, key ? debugstr_guid(&key->fmtid) : NULL, key ? key->pid : 0, pv); - - if (!key || !pv) - return E_POINTER; - if (This->access != STGM_READ - && This->access != STGM_READWRITE) - return STG_E_ACCESSDENIED; - - /* Special case */ - if (IsEqualPropertyKey(*key, PKEY_AudioEndpoint_GUID)) - { - pv->vt = VT_LPWSTR; - pv->pwszVal = CoTaskMemAlloc(39 * sizeof(WCHAR)); - if (!pv->pwszVal) - return E_OUTOFMEMORY; - StringFromGUID2(&This->parent->devguid, pv->pwszVal, 39); - return S_OK; - } - - hres = MMDevice_GetPropValue(&This->parent->devguid, This->parent->flow, key, pv); - if (FAILED(hres)) - return hres; - - if (WARN_ON(mmdevapi)) - { - if ((IsEqualPropertyKey(*key, DEVPKEY_Device_FriendlyName) || - IsEqualPropertyKey(*key, DEVPKEY_DeviceInterface_FriendlyName) || - IsEqualPropertyKey(*key, DEVPKEY_Device_DeviceDesc)) && - pv->vt == VT_LPWSTR && wcslen(pv->pwszVal) > 62) - WARN("Returned name exceeds length limit of some broken apps/libs, might crash: %s\n", debugstr_w(pv->pwszVal)); - } - return hres; -} - -static HRESULT WINAPI MMDevPropStore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT pv) -{ - MMDevPropStore *This = impl_from_IPropertyStore(iface); - TRACE("(%p)->(\"%s,%lu\", %p)\n", This, key ? debugstr_guid(&key->fmtid) : NULL, key ? key->pid : 0, pv); - - if (!key || !pv) - return E_POINTER; - - if (This->access != STGM_WRITE - && This->access != STGM_READWRITE) - return STG_E_ACCESSDENIED; - return MMDevice_SetPropValue(&This->parent->devguid, This->parent->flow, key, pv); -} - -static HRESULT WINAPI MMDevPropStore_Commit(IPropertyStore *iface) -{ - MMDevPropStore *This = impl_from_IPropertyStore(iface); - TRACE("(%p)\n", iface); - - if (This->access != STGM_WRITE - && This->access != STGM_READWRITE) - return STG_E_ACCESSDENIED; - - /* Does nothing - for mmdevapi, the propstore values are written on SetValue, - * not on Commit. */ - - return S_OK; -} - -static const IPropertyStoreVtbl MMDevPropVtbl = -{ - MMDevPropStore_QueryInterface, - MMDevPropStore_AddRef, - MMDevPropStore_Release, - MMDevPropStore_GetCount, - MMDevPropStore_GetAt, - MMDevPropStore_GetValue, - MMDevPropStore_SetValue, - MMDevPropStore_Commit -}; - - -/* Property bag for IBaseFilter activation */ -static HRESULT WINAPI PB_QueryInterface(IPropertyBag *iface, REFIID riid, void **ppv) -{ - ERR("Should not be called\n"); - *ppv = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI PB_AddRef(IPropertyBag *iface) -{ - ERR("Should not be called\n"); - return 2; -} - -static ULONG WINAPI PB_Release(IPropertyBag *iface) -{ - ERR("Should not be called\n"); - return 1; -} - -static HRESULT WINAPI PB_Read(IPropertyBag *iface, LPCOLESTR name, VARIANT *var, IErrorLog *log) -{ - IPropertyBagImpl *This = impl_from_IPropertyBag(iface); - TRACE("Trying to read %s, type %u\n", debugstr_w(name), var->n1.n2.vt); - if (!lstrcmpW(name, L"DSGuid")) - { - WCHAR guidstr[39]; - StringFromGUID2(&This->devguid, guidstr,ARRAY_SIZE(guidstr)); - var->n1.n2.vt = VT_BSTR; - var->n1.n2.n3.bstrVal = SysAllocString(guidstr); - return S_OK; - } - ERR("Unknown property '%s' queried\n", debugstr_w(name)); - return E_FAIL; -} - -static HRESULT WINAPI PB_Write(IPropertyBag *iface, LPCOLESTR name, VARIANT *var) -{ - ERR("Should not be called\n"); - return E_FAIL; -} - -static const IPropertyBagVtbl PB_Vtbl = -{ - PB_QueryInterface, - PB_AddRef, - PB_Release, - PB_Read, - PB_Write -}; - -static ULONG WINAPI info_device_ps_AddRef(IPropertyStore *iface) -{ - return 2; -} - -static ULONG WINAPI info_device_ps_Release(IPropertyStore *iface) -{ - return 1; -} - -static HRESULT WINAPI info_device_ps_GetValue(IPropertyStore *iface, - REFPROPERTYKEY key, PROPVARIANT *pv) -{ - TRACE("(static)->(\"%s,%lu\", %p)\n", debugstr_guid(&key->fmtid), key ? key->pid : 0, pv); - - if (!key || !pv) - return E_POINTER; - - if (IsEqualPropertyKey(*key, DEVPKEY_Device_Driver)) - { - INT size = (lstrlenW(drvs.module_name) + 1) * sizeof(WCHAR); - pv->vt = VT_LPWSTR; - pv->pwszVal = CoTaskMemAlloc(size); - if (!pv->pwszVal) - return E_OUTOFMEMORY; - memcpy(pv->pwszVal, drvs.module_name, size); - return S_OK; - } - - return E_INVALIDARG; -} - -static const IPropertyStoreVtbl info_device_ps_Vtbl = -{ - NULL, - info_device_ps_AddRef, - info_device_ps_Release, - NULL, - NULL, - info_device_ps_GetValue, - NULL, - NULL -}; - -static IPropertyStore info_device_ps = { - &info_device_ps_Vtbl -}; - -static ULONG WINAPI info_device_AddRef(IMMDevice *iface) -{ - return 2; -} - -static ULONG WINAPI info_device_Release(IMMDevice *iface) -{ - return 1; -} - -static HRESULT WINAPI info_device_OpenPropertyStore(IMMDevice *iface, - DWORD access, IPropertyStore **ppv) -{ - TRACE("(static)->(%lx, %p)\n", access, ppv); - *ppv = &info_device_ps; - return S_OK; -} - -static const IMMDeviceVtbl info_device_Vtbl = -{ - NULL, - info_device_AddRef, - info_device_Release, - NULL, - info_device_OpenPropertyStore, - NULL, - NULL -}; - -static IMMDevice info_device = { - &info_device_Vtbl -}; diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/main.c b/pkgs/osu-wine/audio-revert/mmdevapi/main.c deleted file mode 100644 index c792661..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/main.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2009 Maarten Lankhorst - * Copyright 2011 Andrew Eikum for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include - -#define COBJMACROS -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" - -#include "ole2.h" -#include "olectl.h" -#include "rpcproxy.h" -#include "propsys.h" -#include "propkeydef.h" -#include "mmdeviceapi.h" -#include "mmsystem.h" -#include "dsound.h" -#include "audioclient.h" -#include "endpointvolume.h" -#include "audiopolicy.h" -#include "devpkey.h" -#include "winreg.h" -#include "spatialaudioclient.h" - -#include "mmdevapi.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); - -DriverFuncs drvs; - -const WCHAR drv_keyW[] = L"Software\\Wine\\Drivers"; - -static const char *get_priority_string(int prio) -{ - switch(prio){ - case Priority_Unavailable: - return "Unavailable"; - case Priority_Low: - return "Low"; - case Priority_Neutral: - return "Neutral"; - case Priority_Preferred: - return "Preferred"; - } - return "Invalid"; -} - -static BOOL load_driver(const WCHAR *name, DriverFuncs *driver) -{ - WCHAR driver_module[264]; - - lstrcpyW(driver_module, L"wine"); - lstrcatW(driver_module, name); - lstrcatW(driver_module, L".drv"); - - TRACE("Attempting to load %s\n", wine_dbgstr_w(driver_module)); - - driver->module = LoadLibraryW(driver_module); - if(!driver->module){ - TRACE("Unable to load %s: %lu\n", wine_dbgstr_w(driver_module), - GetLastError()); - return FALSE; - } - -#define LDFC(n) do { driver->p##n = (void*)GetProcAddress(driver->module, #n);\ - if(!driver->p##n) { FreeLibrary(driver->module); return FALSE; } } while(0) - LDFC(GetPriority); - LDFC(GetEndpointIDs); - LDFC(GetAudioEndpoint); - LDFC(GetAudioSessionManager); -#undef LDFC - - /* optional - do not fail if not found */ - driver->pGetPropValue = (void*)GetProcAddress(driver->module, "GetPropValue"); - - driver->priority = driver->pGetPriority(); - lstrcpyW(driver->module_name, driver_module); - - TRACE("Successfully loaded %s with priority %s\n", - wine_dbgstr_w(driver_module), get_priority_string(driver->priority)); - - return TRUE; -} - -static BOOL WINAPI init_driver(INIT_ONCE *once, void *param, void **context) -{ - static WCHAR default_list[] = L"pulse,alsa,oss,coreaudio"; - DriverFuncs driver; - HKEY key; - WCHAR reg_list[256], *p, *next, *driver_list = default_list; - - if(RegOpenKeyW(HKEY_CURRENT_USER, drv_keyW, &key) == ERROR_SUCCESS){ - DWORD size = sizeof(reg_list); - - if(RegQueryValueExW(key, L"Audio", 0, NULL, (BYTE*)reg_list, &size) == ERROR_SUCCESS){ - if(reg_list[0] == '\0'){ - TRACE("User explicitly chose no driver\n"); - RegCloseKey(key); - return TRUE; - } - - driver_list = reg_list; - } - - RegCloseKey(key); - } - - TRACE("Loading driver list %s\n", wine_dbgstr_w(driver_list)); - for(next = p = driver_list; next; p = next + 1){ - next = wcschr(p, ','); - if(next) - *next = '\0'; - - driver.priority = Priority_Unavailable; - if(load_driver(p, &driver)){ - if(driver.priority == Priority_Unavailable) - FreeLibrary(driver.module); - else if(!drvs.module || driver.priority > drvs.priority){ - TRACE("Selecting driver %s with priority %s\n", - wine_dbgstr_w(p), get_priority_string(driver.priority)); - if(drvs.module) - FreeLibrary(drvs.module); - drvs = driver; - }else - FreeLibrary(driver.module); - }else - TRACE("Failed to load driver %s\n", wine_dbgstr_w(p)); - - if(next) - *next = ','; - } - - if (drvs.module != 0){ - load_devices_from_reg(); - load_driver_devices(eRender); - load_driver_devices(eCapture); - } - - return drvs.module != 0; -} - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - TRACE("(0x%p, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved); - - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hinstDLL); - break; - case DLL_PROCESS_DETACH: - if(lpvReserved) - break; - MMDevEnum_Free(); - break; - } - - return TRUE; -} - -typedef HRESULT (*FnCreateInstance)(REFIID riid, LPVOID *ppobj); - -typedef struct { - IClassFactory IClassFactory_iface; - REFCLSID rclsid; - FnCreateInstance pfnCreateInstance; -} IClassFactoryImpl; - -static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) -{ - return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); -} - -static HRESULT WINAPI -MMCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj) -{ - IClassFactoryImpl *This = impl_from_IClassFactory(iface); - TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppobj); - if (ppobj == NULL) - return E_POINTER; - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IClassFactory)) - { - *ppobj = iface; - IClassFactory_AddRef(iface); - return S_OK; - } - *ppobj = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI MMCF_AddRef(LPCLASSFACTORY iface) -{ - return 2; -} - -static ULONG WINAPI MMCF_Release(LPCLASSFACTORY iface) -{ - /* static class, won't be freed */ - return 1; -} - -static HRESULT WINAPI MMCF_CreateInstance( - LPCLASSFACTORY iface, - LPUNKNOWN pOuter, - REFIID riid, - LPVOID *ppobj) -{ - IClassFactoryImpl *This = impl_from_IClassFactory(iface); - TRACE("(%p, %p, %s, %p)\n", This, pOuter, debugstr_guid(riid), ppobj); - - if (pOuter) - return CLASS_E_NOAGGREGATION; - - if (ppobj == NULL) { - WARN("invalid parameter\n"); - return E_POINTER; - } - *ppobj = NULL; - return This->pfnCreateInstance(riid, ppobj); -} - -static HRESULT WINAPI MMCF_LockServer(LPCLASSFACTORY iface, BOOL dolock) -{ - IClassFactoryImpl *This = impl_from_IClassFactory(iface); - FIXME("(%p, %d) stub!\n", This, dolock); - return S_OK; -} - -static const IClassFactoryVtbl MMCF_Vtbl = { - MMCF_QueryInterface, - MMCF_AddRef, - MMCF_Release, - MMCF_CreateInstance, - MMCF_LockServer -}; - -static IClassFactoryImpl MMDEVAPI_CF[] = { - { { &MMCF_Vtbl }, &CLSID_MMDeviceEnumerator, (FnCreateInstance)MMDevEnum_Create } -}; - -HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) -{ - static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; - unsigned int i = 0; - TRACE("(%s, %s, %p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); - - if(!InitOnceExecuteOnce(&init_once, init_driver, NULL, NULL)) { - ERR("Driver initialization failed\n"); - return E_FAIL; - } - - if (ppv == NULL) { - WARN("invalid parameter\n"); - return E_INVALIDARG; - } - - *ppv = NULL; - - if (!IsEqualIID(riid, &IID_IClassFactory) && - !IsEqualIID(riid, &IID_IUnknown)) { - WARN("no interface for %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; - } - - for (i = 0; i < ARRAY_SIZE(MMDEVAPI_CF); ++i) - { - if (IsEqualGUID(rclsid, MMDEVAPI_CF[i].rclsid)) { - IClassFactory_AddRef(&MMDEVAPI_CF[i].IClassFactory_iface); - *ppv = &MMDEVAPI_CF[i]; - return S_OK; - } - } - - WARN("(%s, %s, %p): no class found.\n", debugstr_guid(rclsid), - debugstr_guid(riid), ppv); - return CLASS_E_CLASSNOTAVAILABLE; -} - -struct activate_async_op { - IActivateAudioInterfaceAsyncOperation IActivateAudioInterfaceAsyncOperation_iface; - LONG ref; - - IActivateAudioInterfaceCompletionHandler *callback; - HRESULT result_hr; - IUnknown *result_iface; -}; - -static struct activate_async_op *impl_from_IActivateAudioInterfaceAsyncOperation(IActivateAudioInterfaceAsyncOperation *iface) -{ - return CONTAINING_RECORD(iface, struct activate_async_op, IActivateAudioInterfaceAsyncOperation_iface); -} - -static HRESULT WINAPI activate_async_op_QueryInterface(IActivateAudioInterfaceAsyncOperation *iface, - REFIID riid, void **ppv) -{ - struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface); - - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IActivateAudioInterfaceAsyncOperation)) { - *ppv = &This->IActivateAudioInterfaceAsyncOperation_iface; - } else { - *ppv = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI activate_async_op_AddRef(IActivateAudioInterfaceAsyncOperation *iface) -{ - struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface); - LONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) refcount now %li\n", This, ref); - return ref; -} - -static ULONG WINAPI activate_async_op_Release(IActivateAudioInterfaceAsyncOperation *iface) -{ - struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface); - LONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) refcount now %li\n", This, ref); - if (!ref) { - if(This->result_iface) - IUnknown_Release(This->result_iface); - IActivateAudioInterfaceCompletionHandler_Release(This->callback); - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static HRESULT WINAPI activate_async_op_GetActivateResult(IActivateAudioInterfaceAsyncOperation *iface, - HRESULT *result_hr, IUnknown **result_iface) -{ - struct activate_async_op *This = impl_from_IActivateAudioInterfaceAsyncOperation(iface); - - TRACE("(%p)->(%p, %p)\n", This, result_hr, result_iface); - - *result_hr = This->result_hr; - - if(This->result_hr == S_OK){ - *result_iface = This->result_iface; - IUnknown_AddRef(*result_iface); - } - - return S_OK; -} - -static IActivateAudioInterfaceAsyncOperationVtbl IActivateAudioInterfaceAsyncOperation_vtbl = { - activate_async_op_QueryInterface, - activate_async_op_AddRef, - activate_async_op_Release, - activate_async_op_GetActivateResult, -}; - -static DWORD WINAPI activate_async_threadproc(void *user) -{ - struct activate_async_op *op = user; - - SetThreadDescription(GetCurrentThread(), L"wine_mmdevapi_activate_async"); - - IActivateAudioInterfaceCompletionHandler_ActivateCompleted(op->callback, &op->IActivateAudioInterfaceAsyncOperation_iface); - - IActivateAudioInterfaceAsyncOperation_Release(&op->IActivateAudioInterfaceAsyncOperation_iface); - - return 0; -} - -static HRESULT get_mmdevice_by_activatepath(const WCHAR *path, IMMDevice **mmdev) -{ - IMMDeviceEnumerator *devenum; - HRESULT hr; - - static const WCHAR DEVINTERFACE_AUDIO_RENDER_WSTR[] = L"{E6327CAD-DCEC-4949-AE8A-991E976A79D2}"; - static const WCHAR DEVINTERFACE_AUDIO_CAPTURE_WSTR[] = L"{2EEF81BE-33FA-4800-9670-1CD474972C3F}"; - static const WCHAR MMDEV_PATH_PREFIX[] = L"\\\\?\\SWD#MMDEVAPI#"; - - hr = MMDevEnum_Create(&IID_IMMDeviceEnumerator, (void**)&devenum); - if (FAILED(hr)) { - WARN("Failed to create MMDeviceEnumerator: %08lx\n", hr); - return hr; - } - - if (!lstrcmpiW(path, DEVINTERFACE_AUDIO_RENDER_WSTR)){ - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eRender, eMultimedia, mmdev); - } else if (!lstrcmpiW(path, DEVINTERFACE_AUDIO_CAPTURE_WSTR)){ - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, eCapture, eMultimedia, mmdev); - } else if (!memcmp(path, MMDEV_PATH_PREFIX, sizeof(MMDEV_PATH_PREFIX) - sizeof(WCHAR))) { - WCHAR device_id[56]; /* == strlen("{0.0.1.00000000}.{fd47d9cc-4218-4135-9ce2-0c195c87405b}") + 1 */ - - lstrcpynW(device_id, path + (ARRAY_SIZE(MMDEV_PATH_PREFIX) - 1), ARRAY_SIZE(device_id)); - - hr = IMMDeviceEnumerator_GetDevice(devenum, device_id, mmdev); - } else { - FIXME("Unrecognized device id format: %s\n", debugstr_w(path)); - hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - } - - if (FAILED(hr)) { - WARN("Failed to get requested device (%s): %08lx\n", debugstr_w(path), hr); - *mmdev = NULL; - hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - } - - IMMDeviceEnumerator_Release(devenum); - - return hr; -} - -/*********************************************************************** - * ActivateAudioInterfaceAsync (MMDEVAPI.17) - */ -HRESULT WINAPI ActivateAudioInterfaceAsync(const WCHAR *path, REFIID riid, - PROPVARIANT *params, IActivateAudioInterfaceCompletionHandler *done_handler, - IActivateAudioInterfaceAsyncOperation **op_out) -{ - struct activate_async_op *op; - HANDLE ht; - IMMDevice *mmdev; - - TRACE("(%s, %s, %p, %p, %p)\n", debugstr_w(path), debugstr_guid(riid), - params, done_handler, op_out); - - op = HeapAlloc(GetProcessHeap(), 0, sizeof(*op)); - if (!op) - return E_OUTOFMEMORY; - - op->ref = 2; /* returned ref and threadproc ref */ - op->IActivateAudioInterfaceAsyncOperation_iface.lpVtbl = &IActivateAudioInterfaceAsyncOperation_vtbl; - op->callback = done_handler; - IActivateAudioInterfaceCompletionHandler_AddRef(done_handler); - - op->result_hr = get_mmdevice_by_activatepath(path, &mmdev); - if (SUCCEEDED(op->result_hr)) { - op->result_hr = IMMDevice_Activate(mmdev, riid, CLSCTX_INPROC_SERVER, params, (void**)&op->result_iface); - IMMDevice_Release(mmdev); - }else - op->result_iface = NULL; - - ht = CreateThread(NULL, 0, &activate_async_threadproc, op, 0, NULL); - CloseHandle(ht); - - *op_out = &op->IActivateAudioInterfaceAsyncOperation_iface; - - return S_OK; -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi.h b/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi.h deleted file mode 100644 index 5505385..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2009 Maarten Lankhorst - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "unixlib.h" -#include -#include - -extern HRESULT MMDevEnum_Create(REFIID riid, void **ppv); -extern void MMDevEnum_Free(void); - -typedef struct _DriverFuncs { - HMODULE module; - WCHAR module_name[64]; - int priority; - - /* Returns a "priority" value for the driver. Highest priority wins. - * If multiple drivers think they are valid, they will return a - * priority value reflecting the likelihood that they are actually - * valid. See enum _DriverPriority. */ - int (WINAPI *pGetPriority)(void); - - /* ids gets an array of human-friendly endpoint names - * keys gets an array of driver-specific stuff that is used - * in GetAudioEndpoint to identify the endpoint - * it is the caller's responsibility to free both arrays, and - * all of the elements in both arrays with HeapFree() */ - HRESULT (WINAPI *pGetEndpointIDs)(EDataFlow flow, WCHAR ***ids, - GUID **guids, UINT *num, UINT *default_index); - HRESULT (WINAPI *pGetAudioEndpoint)(void *key, IMMDevice *dev, - IAudioClient **out); - HRESULT (WINAPI *pGetAudioSessionManager)(IMMDevice *device, - IAudioSessionManager2 **out); - HRESULT (WINAPI *pGetPropValue)(GUID *guid, - const PROPERTYKEY *prop, PROPVARIANT *out); -} DriverFuncs; - -extern DriverFuncs drvs; - -typedef struct MMDevice { - IMMDevice IMMDevice_iface; - IMMEndpoint IMMEndpoint_iface; - LONG ref; - - CRITICAL_SECTION crst; - - EDataFlow flow; - DWORD state; - GUID devguid; - WCHAR *drv_id; - - struct list entry; -} MMDevice; - -extern HRESULT AudioClient_Create(MMDevice *parent, IAudioClient **ppv); -extern HRESULT AudioEndpointVolume_Create(MMDevice *parent, IAudioEndpointVolumeEx **ppv); -extern HRESULT SpatialAudioClient_Create(IMMDevice *device, ISpatialAudioClient **out); - -extern HRESULT load_devices_from_reg(void); -extern HRESULT load_driver_devices(EDataFlow flow); - -extern const WCHAR drv_keyW[]; diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi.spec b/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi.spec deleted file mode 100644 index 90ecaf5..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi.spec +++ /dev/null @@ -1,21 +0,0 @@ - 2 stub @ - 3 stub @ - 4 stub @ - 5 stub @ - 6 stub @ - 7 stub @ - 8 stub @ - 9 stub @ -10 stub @ -11 stub @ -12 stub @ -13 stub @ -14 stub @ -15 stub @ -16 stub @ -17 stdcall ActivateAudioInterfaceAsync( wstr ptr ptr ptr ptr ) - -@ stdcall -private DllCanUnloadNow() -@ stdcall -private DllGetClassObject( ptr ptr ptr ) -@ stdcall -private DllRegisterServer() -@ stdcall -private DllUnregisterServer() diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi_classes.idl b/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi_classes.idl deleted file mode 100644 index e364fce..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/mmdevapi_classes.idl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * COM Classes for mmdevapi - * - * Copyright 2010 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#pragma makedep register - -[ - helpstring("MMDeviceEnumerator class"), - threading(both), - uuid(bcde0395-e52f-467c-8e3d-c4579291692e) -] -coclass MMDeviceEnumerator { interface IMMDeviceEnumerator; } diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/spatialaudio.c b/pkgs/osu-wine/audio-revert/mmdevapi/spatialaudio.c deleted file mode 100644 index d77e0a6..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/spatialaudio.c +++ /dev/null @@ -1,976 +0,0 @@ -/* - * Copyright 2020 Andrew Eikum for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#define NONAMELESSUNION - -#include - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "wine/heap.h" -#include "wine/debug.h" -#include "wine/list.h" - -#include "ole2.h" -#include "mmdeviceapi.h" -#include "mmsystem.h" -#include "audioclient.h" -#include "endpointvolume.h" -#include "audiopolicy.h" -#include "spatialaudioclient.h" - -#include "mmdevapi.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi); - -static UINT32 AudioObjectType_to_index(AudioObjectType type) -{ - UINT32 o = 0; - while(type){ - type >>= 1; - ++o; - } - return o - 2; -} - -typedef struct SpatialAudioImpl SpatialAudioImpl; -typedef struct SpatialAudioStreamImpl SpatialAudioStreamImpl; -typedef struct SpatialAudioObjectImpl SpatialAudioObjectImpl; - -struct SpatialAudioObjectImpl { - ISpatialAudioObject ISpatialAudioObject_iface; - LONG ref; - - SpatialAudioStreamImpl *sa_stream; - AudioObjectType type; - UINT32 static_idx; - - float *buf; - - struct list entry; -}; - -struct SpatialAudioStreamImpl { - ISpatialAudioObjectRenderStream ISpatialAudioObjectRenderStream_iface; - LONG ref; - CRITICAL_SECTION lock; - - SpatialAudioImpl *sa_client; - SpatialAudioObjectRenderStreamActivationParams params; - - IAudioClient *client; - IAudioRenderClient *render; - - UINT32 period_frames, update_frames; - WAVEFORMATEXTENSIBLE stream_fmtex; - - float *buf; - - UINT32 static_object_map[17]; - - struct list objects; -}; - -struct SpatialAudioImpl { - ISpatialAudioClient ISpatialAudioClient_iface; - IAudioFormatEnumerator IAudioFormatEnumerator_iface; - IMMDevice *mmdev; - LONG ref; - WAVEFORMATEXTENSIBLE object_fmtex; -}; - -static inline SpatialAudioObjectImpl *impl_from_ISpatialAudioObject(ISpatialAudioObject *iface) -{ - return CONTAINING_RECORD(iface, SpatialAudioObjectImpl, ISpatialAudioObject_iface); -} - -static inline SpatialAudioStreamImpl *impl_from_ISpatialAudioObjectRenderStream(ISpatialAudioObjectRenderStream *iface) -{ - return CONTAINING_RECORD(iface, SpatialAudioStreamImpl, ISpatialAudioObjectRenderStream_iface); -} - -static inline SpatialAudioImpl *impl_from_ISpatialAudioClient(ISpatialAudioClient *iface) -{ - return CONTAINING_RECORD(iface, SpatialAudioImpl, ISpatialAudioClient_iface); -} - -static inline SpatialAudioImpl *impl_from_IAudioFormatEnumerator(IAudioFormatEnumerator *iface) -{ - return CONTAINING_RECORD(iface, SpatialAudioImpl, IAudioFormatEnumerator_iface); -} - -static HRESULT WINAPI SAO_QueryInterface(ISpatialAudioObject *iface, - REFIID riid, void **ppv) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - - TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_ISpatialAudioObjectBase) || - IsEqualIID(riid, &IID_ISpatialAudioObject)) { - *ppv = &This->ISpatialAudioObject_iface; - } - else - return E_NOINTERFACE; - - IUnknown_AddRef((IUnknown *)*ppv); - - return S_OK; -} - -static ULONG WINAPI SAO_AddRef(ISpatialAudioObject *iface) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - ULONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) new ref %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI SAO_Release(ISpatialAudioObject *iface) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - ULONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) new ref %lu\n", This, ref); - if(!ref){ - EnterCriticalSection(&This->sa_stream->lock); - list_remove(&This->entry); - LeaveCriticalSection(&This->sa_stream->lock); - - ISpatialAudioObjectRenderStream_Release(&This->sa_stream->ISpatialAudioObjectRenderStream_iface); - heap_free(This->buf); - heap_free(This); - } - return ref; -} - -static HRESULT WINAPI SAO_GetBuffer(ISpatialAudioObject *iface, - BYTE **buffer, UINT32 *bytes) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - - TRACE("(%p)->(%p, %p)\n", This, buffer, bytes); - - EnterCriticalSection(&This->sa_stream->lock); - - if(This->sa_stream->update_frames == ~0){ - LeaveCriticalSection(&This->sa_stream->lock); - return SPTLAUDCLNT_E_OUT_OF_ORDER; - } - - *buffer = (BYTE *)This->buf; - *bytes = This->sa_stream->update_frames * - This->sa_stream->sa_client->object_fmtex.Format.nBlockAlign; - - LeaveCriticalSection(&This->sa_stream->lock); - - return S_OK; -} - -static HRESULT WINAPI SAO_SetEndOfStream(ISpatialAudioObject *iface, UINT32 frames) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - FIXME("(%p)->(%u)\n", This, frames); - return E_NOTIMPL; -} - -static HRESULT WINAPI SAO_IsActive(ISpatialAudioObject *iface, BOOL *active) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - FIXME("(%p)->(%p)\n", This, active); - return E_NOTIMPL; -} - -static HRESULT WINAPI SAO_GetAudioObjectType(ISpatialAudioObject *iface, - AudioObjectType *type) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - - TRACE("(%p)->(%p)\n", This, type); - - *type = This->type; - - return S_OK; -} - -static HRESULT WINAPI SAO_SetPosition(ISpatialAudioObject *iface, float x, - float y, float z) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - FIXME("(%p)->(%f, %f, %f)\n", This, x, y, z); - return E_NOTIMPL; -} - -static HRESULT WINAPI SAO_SetVolume(ISpatialAudioObject *iface, float vol) -{ - SpatialAudioObjectImpl *This = impl_from_ISpatialAudioObject(iface); - FIXME("(%p)->(%f)\n", This, vol); - return E_NOTIMPL; -} - -static ISpatialAudioObjectVtbl ISpatialAudioObject_vtbl = { - SAO_QueryInterface, - SAO_AddRef, - SAO_Release, - SAO_GetBuffer, - SAO_SetEndOfStream, - SAO_IsActive, - SAO_GetAudioObjectType, - SAO_SetPosition, - SAO_SetVolume, -}; - -static HRESULT WINAPI SAORS_QueryInterface(ISpatialAudioObjectRenderStream *iface, - REFIID riid, void **ppv) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - - TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStreamBase) || - IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStream)) { - *ppv = &This->ISpatialAudioObjectRenderStream_iface; - } - else - return E_NOINTERFACE; - - IUnknown_AddRef((IUnknown *)*ppv); - - return S_OK; -} - -static ULONG WINAPI SAORS_AddRef(ISpatialAudioObjectRenderStream *iface) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - ULONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) new ref %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI SAORS_Release(ISpatialAudioObjectRenderStream *iface) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - ULONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) new ref %lu\n", This, ref); - if(!ref){ - IAudioClient_Stop(This->client); - if(This->update_frames != ~0 && This->update_frames > 0) - IAudioRenderClient_ReleaseBuffer(This->render, This->update_frames, 0); - IAudioRenderClient_Release(This->render); - IAudioClient_Release(This->client); - if(This->params.NotifyObject) - ISpatialAudioObjectRenderStreamNotify_Release(This->params.NotifyObject); - heap_free((void*)This->params.ObjectFormat); - CloseHandle(This->params.EventHandle); - DeleteCriticalSection(&This->lock); - ISpatialAudioClient_Release(&This->sa_client->ISpatialAudioClient_iface); - heap_free(This); - } - return ref; -} - -static HRESULT WINAPI SAORS_GetAvailableDynamicObjectCount( - ISpatialAudioObjectRenderStream *iface, UINT32 *count) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - FIXME("(%p)->(%p)\n", This, count); - - *count = 0; - return S_OK; -} - -static HRESULT WINAPI SAORS_GetService(ISpatialAudioObjectRenderStream *iface, - REFIID riid, void **service) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(riid), service); - return E_NOTIMPL; -} - -static HRESULT WINAPI SAORS_Start(ISpatialAudioObjectRenderStream *iface) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - HRESULT hr; - - TRACE("(%p)->()\n", This); - - hr = IAudioClient_Start(This->client); - if(FAILED(hr)){ - WARN("IAudioClient::Start failed: %08lx\n", hr); - return hr; - } - - return S_OK; -} - -static HRESULT WINAPI SAORS_Stop(ISpatialAudioObjectRenderStream *iface) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - HRESULT hr; - - TRACE("(%p)->()\n", This); - - hr = IAudioClient_Stop(This->client); - if(FAILED(hr)){ - WARN("IAudioClient::Stop failed: %08lx\n", hr); - return hr; - } - - return S_OK; -} - -static HRESULT WINAPI SAORS_Reset(ISpatialAudioObjectRenderStream *iface) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - FIXME("(%p)->()\n", This); - return E_NOTIMPL; -} - -static HRESULT WINAPI SAORS_BeginUpdatingAudioObjects(ISpatialAudioObjectRenderStream *iface, - UINT32 *dyn_count, UINT32 *frames) -{ - static BOOL fixme_once = FALSE; - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - SpatialAudioObjectImpl *object; - HRESULT hr; - - TRACE("(%p)->(%p, %p)\n", This, dyn_count, frames); - - EnterCriticalSection(&This->lock); - - if(This->update_frames != ~0){ - LeaveCriticalSection(&This->lock); - return SPTLAUDCLNT_E_OUT_OF_ORDER; - } - - This->update_frames = This->period_frames; - - if(This->update_frames > 0){ - hr = IAudioRenderClient_GetBuffer(This->render, This->update_frames, (BYTE **)&This->buf); - if(FAILED(hr)){ - WARN("GetBuffer failed: %08lx\n", hr); - This->update_frames = ~0; - LeaveCriticalSection(&This->lock); - return hr; - } - - LIST_FOR_EACH_ENTRY(object, &This->objects, SpatialAudioObjectImpl, entry){ - memset(object->buf, 0, This->update_frames * This->sa_client->object_fmtex.Format.nBlockAlign); - } - }else if (!fixme_once){ - fixme_once = TRUE; - FIXME("Zero frame update.\n"); - } - - *dyn_count = 0; - *frames = This->update_frames; - - LeaveCriticalSection(&This->lock); - - return S_OK; -} - -static void mix_static_object(SpatialAudioStreamImpl *stream, SpatialAudioObjectImpl *object) -{ - float *in = object->buf, *out; - UINT32 i; - if(object->static_idx == ~0 || - stream->static_object_map[object->static_idx] == ~0){ - WARN("Got unmapped static object?! Not mixing. Type: 0x%x\n", object->type); - return; - } - out = stream->buf + stream->static_object_map[object->static_idx]; - for(i = 0; i < stream->update_frames; ++i){ - *out += *in; - ++in; - out += stream->stream_fmtex.Format.nChannels; - } -} - -static HRESULT WINAPI SAORS_EndUpdatingAudioObjects(ISpatialAudioObjectRenderStream *iface) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - SpatialAudioObjectImpl *object; - HRESULT hr; - - TRACE("(%p)->()\n", This); - - EnterCriticalSection(&This->lock); - - if(This->update_frames == ~0){ - LeaveCriticalSection(&This->lock); - return SPTLAUDCLNT_E_OUT_OF_ORDER; - } - - if(This->update_frames > 0){ - LIST_FOR_EACH_ENTRY(object, &This->objects, SpatialAudioObjectImpl, entry){ - if(object->type != AudioObjectType_Dynamic) - mix_static_object(This, object); - else - WARN("Don't know how to mix dynamic object yet. %p\n", object); - } - - hr = IAudioRenderClient_ReleaseBuffer(This->render, This->update_frames, 0); - if(FAILED(hr)) - WARN("ReleaseBuffer failed: %08lx\n", hr); - } - - This->update_frames = ~0; - - LeaveCriticalSection(&This->lock); - - return S_OK; -} - -static HRESULT WINAPI SAORS_ActivateSpatialAudioObject(ISpatialAudioObjectRenderStream *iface, - AudioObjectType type, ISpatialAudioObject **object) -{ - SpatialAudioStreamImpl *This = impl_from_ISpatialAudioObjectRenderStream(iface); - SpatialAudioObjectImpl *obj; - - TRACE("(%p)->(0x%x, %p)\n", This, type, object); - - if(type == AudioObjectType_Dynamic) - return SPTLAUDCLNT_E_NO_MORE_OBJECTS; - - if(type & ~This->params.StaticObjectTypeMask) - return SPTLAUDCLNT_E_STATIC_OBJECT_NOT_AVAILABLE; - - LIST_FOR_EACH_ENTRY(obj, &This->objects, SpatialAudioObjectImpl, entry){ - if(obj->static_idx == AudioObjectType_to_index(type)) - return SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE; - } - - obj = heap_alloc_zero(sizeof(*obj)); - obj->ISpatialAudioObject_iface.lpVtbl = &ISpatialAudioObject_vtbl; - obj->ref = 1; - obj->type = type; - if(type == AudioObjectType_None){ - FIXME("AudioObjectType_None not implemented yet!\n"); - obj->static_idx = ~0; - }else{ - obj->static_idx = AudioObjectType_to_index(type); - } - - obj->sa_stream = This; - SAORS_AddRef(&This->ISpatialAudioObjectRenderStream_iface); - - obj->buf = heap_alloc_zero(This->period_frames * This->sa_client->object_fmtex.Format.nBlockAlign); - - EnterCriticalSection(&This->lock); - - list_add_tail(&This->objects, &obj->entry); - - LeaveCriticalSection(&This->lock); - - *object = &obj->ISpatialAudioObject_iface; - - return S_OK; -} - -static ISpatialAudioObjectRenderStreamVtbl ISpatialAudioObjectRenderStream_vtbl = { - SAORS_QueryInterface, - SAORS_AddRef, - SAORS_Release, - SAORS_GetAvailableDynamicObjectCount, - SAORS_GetService, - SAORS_Start, - SAORS_Stop, - SAORS_Reset, - SAORS_BeginUpdatingAudioObjects, - SAORS_EndUpdatingAudioObjects, - SAORS_ActivateSpatialAudioObject, -}; - -static HRESULT WINAPI SAC_QueryInterface(ISpatialAudioClient *iface, REFIID riid, void **ppv) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - - TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_ISpatialAudioClient)) { - *ppv = &This->ISpatialAudioClient_iface; - } - else - return E_NOINTERFACE; - - IUnknown_AddRef((IUnknown *)*ppv); - - return S_OK; -} - -static ULONG WINAPI SAC_AddRef(ISpatialAudioClient *iface) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - ULONG ref = InterlockedIncrement(&This->ref); - TRACE("(%p) new ref %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI SAC_Release(ISpatialAudioClient *iface) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - ULONG ref = InterlockedDecrement(&This->ref); - TRACE("(%p) new ref %lu\n", This, ref); - if (!ref) { - IMMDevice_Release(This->mmdev); - heap_free(This); - } - return ref; -} - -static HRESULT WINAPI SAC_GetStaticObjectPosition(ISpatialAudioClient *iface, - AudioObjectType type, float *x, float *y, float *z) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - FIXME("(%p)->(0x%x, %p, %p, %p)\n", This, type, x, y, z); - return E_NOTIMPL; -} - -static HRESULT WINAPI SAC_GetNativeStaticObjectTypeMask(ISpatialAudioClient *iface, - AudioObjectType *mask) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - FIXME("(%p)->(%p)\n", This, mask); - return E_NOTIMPL; -} - -static HRESULT WINAPI SAC_GetMaxDynamicObjectCount(ISpatialAudioClient *iface, - UINT32 *value) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - FIXME("(%p)->(%p)\n", This, value); - - *value = 0; - - return S_OK; -} - -static HRESULT WINAPI SAC_GetSupportedAudioObjectFormatEnumerator( - ISpatialAudioClient *iface, IAudioFormatEnumerator **enumerator) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - - TRACE("(%p)->(%p)\n", This, enumerator); - - *enumerator = &This->IAudioFormatEnumerator_iface; - SAC_AddRef(iface); - - return S_OK; -} - -static HRESULT WINAPI SAC_GetMaxFrameCount(ISpatialAudioClient *iface, - const WAVEFORMATEX *format, UINT32 *count) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - - /* FIXME: should get device period from the device */ - static const REFERENCE_TIME period = 100000; - - TRACE("(%p)->(%p, %p)\n", This, format, count); - - *count = MulDiv(period, format->nSamplesPerSec, 10000000); - - return S_OK; -} - -static HRESULT WINAPI SAC_IsAudioObjectFormatSupported(ISpatialAudioClient *iface, - const WAVEFORMATEX *format) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - FIXME("(%p)->(%p)\n", This, format); - return E_NOTIMPL; -} - -static HRESULT WINAPI SAC_IsSpatialAudioStreamAvailable(ISpatialAudioClient *iface, - REFIID stream_uuid, const PROPVARIANT *info) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - FIXME("(%p)->(%s, %p)\n", This, debugstr_guid(stream_uuid), info); - return E_NOTIMPL; -} - -static WAVEFORMATEX *clone_fmtex(const WAVEFORMATEX *src) -{ - WAVEFORMATEX *r = heap_alloc(sizeof(WAVEFORMATEX) + src->cbSize); - memcpy(r, src, sizeof(WAVEFORMATEX) + src->cbSize); - return r; -} - -static const char *debugstr_fmtex(const WAVEFORMATEX *fmt) -{ - static char buf[2048]; - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt; - snprintf(buf, sizeof(buf), "tag: 0x%x (%s), ch: %u (mask: 0x%lx), rate: %lu, depth: %u", - fmt->wFormatTag, debugstr_guid(&fmtex->SubFormat), - fmt->nChannels, fmtex->dwChannelMask, fmt->nSamplesPerSec, - fmt->wBitsPerSample); - }else{ - snprintf(buf, sizeof(buf), "tag: 0x%x, ch: %u, rate: %lu, depth: %u", - fmt->wFormatTag, fmt->nChannels, fmt->nSamplesPerSec, - fmt->wBitsPerSample); - } - return buf; -} - -static void static_mask_to_channels(AudioObjectType static_mask, WORD *count, DWORD *mask, UINT32 *map) -{ - UINT32 out_chan = 0, map_idx = 0; - *count = 0; - *mask = 0; -#define CONVERT_MASK(f, t) \ - if(static_mask & f){ \ - *count += 1; \ - *mask |= t; \ - map[map_idx++] = out_chan++; \ - TRACE("mapping 0x%x to %u\n", f, out_chan - 1); \ - }else{ \ - map[map_idx++] = ~0; \ - } - CONVERT_MASK(AudioObjectType_FrontLeft, SPEAKER_FRONT_LEFT); - CONVERT_MASK(AudioObjectType_FrontRight, SPEAKER_FRONT_RIGHT); - CONVERT_MASK(AudioObjectType_FrontCenter, SPEAKER_FRONT_CENTER); - CONVERT_MASK(AudioObjectType_LowFrequency, SPEAKER_LOW_FREQUENCY); - CONVERT_MASK(AudioObjectType_SideLeft, SPEAKER_SIDE_LEFT); - CONVERT_MASK(AudioObjectType_SideRight, SPEAKER_SIDE_RIGHT); - CONVERT_MASK(AudioObjectType_BackLeft, SPEAKER_BACK_LEFT); - CONVERT_MASK(AudioObjectType_BackRight, SPEAKER_BACK_RIGHT); - CONVERT_MASK(AudioObjectType_TopFrontLeft, SPEAKER_TOP_FRONT_LEFT); - CONVERT_MASK(AudioObjectType_TopFrontRight, SPEAKER_TOP_FRONT_RIGHT); - CONVERT_MASK(AudioObjectType_TopBackLeft, SPEAKER_TOP_BACK_LEFT); - CONVERT_MASK(AudioObjectType_TopBackRight, SPEAKER_TOP_BACK_RIGHT); - CONVERT_MASK(AudioObjectType_BackCenter, SPEAKER_BACK_CENTER); -} - -static HRESULT activate_stream(SpatialAudioStreamImpl *stream) -{ - WAVEFORMATEXTENSIBLE *object_fmtex = (WAVEFORMATEXTENSIBLE *)stream->params.ObjectFormat; - HRESULT hr; - REFERENCE_TIME period; - - if(!(object_fmtex->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (object_fmtex->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&object_fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))){ - FIXME("Only float formats are supported for now\n"); - return E_INVALIDARG; - } - - hr = IMMDevice_Activate(stream->sa_client->mmdev, &IID_IAudioClient, - CLSCTX_INPROC_SERVER, NULL, (void**)&stream->client); - if(FAILED(hr)){ - WARN("Activate failed: %08lx\n", hr); - return hr; - } - - hr = IAudioClient_GetDevicePeriod(stream->client, &period, NULL); - if(FAILED(hr)){ - WARN("GetDevicePeriod failed: %08lx\n", hr); - IAudioClient_Release(stream->client); - return hr; - } - - stream->stream_fmtex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - static_mask_to_channels(stream->params.StaticObjectTypeMask, - &stream->stream_fmtex.Format.nChannels, &stream->stream_fmtex.dwChannelMask, - stream->static_object_map); - stream->stream_fmtex.Format.nSamplesPerSec = stream->params.ObjectFormat->nSamplesPerSec; - stream->stream_fmtex.Format.wBitsPerSample = stream->params.ObjectFormat->wBitsPerSample; - stream->stream_fmtex.Format.nBlockAlign = (stream->stream_fmtex.Format.nChannels * stream->stream_fmtex.Format.wBitsPerSample) / 8; - stream->stream_fmtex.Format.nAvgBytesPerSec = stream->stream_fmtex.Format.nSamplesPerSec * stream->stream_fmtex.Format.nBlockAlign; - stream->stream_fmtex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - stream->stream_fmtex.Samples.wValidBitsPerSample = stream->stream_fmtex.Format.wBitsPerSample; - stream->stream_fmtex.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - - hr = IAudioClient_Initialize(stream->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, - period, 0, &stream->stream_fmtex.Format, NULL); - if(FAILED(hr)){ - WARN("Initialize failed: %08lx\n", hr); - IAudioClient_Release(stream->client); - return hr; - } - - hr = IAudioClient_SetEventHandle(stream->client, stream->params.EventHandle); - if(FAILED(hr)){ - WARN("SetEventHandle failed: %08lx\n", hr); - IAudioClient_Release(stream->client); - return hr; - } - - hr = IAudioClient_GetService(stream->client, &IID_IAudioRenderClient, (void**)&stream->render); - if(FAILED(hr)){ - WARN("GetService(AudioRenderClient) failed: %08lx\n", hr); - IAudioClient_Release(stream->client); - return hr; - } - - stream->period_frames = MulDiv(period, stream->stream_fmtex.Format.nSamplesPerSec, 10000000); - - return S_OK; -} - -static HRESULT WINAPI SAC_ActivateSpatialAudioStream(ISpatialAudioClient *iface, - const PROPVARIANT *prop, REFIID riid, void **stream) -{ - SpatialAudioImpl *This = impl_from_ISpatialAudioClient(iface); - SpatialAudioObjectRenderStreamActivationParams *params; - HRESULT hr; - - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), stream); - - if(IsEqualIID(riid, &IID_ISpatialAudioObjectRenderStream)){ - SpatialAudioStreamImpl *obj; - - if(prop && - (prop->vt != VT_BLOB || - prop->blob.cbSize != sizeof(SpatialAudioObjectRenderStreamActivationParams))){ - WARN("Got invalid params\n"); - *stream = NULL; - return E_INVALIDARG; - } - - params = (SpatialAudioObjectRenderStreamActivationParams*) prop->blob.pBlobData; - - if(params->StaticObjectTypeMask & AudioObjectType_Dynamic){ - *stream = NULL; - return E_INVALIDARG; - } - - if(params->EventHandle == INVALID_HANDLE_VALUE || - params->EventHandle == 0){ - *stream = NULL; - return E_INVALIDARG; - } - - if(!params->ObjectFormat || - memcmp(params->ObjectFormat, &This->object_fmtex.Format, sizeof(*params->ObjectFormat) + params->ObjectFormat->cbSize)){ - *stream = NULL; - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - - obj = heap_alloc_zero(sizeof(SpatialAudioStreamImpl)); - - obj->ISpatialAudioObjectRenderStream_iface.lpVtbl = &ISpatialAudioObjectRenderStream_vtbl; - obj->ref = 1; - memcpy(&obj->params, params, sizeof(obj->params)); - - obj->update_frames = ~0; - - InitializeCriticalSection(&obj->lock); - list_init(&obj->objects); - - obj->sa_client = This; - SAC_AddRef(&This->ISpatialAudioClient_iface); - - obj->params.ObjectFormat = clone_fmtex(obj->params.ObjectFormat); - - DuplicateHandle(GetCurrentProcess(), obj->params.EventHandle, - GetCurrentProcess(), &obj->params.EventHandle, 0, FALSE, - DUPLICATE_SAME_ACCESS); - - if(obj->params.NotifyObject) - ISpatialAudioObjectRenderStreamNotify_AddRef(obj->params.NotifyObject); - - if(TRACE_ON(mmdevapi)){ - TRACE("ObjectFormat: {%s}\n", debugstr_fmtex(obj->params.ObjectFormat)); - TRACE("StaticObjectTypeMask: 0x%x\n", obj->params.StaticObjectTypeMask); - TRACE("MinDynamicObjectCount: 0x%x\n", obj->params.MinDynamicObjectCount); - TRACE("MaxDynamicObjectCount: 0x%x\n", obj->params.MaxDynamicObjectCount); - TRACE("Category: 0x%x\n", obj->params.Category); - TRACE("EventHandle: %p\n", obj->params.EventHandle); - TRACE("NotifyObject: %p\n", obj->params.NotifyObject); - } - - hr = activate_stream(obj); - if(FAILED(hr)){ - if(obj->params.NotifyObject) - ISpatialAudioObjectRenderStreamNotify_Release(obj->params.NotifyObject); - DeleteCriticalSection(&obj->lock); - heap_free((void*)obj->params.ObjectFormat); - CloseHandle(obj->params.EventHandle); - ISpatialAudioClient_Release(&obj->sa_client->ISpatialAudioClient_iface); - heap_free(obj); - *stream = NULL; - return hr; - } - - *stream = &obj->ISpatialAudioObjectRenderStream_iface; - }else{ - FIXME("Unsupported audio stream IID: %s\n", debugstr_guid(riid)); - *stream = NULL; - return E_NOTIMPL; - } - - return S_OK; -} - -static ISpatialAudioClientVtbl ISpatialAudioClient_vtbl = { - SAC_QueryInterface, - SAC_AddRef, - SAC_Release, - SAC_GetStaticObjectPosition, - SAC_GetNativeStaticObjectTypeMask, - SAC_GetMaxDynamicObjectCount, - SAC_GetSupportedAudioObjectFormatEnumerator, - SAC_GetMaxFrameCount, - SAC_IsAudioObjectFormatSupported, - SAC_IsSpatialAudioStreamAvailable, - SAC_ActivateSpatialAudioStream, -}; - -static HRESULT WINAPI SAOFE_QueryInterface(IAudioFormatEnumerator *iface, - REFIID riid, void **ppvObject) -{ - SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface); - return SAC_QueryInterface(&This->ISpatialAudioClient_iface, riid, ppvObject); -} - -static ULONG WINAPI SAOFE_AddRef(IAudioFormatEnumerator *iface) -{ - SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface); - return SAC_AddRef(&This->ISpatialAudioClient_iface); -} - -static ULONG WINAPI SAOFE_Release(IAudioFormatEnumerator *iface) -{ - SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface); - return SAC_Release(&This->ISpatialAudioClient_iface); -} - -static HRESULT WINAPI SAOFE_GetCount(IAudioFormatEnumerator *iface, UINT32 *count) -{ - SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface); - - TRACE("(%p)->(%p)\n", This, count); - - *count = 1; - - return S_OK; -} - -static HRESULT WINAPI SAOFE_GetFormat(IAudioFormatEnumerator *iface, - UINT32 index, WAVEFORMATEX **format) -{ - SpatialAudioImpl *This = impl_from_IAudioFormatEnumerator(iface); - - TRACE("(%p)->(%u, %p)\n", This, index, format); - - if(index > 0) - return E_INVALIDARG; - - *format = &This->object_fmtex.Format; - - return S_OK; -} - -static IAudioFormatEnumeratorVtbl IAudioFormatEnumerator_vtbl = { - SAOFE_QueryInterface, - SAOFE_AddRef, - SAOFE_Release, - SAOFE_GetCount, - SAOFE_GetFormat, -}; - -HRESULT SpatialAudioClient_Create(IMMDevice *mmdev, ISpatialAudioClient **out) -{ - SpatialAudioImpl *obj; - IAudioClient *aclient; - WAVEFORMATEX *closest; - HRESULT hr; - - obj = heap_alloc_zero(sizeof(*obj)); - - obj->ref = 1; - obj->ISpatialAudioClient_iface.lpVtbl = &ISpatialAudioClient_vtbl; - obj->IAudioFormatEnumerator_iface.lpVtbl = &IAudioFormatEnumerator_vtbl; - - obj->object_fmtex.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - obj->object_fmtex.Format.nChannels = 1; - obj->object_fmtex.Format.nSamplesPerSec = 48000; - obj->object_fmtex.Format.wBitsPerSample = sizeof(float) * 8; - obj->object_fmtex.Format.nBlockAlign = (obj->object_fmtex.Format.nChannels * obj->object_fmtex.Format.wBitsPerSample) / 8; - obj->object_fmtex.Format.nAvgBytesPerSec = obj->object_fmtex.Format.nSamplesPerSec * obj->object_fmtex.Format.nBlockAlign; - obj->object_fmtex.Format.cbSize = 0; - - hr = IMMDevice_Activate(mmdev, &IID_IAudioClient, - CLSCTX_INPROC_SERVER, NULL, (void**)&aclient); - if(FAILED(hr)){ - WARN("Activate failed: %08lx\n", hr); - heap_free(obj); - return hr; - } - - hr = IAudioClient_IsFormatSupported(aclient, AUDCLNT_SHAREMODE_SHARED, &obj->object_fmtex.Format, &closest); - - IAudioClient_Release(aclient); - - if(hr == S_FALSE){ - if(sizeof(WAVEFORMATEX) + closest->cbSize > sizeof(obj->object_fmtex)){ - ERR("Returned format too large: %s\n", debugstr_fmtex(closest)); - CoTaskMemFree(closest); - heap_free(obj); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - }else if(!((closest->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (closest->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&((WAVEFORMATEXTENSIBLE *)closest)->SubFormat, - &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) && - closest->wBitsPerSample == 32)){ - ERR("Returned format not 32-bit float: %s\n", debugstr_fmtex(closest)); - CoTaskMemFree(closest); - heap_free(obj); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - WARN("The audio stack doesn't support 48kHz 32bit float. Using the closest match. Audio may be glitchy. %s\n", debugstr_fmtex(closest)); - memcpy(&obj->object_fmtex, - closest, - sizeof(WAVEFORMATEX) + closest->cbSize); - CoTaskMemFree(closest); - } else if(hr != S_OK){ - WARN("Checking supported formats failed: %08lx\n", hr); - heap_free(obj); - return hr; - } - - obj->mmdev = mmdev; - IMMDevice_AddRef(mmdev); - - *out = &obj->ISpatialAudioClient_iface; - - return S_OK; -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/tests/Makefile.in b/pkgs/osu-wine/audio-revert/mmdevapi/tests/Makefile.in deleted file mode 100644 index dd180a2..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/tests/Makefile.in +++ /dev/null @@ -1,10 +0,0 @@ -TESTDLL = mmdevapi.dll -IMPORTS = ole32 version user32 advapi32 winmm - -C_SRCS = \ - capture.c \ - dependency.c \ - mmdevenum.c \ - propstore.c \ - render.c \ - spatialaudio.c diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/tests/capture.c b/pkgs/osu-wine/audio-revert/mmdevapi/tests/capture.c deleted file mode 100644 index f3b426a..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/tests/capture.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Copyright 2010 Maarten Lankhorst for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* This test is for audio capture specific mechanisms - * Tests: - * - IAudioClient with eCapture and IAudioCaptureClient - */ - -#include - -#include "wine/test.h" - -#define COBJMACROS - -#ifdef STANDALONE -#include "initguid.h" -#endif - -#include "unknwn.h" -#include "uuids.h" -#include "mmdeviceapi.h" -#include "audioclient.h" - -#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) - -/* undocumented error code */ -#define D3D11_ERROR_4E MAKE_HRESULT(SEVERITY_ERROR, FACILITY_DIRECT3D11, 0x4e) - -static IMMDevice *dev = NULL; -static const LARGE_INTEGER ullZero; - -static void test_uninitialized(IAudioClient *ac) -{ - HRESULT hr; - UINT32 num; - REFERENCE_TIME t1; - - HANDLE handle = CreateEventW(NULL, FALSE, FALSE, NULL); - IUnknown *unk; - - hr = IAudioClient_GetBufferSize(ac, &num); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized GetBufferSize call returns %08lx\n", hr); - - hr = IAudioClient_GetStreamLatency(ac, &t1); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized GetStreamLatency call returns %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &num); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized GetCurrentPadding call returns %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized Start call returns %08lx\n", hr); - - hr = IAudioClient_Stop(ac); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized Stop call returns %08lx\n", hr); - - hr = IAudioClient_Reset(ac); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized Reset call returns %08lx\n", hr); - - hr = IAudioClient_SetEventHandle(ac, handle); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized SetEventHandle call returns %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_IAudioStreamVolume, (void**)&unk); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized GetService call returns %08lx\n", hr); - - CloseHandle(handle); -} - -static void test_capture(IAudioClient *ac, HANDLE handle, WAVEFORMATEX *wfx) -{ - IAudioCaptureClient *acc; - HRESULT hr; - UINT32 frames, next, pad, sum = 0; - BYTE *data; - DWORD flags; - UINT64 pos, qpc; - REFERENCE_TIME period; - - hr = IAudioClient_GetService(ac, &IID_IAudioCaptureClient, (void**)&acc); - ok(hr == S_OK, "IAudioClient_GetService(IID_IAudioCaptureClient) returns %08lx\n", hr); - if (hr != S_OK) - return; - - ok(ResetEvent(handle), "ResetEvent\n"); - - hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); - ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - ok(next == pad, "GetNextPacketSize %u vs. GCP %u\n", next, pad); - /* later GCP will grow, while GNPS is 0 or period size */ - - hr = IAudioCaptureClient_GetNextPacketSize(acc, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetNextPacketSize(NULL) returns %08lx\n", hr); - - data = (void*)0xdeadf00d; - frames = 0xdeadbeef; - flags = 0xabadcafe; - hr = IAudioCaptureClient_GetBuffer(acc, &data, NULL, NULL, NULL, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(data, NULL, NULL) returns %08lx\n", hr); - - hr = IAudioCaptureClient_GetBuffer(acc, NULL, &frames, NULL, NULL, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, &frames, NULL) returns %08lx\n", hr); - - hr = IAudioCaptureClient_GetBuffer(acc, NULL, NULL, &flags, NULL, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(NULL, NULL, &flags) returns %08lx\n", hr); - - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, NULL, NULL, NULL); - ok(hr == E_POINTER, "IAudioCaptureClient_GetBuffer(&ata, &frames, NULL) returns %08lx\n", hr); - ok(broken((DWORD_PTR)data == 0xdeadf00d) || /* <= win8 */ - data == NULL, "data is reset to %p\n", data); - ok(frames == 0xdeadbeef, "frames is reset to %08x\n", frames); - ok(flags == 0xabadcafe, "flags is reset to %08lx\n", flags); - - hr = IAudioClient_GetDevicePeriod(ac, &period, NULL); - ok(hr == S_OK, "GetDevicePeriod failed: %08lx\n", hr); - period = MulDiv(period, wfx->nSamplesPerSec, 10000000); /* as in render.c */ - - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr); - - ok(WaitForSingleObject(handle, 1000) == WAIT_OBJECT_0, "Waiting on event handle failed!\n"); - - data = (void*)0xdeadf00d; - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - ok(hr == S_OK || hr == AUDCLNT_S_BUFFER_EMPTY, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - if (hr == S_OK){ - ok(frames, "Amount of frames locked is 0!\n"); - /* broken: some w7 machines return pad == 0 and DATA_DISCONTINUITY here, - * AUDCLNT_S_BUFFER_EMPTY above, yet pos == 1-2 * period rather than 0 */ - ok(pos == sum || broken(flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY), - "Position %u expected %u\n", (UINT)pos, sum); - sum = pos; - }else if (hr == AUDCLNT_S_BUFFER_EMPTY){ - ok(!frames, "Amount of frames locked with empty buffer is %u!\n", frames); - ok(broken(data == (void*)0xdeadf00d) || /* <= win8 */ - data == NULL, "No data changed to %p\n", data); - } - - trace("Wait'ed position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); - - hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); - ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08lx\n", hr); - ok(next == frames, "GetNextPacketSize %u vs. GetBuffer %u\n", next, frames); - - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); - - hr = IAudioCaptureClient_ReleaseBuffer(acc, 0); - ok(hr == S_OK, "Releasing 0 returns %08lx\n", hr); - - hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); - ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08lx\n", hr); - - if (frames) { - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Releasing buffer twice returns %08lx\n", hr); - sum += frames; - } - - Sleep(350); /* for sure there's data now */ - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - - /** GetNextPacketSize - * returns either 0 or one period worth of frames - * whereas GetCurrentPadding grows when input is not consumed. */ - hr = IAudioCaptureClient_GetNextPacketSize(acc, &next); - ok(hr == S_OK, "IAudioCaptureClient_GetNextPacketSize returns %08lx\n", hr); - flaky_wine - ok(next < pad, "GetNextPacketSize %u vs. GCP %u\n", next, pad); - - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - ok(next == frames, "GetNextPacketSize %u vs. GetBuffer %u\n", next, frames); - - if(hr == S_OK){ - UINT32 frames2 = frames; - UINT64 pos2, qpc2; - ok(frames, "Amount of frames locked is 0!\n"); - ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); - - hr = IAudioCaptureClient_ReleaseBuffer(acc, 0); - ok(hr == S_OK, "Releasing 0 returns %08lx\n", hr); - - /* GCP did not decrement, no data consumed */ - hr = IAudioClient_GetCurrentPadding(ac, &frames); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - ok(frames == pad || frames == pad + next /* concurrent feeder */, - "GCP %u past ReleaseBuffer(0) initially %u\n", frames, pad); - - /* should re-get the same data */ - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos2, &qpc2); - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - ok(frames2 == frames, "GetBuffer after ReleaseBuffer(0) %u/%u\n", frames2, frames); - ok(pos2 == pos, "Position after ReleaseBuffer(0) %u/%u\n", (UINT)pos2, (UINT)pos); - todo_wine_if(qpc2 != qpc) - /* FIXME: Some drivers fail */ - ok(qpc2 == qpc, "HPC after ReleaseBuffer(0) %u vs. %u\n", (UINT)qpc2, (UINT)qpc); - } - - /* trace after the GCP test because log output to MS-DOS console disturbs timing */ - trace("Sleep.1 position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); - - if(hr == S_OK){ - UINT32 frames2 = 0xabadcafe; - BYTE *data2 = (void*)0xdeadf00d; - flags = 0xabadcafe; - - ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); - - pos = qpc = 0xdeadbeef; - hr = IAudioCaptureClient_GetBuffer(acc, &data2, &frames2, &flags, &pos, &qpc); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Out of order IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - ok(frames2 == 0xabadcafe, "Out of order frames changed to %x\n", frames2); - ok(broken(data2 == (void*)0xdeadf00d) /* <= win8 */ || - data2 == NULL, "Out of order data changed to %p\n", data2); - ok(flags == 0xabadcafe, "Out of order flags changed to %lx\n", flags); - ok(pos == 0xdeadbeef, "Out of order position changed to %x\n", (UINT)pos); - ok(qpc == 0xdeadbeef, "Out of order timer changed to %x\n", (UINT)qpc); - - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames+1); - ok(hr == AUDCLNT_E_INVALID_SIZE, "Releasing buffer+1 returns %08lx\n", hr); - - hr = IAudioCaptureClient_ReleaseBuffer(acc, 1); - ok(hr == AUDCLNT_E_INVALID_SIZE, "Releasing 1 returns %08lx\n", hr); - - hr = IAudioClient_Reset(ac); - ok(hr == AUDCLNT_E_NOT_STOPPED, "Reset failed: %08lx\n", hr); - } - - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); - - if (frames) { - sum += frames; - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "Releasing buffer twice returns %08lx\n", hr); - } - - frames = period; - flaky_wine - ok(next == frames, "GetNextPacketSize %u vs. GetDevicePeriod %u\n", next, frames); - - /* GetBufferSize is not a multiple of the period size! */ - hr = IAudioClient_GetBufferSize(ac, &next); - ok(hr == S_OK, "GetBufferSize failed: %08lx\n", hr); - trace("GetBufferSize %u period size %u\n", next, frames); - - Sleep(400); /* overrun */ - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - - trace("Overrun position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); - - if(hr == S_OK){ - if(flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY){ - /* Native's position is one period further than what we read. - * Perhaps that's precisely the meaning of DATA_DISCONTINUITY: - * signal when the position jump left a gap. */ - ok(pos == sum + frames, "Position %u last %u frames %u\n", (UINT)pos, sum, frames); - sum = pos; - }else{ /* win10 */ - ok(pos == sum, "Position %u last %u frames %u\n", (UINT)pos, sum, frames); - } - - ok(pad == next, "GCP %u vs. BufferSize %u\n", (UINT32)pad, next); - } - - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); - sum += frames; - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - - trace("Cont'ed position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); - - if(hr == S_OK){ - flaky_wine - ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); - flaky_wine - ok(!flags, "flags %lu\n", flags); - - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); - sum += frames; - } - - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop on a started stream returns %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr); - - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - - trace("Restart position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); - flaky_wine - ok(pad > sum, "restarted GCP %u\n", pad); /* GCP is still near buffer size */ - - if(frames){ - flaky_wine - ok(pos == sum, "Position %u expected %u\n", (UINT)pos, sum); - ok(!flags, "flags %lu\n", flags); - - hr = IAudioCaptureClient_ReleaseBuffer(acc, frames); - ok(hr == S_OK, "Releasing buffer returns %08lx\n", hr); - sum += frames; - } - - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop on a started stream returns %08lx\n", hr); - - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset on a stopped stream returns %08lx\n", hr); - sum += pad - frames; - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - ok(!pad, "reset GCP %u\n", pad); - - flags = 0xabadcafe; - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - ok(hr == AUDCLNT_S_BUFFER_EMPTY, - "Initial IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - - trace("Reset position %d pad %u flags %lx, amount of frames locked: %u\n", - hr==S_OK ? (UINT)pos : -1, pad, flags, frames); - - if(SUCCEEDED(hr)) - IAudioCaptureClient_ReleaseBuffer(acc, frames); - - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr); - - Sleep(180); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding call returns %08lx\n", hr); - - hr = IAudioCaptureClient_GetBuffer(acc, &data, &frames, &flags, &pos, &qpc); - flaky_wine - ok(hr == S_OK, "Valid IAudioCaptureClient_GetBuffer returns %08lx\n", hr); - trace("Running position %d pad %u flags %lx, amount of frames locked: %u\n", - SUCCEEDED(hr) ? (UINT)pos : -1, pad, flags, frames); - - if(SUCCEEDED(hr)){ - /* Some w7 machines signal DATA_DISCONTINUITY here following the - * previous AUDCLNT_S_BUFFER_EMPTY, others not. What logic? */ - ok(pos >= sum, "Position %u gap %d\n", (UINT)pos, (UINT)pos - sum); - IAudioCaptureClient_ReleaseBuffer(acc, frames); - } - - IAudioCaptureClient_Release(acc); -} - -static void test_audioclient(void) -{ - IAudioClient *ac; - IUnknown *unk; - HRESULT hr; - ULONG ref; - WAVEFORMATEX *pwfx, *pwfx2; - REFERENCE_TIME t1, t2; - HANDLE handle; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - handle = CreateEventW(NULL, FALSE, FALSE, NULL); - - hr = IAudioClient_QueryInterface(ac, &IID_IUnknown, NULL); - ok(hr == E_POINTER, "QueryInterface(NULL) returned %08lx\n", hr); - - unk = (void*)(LONG_PTR)0x12345678; - hr = IAudioClient_QueryInterface(ac, &IID_NULL, (void**)&unk); - ok(hr == E_NOINTERFACE, "QueryInterface(IID_NULL) returned %08lx\n", hr); - ok(!unk, "QueryInterface(IID_NULL) returned non-null pointer %p\n", unk); - - hr = IAudioClient_QueryInterface(ac, &IID_IUnknown, (void**)&unk); - ok(hr == S_OK, "QueryInterface(IID_IUnknown) returned %08lx\n", hr); - if (unk) - { - ref = IUnknown_Release(unk); - ok(ref == 1, "Released count is %lu\n", ref); - } - - hr = IAudioClient_QueryInterface(ac, &IID_IAudioClient, (void**)&unk); - ok(hr == S_OK, "QueryInterface(IID_IAudioClient) returned %08lx\n", hr); - if (unk) - { - ref = IUnknown_Release(unk); - ok(ref == 1, "Released count is %lu\n", ref); - } - - hr = IAudioClient_GetDevicePeriod(ac, NULL, NULL); - ok(hr == E_POINTER, "Invalid GetDevicePeriod call returns %08lx\n", hr); - - hr = IAudioClient_GetDevicePeriod(ac, &t1, NULL); - ok(hr == S_OK, "Valid GetDevicePeriod call returns %08lx\n", hr); - - hr = IAudioClient_GetDevicePeriod(ac, NULL, &t2); - ok(hr == S_OK, "Valid GetDevicePeriod call returns %08lx\n", hr); - - hr = IAudioClient_GetDevicePeriod(ac, &t1, &t2); - ok(hr == S_OK, "Valid GetDevicePeriod call returns %08lx\n", hr); - trace("Returned periods: %u.%04u ms %u.%04u ms\n", - (UINT)(t1/10000), (UINT)(t1 % 10000), - (UINT)(t2/10000), (UINT)(t2 % 10000)); - - hr = IAudioClient_GetMixFormat(ac, NULL); - ok(hr == E_POINTER, "GetMixFormat returns %08lx\n", hr); - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "Valid GetMixFormat returns %08lx\n", hr); - - if (hr == S_OK) - { - trace("pwfx: %p\n", pwfx); - trace("Tag: %04x\n", pwfx->wFormatTag); - trace("bits: %u\n", pwfx->wBitsPerSample); - trace("chan: %u\n", pwfx->nChannels); - trace("rate: %lu\n", pwfx->nSamplesPerSec); - trace("align: %u\n", pwfx->nBlockAlign); - trace("extra: %u\n", pwfx->cbSize); - ok(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE, "wFormatTag is %x\n", pwfx->wFormatTag); - if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - { - WAVEFORMATEXTENSIBLE *pwfxe = (void*)pwfx; - trace("Res: %u\n", pwfxe->Samples.wReserved); - trace("Mask: %lx\n", pwfxe->dwChannelMask); - trace("Alg: %s\n", - IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)?"PCM": - (IsEqualGUID(&pwfxe->SubFormat, - &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)?"FLOAT":"Other")); - } - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2); - ok(hr == S_OK, "Valid IsFormatSupported(Shared) call returns %08lx\n", hr); - ok(pwfx2 == NULL, "pwfx2 is non-null\n"); - CoTaskMemFree(pwfx2); - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, NULL, NULL); - ok(hr == E_POINTER, "IsFormatSupported(NULL) call returns %08lx\n", hr); - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, NULL); - ok(hr == E_POINTER, "IsFormatSupported(Shared,NULL) call returns %08lx\n", hr); - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, NULL); - ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "IsFormatSupported(Exclusive) call returns %08lx\n", hr); - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, &pwfx2); - ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "IsFormatSupported(Exclusive) call returns %08lx\n", hr); - ok(pwfx2 == NULL, "pwfx2 non-null on exclusive IsFormatSupported\n"); - - hr = IAudioClient_IsFormatSupported(ac, 0xffffffff, pwfx, NULL); - ok(hr == E_INVALIDARG/*w32*/ || - broken(hr == AUDCLNT_E_UNSUPPORTED_FORMAT/*w64 response from exclusive mode driver */), - "IsFormatSupported(0xffffffff) call returns %08lx\n", hr); - } - - test_uninitialized(ac); - - hr = IAudioClient_Initialize(ac, 3, 0, 5000000, 0, pwfx, NULL); - ok(broken(hr == AUDCLNT_E_NOT_INITIALIZED) || /* <= win8 */ - hr == E_INVALIDARG, "Initialize with invalid sharemode returns %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0xffffffff, 5000000, 0, pwfx, NULL); - ok(hr == E_INVALIDARG || hr == AUDCLNT_E_INVALID_STREAM_FLAG, "Initialize with invalid flags returns %08lx\n", hr); - - /* A period != 0 is ignored and the call succeeds. - * Since we can only initialize successfully once, skip those tests. - */ - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, NULL, NULL); - ok(hr == E_POINTER, "Initialize with null format returns %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 4987654, 0, pwfx, NULL); - ok(hr == S_OK, "Valid Initialize returns %08lx\n", hr); - - if (hr != S_OK) - { - skip("Cannot initialize %08lx, remainder of tests is useless\n", hr); - goto cleanup; - } - - hr = IAudioClient_GetStreamLatency(ac, NULL); - ok(hr == E_POINTER, "GetStreamLatency(NULL) call returns %08lx\n", hr); - - hr = IAudioClient_GetStreamLatency(ac, &t1); - ok(hr == S_OK, "Valid GetStreamLatency call returns %08lx\n", hr); - trace("Returned latency: %u.%04u ms\n", - (UINT)(t1/10000), (UINT)(t1 % 10000)); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, pwfx, NULL); - ok(hr == AUDCLNT_E_ALREADY_INITIALIZED, "Calling Initialize twice returns %08lx\n", hr); - - hr = IAudioClient_SetEventHandle(ac, NULL); - ok(hr == E_INVALIDARG, "SetEventHandle(NULL) returns %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == AUDCLNT_E_EVENTHANDLE_NOT_SET || - hr == D3D11_ERROR_4E /* win10 */, "Start before SetEventHandle returns %08lx\n", hr); - - hr = IAudioClient_SetEventHandle(ac, handle); - ok(hr == S_OK, "SetEventHandle returns %08lx\n", hr); - - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset on an already reset stream returns %08lx\n", hr); - - hr = IAudioClient_Stop(ac); - ok(hr == S_FALSE, "Stop on a stopped stream returns %08lx\n", hr); - - test_capture(ac, handle, pwfx); - -cleanup: - IAudioClient_Release(ac); - CloseHandle(handle); - CoTaskMemFree(pwfx); -} - -static void test_streamvolume(void) -{ - IAudioClient *ac; - IAudioStreamVolume *asv; - WAVEFORMATEX *fmt; - UINT32 chans, i; - HRESULT hr; - float vol, *vols; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, - 0, fmt, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetService(ac, &IID_IAudioStreamVolume, (void**)&asv); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelCount(asv, NULL); - ok(hr == E_POINTER, "GetChannelCount gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelCount(asv, &chans); - ok(hr == S_OK, "GetChannelCount failed: %08lx\n", hr); - ok(chans == fmt->nChannels, "GetChannelCount gave wrong number of channels: %d\n", chans); - - hr = IAudioStreamVolume_GetChannelVolume(asv, fmt->nChannels, NULL); - ok(hr == E_POINTER, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, fmt->nChannels, &vol); - ok(hr == E_INVALIDARG, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, 0, NULL); - ok(hr == E_POINTER, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, 0, &vol); - ok(hr == S_OK, "GetChannelVolume failed: %08lx\n", hr); - ok(vol == 1.f, "Channel volume was not 1: %f\n", vol); - - hr = IAudioStreamVolume_SetChannelVolume(asv, fmt->nChannels, -1.f); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetChannelVolume(asv, 0, -1.f); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetChannelVolume(asv, 0, 2.f); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetChannelVolume(asv, 0, 0.2f); - ok(hr == S_OK, "SetChannelVolume failed: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, 0, &vol); - ok(hr == S_OK, "GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "Channel volume wasn't 0.2: %f\n", vol); - - hr = IAudioStreamVolume_GetAllVolumes(asv, 0, NULL); - ok(hr == E_POINTER, "GetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetAllVolumes(asv, fmt->nChannels, NULL); - ok(hr == E_POINTER, "GetAllVolumes gave wrong error: %08lx\n", hr); - - vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float)); - ok(vols != NULL, "HeapAlloc failed\n"); - - hr = IAudioStreamVolume_GetAllVolumes(asv, fmt->nChannels - 1, vols); - ok(hr == E_INVALIDARG, "GetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetAllVolumes(asv, fmt->nChannels, vols); - ok(hr == S_OK, "GetAllVolumes failed: %08lx\n", hr); - ok(fabsf(vols[0] - 0.2f) < 0.05f, "Channel 0 volume wasn't 0.2: %f\n", vol); - for(i = 1; i < fmt->nChannels; ++i) - ok(vols[i] == 1.f, "Channel %d volume is not 1: %f\n", i, vols[i]); - - hr = IAudioStreamVolume_SetAllVolumes(asv, 0, NULL); - ok(hr == E_POINTER, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetAllVolumes(asv, fmt->nChannels, NULL); - ok(hr == E_POINTER, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetAllVolumes(asv, fmt->nChannels - 1, vols); - ok(hr == E_INVALIDARG, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetAllVolumes(asv, fmt->nChannels, vols); - ok(hr == S_OK, "SetAllVolumes failed: %08lx\n", hr); - - HeapFree(GetProcessHeap(), 0, vols); - IAudioStreamVolume_Release(asv); - IAudioClient_Release(ac); - CoTaskMemFree(fmt); -} - -static void test_channelvolume(void) -{ - IAudioClient *ac; - IChannelAudioVolume *acv; - WAVEFORMATEX *fmt; - UINT32 chans, i; - HRESULT hr; - float vol, *vols; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_IChannelAudioVolume, (void**)&acv); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IChannelAudioVolume_GetChannelCount(acv, NULL); - ok(hr == NULL_PTR_ERR, "GetChannelCount gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelCount(acv, &chans); - ok(hr == S_OK, "GetChannelCount failed: %08lx\n", hr); - ok(chans == fmt->nChannels, "GetChannelCount gave wrong number of channels: %d\n", chans); - - hr = IChannelAudioVolume_GetChannelVolume(acv, fmt->nChannels, NULL); - ok(hr == NULL_PTR_ERR, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(acv, fmt->nChannels, &vol); - ok(hr == E_INVALIDARG, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(acv, 0, NULL); - ok(hr == NULL_PTR_ERR, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(acv, 0, &vol); - ok(hr == S_OK, "GetChannelVolume failed: %08lx\n", hr); - ok(vol == 1.f, "Channel volume was not 1: %f\n", vol); - - hr = IChannelAudioVolume_SetChannelVolume(acv, fmt->nChannels, -1.f, NULL); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(acv, 0, -1.f, NULL); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(acv, 0, 2.f, NULL); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(acv, 0, 0.2f, NULL); - ok(hr == S_OK, "SetChannelVolume failed: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(acv, 0, &vol); - ok(hr == S_OK, "GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "Channel volume wasn't 0.2: %f\n", vol); - - hr = IChannelAudioVolume_GetAllVolumes(acv, 0, NULL); - ok(hr == NULL_PTR_ERR, "GetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetAllVolumes(acv, fmt->nChannels, NULL); - ok(hr == NULL_PTR_ERR, "GetAllVolumes gave wrong error: %08lx\n", hr); - - vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float)); - ok(vols != NULL, "HeapAlloc failed\n"); - - hr = IChannelAudioVolume_GetAllVolumes(acv, fmt->nChannels - 1, vols); - ok(hr == E_INVALIDARG, "GetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetAllVolumes(acv, fmt->nChannels, vols); - ok(hr == S_OK, "GetAllVolumes failed: %08lx\n", hr); - ok(fabsf(vols[0] - 0.2f) < 0.05f, "Channel 0 volume wasn't 0.2: %f\n", vol); - for(i = 1; i < fmt->nChannels; ++i) - ok(vols[i] == 1.f, "Channel %d volume is not 1: %f\n", i, vols[i]); - - hr = IChannelAudioVolume_SetAllVolumes(acv, 0, NULL, NULL); - ok(hr == NULL_PTR_ERR, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetAllVolumes(acv, fmt->nChannels, NULL, NULL); - ok(hr == NULL_PTR_ERR, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetAllVolumes(acv, fmt->nChannels - 1, vols, NULL); - ok(hr == E_INVALIDARG, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetAllVolumes(acv, fmt->nChannels, vols, NULL); - ok(hr == S_OK, "SetAllVolumes failed: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(acv, 0, 1.0f, NULL); - ok(hr == S_OK, "SetChannelVolume failed: %08lx\n", hr); - - HeapFree(GetProcessHeap(), 0, vols); - IChannelAudioVolume_Release(acv); - IAudioClient_Release(ac); - CoTaskMemFree(fmt); -} - -static void test_simplevolume(void) -{ - IAudioClient *ac; - ISimpleAudioVolume *sav; - WAVEFORMATEX *fmt; - HRESULT hr; - float vol; - BOOL mute; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_ISimpleAudioVolume, (void**)&sav); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - if(hr != S_OK) - return; - - hr = ISimpleAudioVolume_GetMasterVolume(sav, NULL); - ok(hr == NULL_PTR_ERR, "GetMasterVolume gave wrong error: %08lx\n", hr); - - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, -1.f, NULL); - ok(hr == E_INVALIDARG, "SetMasterVolume gave wrong error: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 2.f, NULL); - ok(hr == E_INVALIDARG, "SetMasterVolume gave wrong error: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 0.2f, NULL); - ok(hr == S_OK, "SetMasterVolume failed: %08lx\n", hr); - - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "Master volume wasn't 0.2: %f\n", vol); - - hr = ISimpleAudioVolume_GetMute(sav, NULL); - ok(hr == NULL_PTR_ERR, "GetMute gave wrong error: %08lx\n", hr); - - mute = TRUE; - hr = ISimpleAudioVolume_GetMute(sav, &mute); - ok(hr == S_OK, "GetMute failed: %08lx\n", hr); - ok(mute == FALSE, "Session is already muted\n"); - - hr = ISimpleAudioVolume_SetMute(sav, TRUE, NULL); - ok(hr == S_OK, "SetMute failed: %08lx\n", hr); - - mute = FALSE; - hr = ISimpleAudioVolume_GetMute(sav, &mute); - ok(hr == S_OK, "GetMute failed: %08lx\n", hr); - ok(mute == TRUE, "Session should have been muted\n"); - - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "Master volume wasn't 0.2: %f\n", vol); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 1.f, NULL); - ok(hr == S_OK, "SetMasterVolume failed: %08lx\n", hr); - - mute = FALSE; - hr = ISimpleAudioVolume_GetMute(sav, &mute); - ok(hr == S_OK, "GetMute failed: %08lx\n", hr); - ok(mute == TRUE, "Session should have been muted\n"); - - hr = ISimpleAudioVolume_SetMute(sav, FALSE, NULL); - ok(hr == S_OK, "SetMute failed: %08lx\n", hr); - - ISimpleAudioVolume_Release(sav); - IAudioClient_Release(ac); - CoTaskMemFree(fmt); -} - -static void test_volume_dependence(void) -{ - IAudioClient *ac, *ac2; - ISimpleAudioVolume *sav; - IChannelAudioVolume *cav; - IAudioStreamVolume *asv; - WAVEFORMATEX *fmt; - HRESULT hr; - float vol; - GUID session; - UINT32 nch; - - hr = CoCreateGuid(&session); - ok(hr == S_OK, "CoCreateGuid failed: %08lx\n", hr); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, &session); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_ISimpleAudioVolume, (void**)&sav); - ok(hr == S_OK, "GetService (SimpleAudioVolume) failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_IChannelAudioVolume, (void**)&cav); - ok(hr == S_OK, "GetService (ChannelAudioVolume) failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_IAudioStreamVolume, (void**)&asv); - ok(hr == S_OK, "GetService (AudioStreamVolume) failed: %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioStreamVolume_SetChannelVolume(asv, 0, 0.2f); - ok(hr == S_OK, "ASV_SetChannelVolume failed: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(cav, 0, 0.4f, NULL); - ok(hr == S_OK, "CAV_SetChannelVolume failed: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 0.6f, NULL); - ok(hr == S_OK, "SAV_SetMasterVolume failed: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, 0, &vol); - ok(hr == S_OK, "ASV_GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "ASV_GetChannelVolume gave wrong volume: %f\n", vol); - - hr = IChannelAudioVolume_GetChannelVolume(cav, 0, &vol); - ok(hr == S_OK, "CAV_GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.4f) < 0.05f, "CAV_GetChannelVolume gave wrong volume: %f\n", vol); - - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "SAV_GetMasterVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.6f) < 0.05f, "SAV_GetMasterVolume gave wrong volume: %f\n", vol); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac2); - if(SUCCEEDED(hr)){ - IChannelAudioVolume *cav2; - IAudioStreamVolume *asv2; - - hr = IAudioClient_Initialize(ac2, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, &session); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac2, &IID_IChannelAudioVolume, (void**)&cav2); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac2, &IID_IAudioStreamVolume, (void**)&asv2); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(cav2, 0, &vol); - ok(hr == S_OK, "CAV_GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.4f) < 0.05f, "CAV_GetChannelVolume gave wrong volume: %f\n", vol); - - hr = IAudioStreamVolume_GetChannelVolume(asv2, 0, &vol); - ok(hr == S_OK, "ASV_GetChannelVolume failed: %08lx\n", hr); - ok(vol == 1.f, "ASV_GetChannelVolume gave wrong volume: %f\n", vol); - - hr = IChannelAudioVolume_GetChannelCount(cav2, &nch); - ok(hr == S_OK, "CAV_GetChannelCount failed: %08lx\n", hr); - ok(nch == fmt->nChannels, "Got wrong channel count, expected %u: %u\n", fmt->nChannels, nch); - - hr = IAudioStreamVolume_GetChannelCount(asv2, &nch); - ok(hr == S_OK, "ASV_GetChannelCount failed: %08lx\n", hr); - ok(nch == fmt->nChannels, "Got wrong channel count, expected %u: %u\n", fmt->nChannels, nch); - - IAudioStreamVolume_Release(asv2); - IChannelAudioVolume_Release(cav2); - IAudioClient_Release(ac2); - }else - skip("Unable to open the same device twice. Skipping session volume control tests\n"); - - hr = IChannelAudioVolume_SetChannelVolume(cav, 0, 1.f, NULL); - ok(hr == S_OK, "CAV_SetChannelVolume failed: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 1.f, NULL); - ok(hr == S_OK, "SAV_SetMasterVolume failed: %08lx\n", hr); - - CoTaskMemFree(fmt); - ISimpleAudioVolume_Release(sav); - IChannelAudioVolume_Release(cav); - IAudioStreamVolume_Release(asv); - IAudioClient_Release(ac); -} - -static void test_marshal(void) -{ - IStream *pStream; - IAudioClient *ac, *acDest; - IAudioCaptureClient *cc, *ccDest; - WAVEFORMATEX *pwfx; - HRESULT hr; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, - 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - CoTaskMemFree(pwfx); - - hr = IAudioClient_GetService(ac, &IID_IAudioCaptureClient, (void**)&cc); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - if(hr != S_OK) { - IAudioClient_Release(ac); - return; - } - - hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); - ok(hr == S_OK, "CreateStreamOnHGlobal failed 0x%08lx\n", hr); - - /* marshal IAudioClient */ - - hr = CoMarshalInterface(pStream, &IID_IAudioClient, (IUnknown*)ac, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); - ok(hr == S_OK, "CoMarshalInterface IAudioClient failed 0x%08lx\n", hr); - - IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - hr = CoUnmarshalInterface(pStream, &IID_IAudioClient, (void **)&acDest); - ok(hr == S_OK, "CoUnmarshalInterface IAudioClient failed 0x%08lx\n", hr); - if (hr == S_OK) - IAudioClient_Release(acDest); - - IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - /* marshal IAudioCaptureClient */ - - hr = CoMarshalInterface(pStream, &IID_IAudioCaptureClient, (IUnknown*)cc, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); - ok(hr == S_OK, "CoMarshalInterface IAudioCaptureClient failed 0x%08lx\n", hr); - - IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - hr = CoUnmarshalInterface(pStream, &IID_IAudioCaptureClient, (void **)&ccDest); - ok(hr == S_OK, "CoUnmarshalInterface IAudioCaptureClient failed 0x%08lx\n", hr); - if (hr == S_OK) - IAudioCaptureClient_Release(ccDest); - - IStream_Release(pStream); - - IAudioClient_Release(ac); - IAudioCaptureClient_Release(cc); - -} - -START_TEST(capture) -{ - HRESULT hr; - IMMDeviceEnumerator *mme = NULL; - - CoInitializeEx(NULL, COINIT_MULTITHREADED); - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); - if (FAILED(hr)) - { - skip("mmdevapi not available: 0x%08lx\n", hr); - goto cleanup; - } - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eCapture, eMultimedia, &dev); - ok(hr == S_OK || hr == E_NOTFOUND, "GetDefaultAudioEndpoint failed: 0x%08lx\n", hr); - if (hr != S_OK || !dev) - { - if (hr == E_NOTFOUND) - skip("No sound card available\n"); - else - skip("GetDefaultAudioEndpoint returns 0x%08lx\n", hr); - goto cleanup; - } - - test_audioclient(); - test_streamvolume(); - test_channelvolume(); - test_simplevolume(); - test_volume_dependence(); - test_marshal(); - - IMMDevice_Release(dev); - -cleanup: - if (mme) - IMMDeviceEnumerator_Release(mme); - CoUninitialize(); -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/tests/dependency.c b/pkgs/osu-wine/audio-revert/mmdevapi/tests/dependency.c deleted file mode 100644 index ef99d7b..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/tests/dependency.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2009 Maarten Lankhorst - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/test.h" - -#define COBJMACROS - -#ifdef STANDALONE -#include "initguid.h" -#endif - -#include "unknwn.h" -#include "uuids.h" -#include "mmdeviceapi.h" -#include "dshow.h" -#include "dsound.h" - -START_TEST(dependency) -{ - HRESULT hr; - IMMDeviceEnumerator *mme = NULL; - IMMDevice *dev = NULL; - IDirectSound8 *ds8 = NULL; - IBaseFilter *bf = NULL; - - CoInitializeEx(NULL, COINIT_MULTITHREADED); - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); - if (FAILED(hr)) - { - skip("mmdevapi not available: 0x%08lx\n", hr); - goto cleanup; - } - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eRender, eMultimedia, &dev); - ok(hr == S_OK || hr == E_NOTFOUND, "GetDefaultAudioEndpoint failed: 0x%08lx\n", hr); - if (hr != S_OK) - { - if (hr == E_NOTFOUND) - skip("No sound card available\n"); - else - skip("GetDefaultAudioEndpoint returns 0x%08lx\n", hr); - goto cleanup; - } - - ok(!GetModuleHandleA("dsound.dll"), "dsound.dll was already loaded!\n"); - - hr = IMMDevice_Activate(dev, &IID_IDirectSound8, CLSCTX_INPROC_SERVER, NULL, (void**)&ds8); - ok(hr == S_OK, "Activating ds8 interface failed: 0x%08lx\n", hr); - if (hr == S_OK) - { - ok(GetModuleHandleA("dsound.dll") != NULL, "dsound.dll not loaded!\n"); - ok(ds8 != NULL, "ds8 pointer is null\n"); - } - if (ds8) - IDirectSound8_Release(ds8); - - ok(!GetModuleHandleA("quartz.dll"), "quartz.dll was already loaded!\n"); - hr = IMMDevice_Activate(dev, &IID_IBaseFilter, CLSCTX_INPROC_SERVER, NULL, (void**)&bf); - ok(hr == S_OK, "Activating bf failed: 0x%08lx\n", hr); - if (hr == S_OK) - { - ok(GetModuleHandleA("quartz.dll") != NULL, "quartz.dll not loaded!\n"); - ok(bf != NULL, "bf pointer is null\n"); - if (bf) - { - CLSID clsid; - hr = IBaseFilter_GetClassID(bf, &clsid); - ok(hr == S_OK, "GetClassId failed with 0x%08lx\n", hr); - if (hr == S_OK) - ok(IsEqualCLSID(&clsid, &CLSID_DSoundRender), "Wrong class id %s\n", wine_dbgstr_guid(&clsid)); - } - } - -cleanup: - if (bf) - IBaseFilter_Release(bf); - if (dev) - IMMDevice_Release(dev); - if (mme) - IMMDeviceEnumerator_Release(mme); - - CoUninitialize(); -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/tests/mmdevenum.c b/pkgs/osu-wine/audio-revert/mmdevapi/tests/mmdevenum.c deleted file mode 100644 index a5b692a..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/tests/mmdevenum.c +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright 2009 Maarten Lankhorst - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "wine/test.h" - -#define COBJMACROS - -#include "initguid.h" -#include "endpointvolume.h" -#include "mmdeviceapi.h" -#include "audioclient.h" -#include "spatialaudioclient.h" -#include "audiopolicy.h" -#include "dshow.h" -#include "dsound.h" -#include "devpkey.h" - -DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); - -static UINT g_num_mmdevs; -static WCHAR g_device_path[MAX_PATH]; - -/* Some of the QueryInterface tests are really just to check if I got the IIDs right :) */ - -/* IMMDeviceCollection appears to have no QueryInterface method and instead forwards to mme */ -static void test_collection(IMMDeviceEnumerator *mme, IMMDeviceCollection *col) -{ - IMMDeviceCollection *col2; - IMMDeviceEnumerator *mme2; - IUnknown *unk; - HRESULT hr; - ULONG ref; - UINT numdev; - IMMDevice *dev; - - /* collection doesn't keep a ref on parent */ - IMMDeviceEnumerator_AddRef(mme); - ref = IMMDeviceEnumerator_Release(mme); - ok(ref == 2, "Reference count on parent is %lu\n", ref); - - ref = IMMDeviceCollection_AddRef(col); - IMMDeviceCollection_Release(col); - ok(ref == 2, "Invalid reference count %lu on collection\n", ref); - - hr = IMMDeviceCollection_QueryInterface(col, &IID_IUnknown, NULL); - ok(hr == E_POINTER, "Null ppv returns %08lx\n", hr); - - hr = IMMDeviceCollection_QueryInterface(col, &IID_IUnknown, (void**)&unk); - ok(hr == S_OK, "Cannot query for IID_IUnknown: 0x%08lx\n", hr); - if (hr == S_OK) - { - ok((IUnknown*)col == unk, "Pointers are not identical %p/%p/%p\n", col, unk, mme); - IUnknown_Release(unk); - } - - hr = IMMDeviceCollection_QueryInterface(col, &IID_IMMDeviceCollection, (void**)&col2); - ok(hr == S_OK, "Cannot query for IID_IMMDeviceCollection: 0x%08lx\n", hr); - if (hr == S_OK) - IMMDeviceCollection_Release(col2); - - hr = IMMDeviceCollection_QueryInterface(col, &IID_IMMDeviceEnumerator, (void**)&mme2); - ok(hr == E_NOINTERFACE, "Query for IID_IMMDeviceEnumerator returned: 0x%08lx\n", hr); - if (hr == S_OK) - IMMDeviceEnumerator_Release(mme2); - - hr = IMMDeviceCollection_GetCount(col, NULL); - ok(hr == E_POINTER, "GetCount returned 0x%08lx\n", hr); - - hr = IMMDeviceCollection_GetCount(col, &numdev); - ok(hr == S_OK, "GetCount returned 0x%08lx\n", hr); - - dev = (void*)(LONG_PTR)0x12345678; - hr = IMMDeviceCollection_Item(col, numdev, &dev); - ok(hr == E_INVALIDARG, "Asking for too high device returned 0x%08lx\n", hr); - ok(dev == NULL, "Returned non-null device\n"); - - g_num_mmdevs = numdev; - - if (numdev) - { - hr = IMMDeviceCollection_Item(col, 0, NULL); - ok(hr == E_POINTER, "Query with null pointer returned 0x%08lx\n", hr); - - hr = IMMDeviceCollection_Item(col, 0, &dev); - ok(hr == S_OK, "Valid Item returned 0x%08lx\n", hr); - ok(dev != NULL, "Device is null!\n"); - if (dev != NULL) - { - char temp[128]; - WCHAR *id = NULL; - if (IMMDevice_GetId(dev, &id) == S_OK) - { - IMMDevice *dev2; - - lstrcpyW(g_device_path, id); - temp[sizeof(temp)-1] = 0; - WideCharToMultiByte(CP_ACP, 0, id, -1, temp, sizeof(temp)-1, NULL, NULL); - trace("Device found: %s\n", temp); - - hr = IMMDeviceEnumerator_GetDevice(mme, id, &dev2); - ok(hr == S_OK, "GetDevice failed: %08lx\n", hr); - - IMMDevice_Release(dev2); - - CoTaskMemFree(id); - } - } - if (dev) - IMMDevice_Release(dev); - } - IMMDeviceCollection_Release(col); -} - -static struct { - LONG ref; - HANDLE evt; - CRITICAL_SECTION lock; - IActivateAudioInterfaceAsyncOperation *op; - DWORD main_tid; - char msg_pfx[128]; - IUnknown *result_iface; - HRESULT result_hr; -} async_activate_test; - -static HRESULT WINAPI async_activate_QueryInterface( - IActivateAudioInterfaceCompletionHandler *iface, - REFIID riid, - void **ppvObject) -{ - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAgileObject) || - IsEqualIID(riid, &IID_IActivateAudioInterfaceCompletionHandler)){ - *ppvObject = iface; - IUnknown_AddRef((IUnknown*)*ppvObject); - return S_OK; - } - - *ppvObject = NULL; - return E_NOINTERFACE; -} - -static ULONG WINAPI async_activate_AddRef( - IActivateAudioInterfaceCompletionHandler *iface) -{ - return InterlockedIncrement(&async_activate_test.ref); -} - -static ULONG WINAPI async_activate_Release( - IActivateAudioInterfaceCompletionHandler *iface) -{ - ULONG ref = InterlockedDecrement(&async_activate_test.ref); - if(ref == 1) - SetEvent(async_activate_test.evt); - return ref; -} - -static HRESULT WINAPI async_activate_ActivateCompleted( - IActivateAudioInterfaceCompletionHandler *iface, - IActivateAudioInterfaceAsyncOperation *op) -{ - HRESULT hr; - - EnterCriticalSection(&async_activate_test.lock); - ok(op == async_activate_test.op, - "%s: Got different completion operation\n", - async_activate_test.msg_pfx); - LeaveCriticalSection(&async_activate_test.lock); - - ok(GetCurrentThreadId() != async_activate_test.main_tid, - "%s: Expected callback on worker thread\n", - async_activate_test.msg_pfx); - - hr = IActivateAudioInterfaceAsyncOperation_GetActivateResult(op, - &async_activate_test.result_hr, &async_activate_test.result_iface); - ok(hr == S_OK, - "%s: GetActivateResult failed: %08lx\n", - async_activate_test.msg_pfx, hr); - - return S_OK; -} - -static IActivateAudioInterfaceCompletionHandlerVtbl async_activate_vtbl = { - async_activate_QueryInterface, - async_activate_AddRef, - async_activate_Release, - async_activate_ActivateCompleted, -}; - -static IActivateAudioInterfaceCompletionHandler async_activate_done = { - &async_activate_vtbl -}; - -static void test_ActivateAudioInterfaceAsync(void) -{ - HRESULT (* WINAPI pActivateAudioInterfaceAsync)(const WCHAR *path, - REFIID riid, PROPVARIANT *params, - IActivateAudioInterfaceCompletionHandler *done_handler, - IActivateAudioInterfaceAsyncOperation **op); - HANDLE h_mmdev; - HRESULT hr; - LPOLESTR path; - DWORD dr; - IAudioClient3 *ac3; - - h_mmdev = LoadLibraryA("mmdevapi.dll"); - - pActivateAudioInterfaceAsync = (void*)GetProcAddress(h_mmdev, "ActivateAudioInterfaceAsync"); - if (!pActivateAudioInterfaceAsync) - { - win_skip("ActivateAudioInterfaceAsync is not supported on Win <= 7\n"); - return; - } - - /* some applications look this up by ordinal */ - pActivateAudioInterfaceAsync = (void*)GetProcAddress(h_mmdev, (char *)17); - ok(pActivateAudioInterfaceAsync != NULL, "mmdevapi.ActivateAudioInterfaceAsync missing!\n"); - - async_activate_test.ref = 1; - async_activate_test.evt = CreateEventW(NULL, FALSE, FALSE, NULL); - InitializeCriticalSection(&async_activate_test.lock); - async_activate_test.op = NULL; - async_activate_test.main_tid = GetCurrentThreadId(); - async_activate_test.result_iface = NULL; - async_activate_test.result_hr = 0; - - - /* try invalid device path */ - strcpy(async_activate_test.msg_pfx, "invalid_path"); - - EnterCriticalSection(&async_activate_test.lock); - hr = pActivateAudioInterfaceAsync(L"winetest_bogus", &IID_IAudioClient3, NULL, &async_activate_done, &async_activate_test.op); - ok(hr == S_OK, "ActivateAudioInterfaceAsync failed: %08lx\n", hr); - LeaveCriticalSection(&async_activate_test.lock); - - IActivateAudioInterfaceAsyncOperation_Release(async_activate_test.op); - - dr = WaitForSingleObject(async_activate_test.evt, 1000); /* wait for all refs other than our own to be released */ - ok(dr == WAIT_OBJECT_0, "Timed out waiting for async activate to complete\n"); - ok(async_activate_test.ref == 1, "ActivateAudioInterfaceAsync leaked a handler ref: %lu\n", async_activate_test.ref); - ok(async_activate_test.result_hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - "mmdevice activation gave wrong result: %08lx\n", async_activate_test.result_hr); - ok(async_activate_test.result_iface == NULL, "Got non-NULL iface pointer: %p\n", async_activate_test.result_iface); - - - /* device id from IMMDevice does not work */ - if(g_num_mmdevs > 0){ - strcpy(async_activate_test.msg_pfx, "mmdevice_id"); - - EnterCriticalSection(&async_activate_test.lock); - hr = pActivateAudioInterfaceAsync(g_device_path, &IID_IAudioClient3, NULL, &async_activate_done, &async_activate_test.op); - ok(hr == S_OK, "ActivateAudioInterfaceAsync failed: %08lx\n", hr); - LeaveCriticalSection(&async_activate_test.lock); - - IActivateAudioInterfaceAsyncOperation_Release(async_activate_test.op); - - dr = WaitForSingleObject(async_activate_test.evt, 1000); - ok(dr == WAIT_OBJECT_0, "Timed out waiting for async activate to complete\n"); - ok(async_activate_test.ref == 1, "ActivateAudioInterfaceAsync leaked a handler ref: %lu\n", async_activate_test.ref); - ok(async_activate_test.result_hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - "mmdevice activation gave wrong result: %08lx\n", async_activate_test.result_hr); - ok(async_activate_test.result_iface == NULL, "Got non-NULL iface pointer: %p\n", async_activate_test.result_iface); - } - - - /* try DEVINTERFACE_AUDIO_RENDER */ - strcpy(async_activate_test.msg_pfx, "audio_render"); - StringFromIID(&DEVINTERFACE_AUDIO_RENDER, &path); - - EnterCriticalSection(&async_activate_test.lock); - hr = pActivateAudioInterfaceAsync(path, &IID_IAudioClient3, NULL, &async_activate_done, &async_activate_test.op); - ok(hr == S_OK, "ActivateAudioInterfaceAsync failed: %08lx\n", hr); - LeaveCriticalSection(&async_activate_test.lock); - - IActivateAudioInterfaceAsyncOperation_Release(async_activate_test.op); - - dr = WaitForSingleObject(async_activate_test.evt, 1000); - ok(dr == WAIT_OBJECT_0, "Timed out waiting for async activate to complete\n"); - ok(async_activate_test.ref == 1, "ActivateAudioInterfaceAsync leaked a handler ref\n"); - ok(async_activate_test.result_hr == S_OK || - (g_num_mmdevs == 0 && async_activate_test.result_hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || /* no devices */ - broken(async_activate_test.result_hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)), /* win8 doesn't support DEVINTERFACE_AUDIO_RENDER */ - "mmdevice activation gave wrong result: %08lx\n", async_activate_test.result_hr); - - if(async_activate_test.result_hr == S_OK){ - ok(async_activate_test.result_iface != NULL, "Got NULL iface pointer on success?\n"); - - /* returned iface should be the IID we requested */ - hr = IUnknown_QueryInterface(async_activate_test.result_iface, &IID_IAudioClient3, (void**)&ac3); - ok(hr == S_OK, "Failed to query IAudioClient3: %08lx\n", hr); - ok(async_activate_test.result_iface == (IUnknown*)ac3, - "Activated interface other than IAudioClient3!\n"); - IAudioClient3_Release(ac3); - - IUnknown_Release(async_activate_test.result_iface); - } - - CoTaskMemFree(path); - - CloseHandle(async_activate_test.evt); - DeleteCriticalSection(&async_activate_test.lock); -} - -static HRESULT WINAPI notif_QueryInterface(IMMNotificationClient *iface, - const GUID *riid, void **obj) -{ - ok(0, "Unexpected QueryInterface call\n"); - return E_NOTIMPL; -} - -static ULONG WINAPI notif_AddRef(IMMNotificationClient *iface) -{ - ok(0, "Unexpected AddRef call\n"); - return 2; -} - -static ULONG WINAPI notif_Release(IMMNotificationClient *iface) -{ - ok(0, "Unexpected Release call\n"); - return 1; -} - -static HRESULT WINAPI notif_OnDeviceStateChanged(IMMNotificationClient *iface, - const WCHAR *device_id, DWORD new_state) -{ - ok(0, "Unexpected OnDeviceStateChanged call\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI notif_OnDeviceAdded(IMMNotificationClient *iface, - const WCHAR *device_id) -{ - ok(0, "Unexpected OnDeviceAdded call\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI notif_OnDeviceRemoved(IMMNotificationClient *iface, - const WCHAR *device_id) -{ - ok(0, "Unexpected OnDeviceRemoved call\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI notif_OnDefaultDeviceChanged(IMMNotificationClient *iface, - EDataFlow flow, ERole role, const WCHAR *device_id) -{ - ok(0, "Unexpected OnDefaultDeviceChanged call\n"); - return E_NOTIMPL; -} - -static HRESULT WINAPI notif_OnPropertyValueChanged(IMMNotificationClient *iface, - const WCHAR *device_id, const PROPERTYKEY key) -{ - ok(0, "Unexpected OnPropertyValueChanged call\n"); - return E_NOTIMPL; -} - -static IMMNotificationClientVtbl notif_vtbl = { - notif_QueryInterface, - notif_AddRef, - notif_Release, - notif_OnDeviceStateChanged, - notif_OnDeviceAdded, - notif_OnDeviceRemoved, - notif_OnDefaultDeviceChanged, - notif_OnPropertyValueChanged -}; - -static IMMNotificationClient notif = { ¬if_vtbl }; - -/* Only do parameter tests here, the actual MMDevice testing should be a separate test */ -START_TEST(mmdevenum) -{ - HRESULT hr; - IUnknown *unk = NULL; - IMMDeviceEnumerator *mme, *mme2; - ULONG ref; - IMMDeviceCollection *col; - IMMDevice *dev; - - CoInitializeEx(NULL, COINIT_MULTITHREADED); - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); - if (FAILED(hr)) - { - skip("mmdevapi not available: 0x%08lx\n", hr); - return; - } - - /* Odd behavior.. bug? */ - ref = IMMDeviceEnumerator_AddRef(mme); - ok(ref == 3, "Invalid reference count after incrementing: %lu\n", ref); - IMMDeviceEnumerator_Release(mme); - - hr = IMMDeviceEnumerator_QueryInterface(mme, &IID_IUnknown, (void**)&unk); - ok(hr == S_OK, "returned 0x%08lx\n", hr); - if (hr != S_OK) return; - - ok( (LONG_PTR)mme == (LONG_PTR)unk, "Pointers are unequal %p/%p\n", unk, mme); - IUnknown_Release(unk); - - /* Proving that it is static.. */ - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme2); - ok(hr == S_OK, "CoCreateInstance failed: 0x%08lx\n", hr); - IMMDeviceEnumerator_Release(mme2); - ok(mme == mme2, "Pointers are not equal!\n"); - - hr = IMMDeviceEnumerator_QueryInterface(mme, &IID_IUnknown, NULL); - ok(hr == E_POINTER, "Null pointer on QueryInterface returned %08lx\n", hr); - - hr = IMMDeviceEnumerator_QueryInterface(mme, &GUID_NULL, (void**)&unk); - ok(!unk, "Unk not reset to null after invalid QI\n"); - ok(hr == E_NOINTERFACE, "Invalid hr %08lx returned on IID_NULL\n", hr); - - hr = IMMDeviceEnumerator_GetDevice(mme, L"notadevice", NULL); - ok(hr == E_POINTER, "GetDevice gave wrong error: %08lx\n", hr); - - hr = IMMDeviceEnumerator_GetDevice(mme, NULL, &dev); - ok(hr == E_POINTER, "GetDevice gave wrong error: %08lx\n", hr); - - hr = IMMDeviceEnumerator_GetDevice(mme, L"notadevice", &dev); - ok(hr == E_INVALIDARG, "GetDevice gave wrong error: %08lx\n", hr); - - col = (void*)(LONG_PTR)0x12345678; - hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, 0xffff, DEVICE_STATEMASK_ALL, &col); - ok(hr == E_INVALIDARG, "Setting invalid data flow returned 0x%08lx\n", hr); - ok(col == NULL, "Collection pointer non-null on failure\n"); - - hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, eAll, DEVICE_STATEMASK_ALL+1, &col); - ok(hr == E_INVALIDARG, "Setting invalid mask returned 0x%08lx\n", hr); - - hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, eAll, DEVICE_STATEMASK_ALL, NULL); - ok(hr == E_POINTER, "Invalid pointer returned: 0x%08lx\n", hr); - - hr = IMMDeviceEnumerator_EnumAudioEndpoints(mme, eAll, DEVICE_STATEMASK_ALL, &col); - ok(hr == S_OK, "Valid EnumAudioEndpoints returned 0x%08lx\n", hr); - if (hr == S_OK) - { - ok(!!col, "Returned null pointer\n"); - if (col) - test_collection(mme, col); - } - - hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, NULL); - ok(hr == E_POINTER, "RegisterEndpointNotificationCallback failed: %08lx\n", hr); - - hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, ¬if); - ok(hr == S_OK, "RegisterEndpointNotificationCallback failed: %08lx\n", hr); - - hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(mme, ¬if); - ok(hr == S_OK, "RegisterEndpointNotificationCallback failed: %08lx\n", hr); - - hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, NULL); - ok(hr == E_POINTER, "UnregisterEndpointNotificationCallback failed: %08lx\n", hr); - - hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, (IMMNotificationClient*)0xdeadbeef); - ok(hr == E_NOTFOUND, "UnregisterEndpointNotificationCallback failed: %08lx\n", hr); - - hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); - ok(hr == S_OK, "UnregisterEndpointNotificationCallback failed: %08lx\n", hr); - - hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); - ok(hr == S_OK, "UnregisterEndpointNotificationCallback failed: %08lx\n", hr); - - hr = IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(mme, ¬if); - ok(hr == E_NOTFOUND, "UnregisterEndpointNotificationCallback failed: %08lx\n", hr); - - IMMDeviceEnumerator_Release(mme); - - test_ActivateAudioInterfaceAsync(); -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/tests/propstore.c b/pkgs/osu-wine/audio-revert/mmdevapi/tests/propstore.c deleted file mode 100644 index 89eaada..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/tests/propstore.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2010 Maarten Lankhorst for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define NONAMELESSUNION -#include "wine/test.h" - -#define COBJMACROS - -#ifdef STANDALONE -#include "initguid.h" -#endif - -#include "unknwn.h" -#include "uuids.h" -#include "mmdeviceapi.h" -#include "devpkey.h" - -static BOOL (WINAPI *pIsWow64Process)(HANDLE, BOOL *); - -static const WCHAR software_renderW[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio\\Render"; - - -static void test_propertystore(IPropertyStore *store) -{ - HRESULT hr; - PROPVARIANT pv; - char temp[128]; - temp[sizeof(temp)-1] = 0; - - pv.vt = VT_EMPTY; - hr = IPropertyStore_GetValue(store, &PKEY_AudioEndpoint_GUID, &pv); - ok(hr == S_OK, "Failed with %08lx\n", hr); - ok(pv.vt == VT_LPWSTR, "Value should be %i, is %i\n", VT_LPWSTR, pv.vt); - if (hr == S_OK && pv.vt == VT_LPWSTR) - { - WideCharToMultiByte(CP_ACP, 0, pv.pwszVal, -1, temp, sizeof(temp)-1, NULL, NULL); - trace("guid: %s\n", temp); - PropVariantClear(&pv); - } - - pv.vt = VT_EMPTY; - hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_FriendlyName, &pv); - ok(hr == S_OK, "Failed with %08lx\n", hr); - ok(pv.vt == VT_LPWSTR && pv.pwszVal, "FriendlyName value had wrong type: 0x%x or was NULL\n", pv.vt); - PropVariantClear(&pv); - - pv.vt = VT_EMPTY; - hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_Enabled, &pv); - ok(hr == S_OK, "Failed with %08lx\n", hr); - ok(pv.vt == VT_EMPTY, "Key should not be found\n"); - PropVariantClear(&pv); - - pv.vt = VT_EMPTY; - hr = IPropertyStore_GetValue(store, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_ClassGuid, &pv); - ok(hr == S_OK, "Failed with %08lx\n", hr); - ok(pv.vt == VT_EMPTY, "Key should not be found\n"); - PropVariantClear(&pv); -} - -static void test_deviceinterface(IPropertyStore *store) -{ - HRESULT hr; - PROPVARIANT pv; - - static const PROPERTYKEY deviceinterface_key = { - {0x233164c8, 0x1b2c, 0x4c7d, {0xbc, 0x68, 0xb6, 0x71, 0x68, 0x7a, 0x25, 0x67}}, 1 - }; - - pv.vt = VT_EMPTY; - hr = IPropertyStore_GetValue(store, &deviceinterface_key, &pv); - ok(hr == S_OK, "GetValue failed: %08lx\n", hr); - ok(pv.vt == VT_LPWSTR, "Got wrong variant type: 0x%x\n", pv.vt); - trace("device interface: %s\n", wine_dbgstr_w(pv.pwszVal)); - PropVariantClear(&pv); -} - -static void test_getat(IPropertyStore *store) -{ - HRESULT hr; - DWORD propcount; - DWORD prop; - PROPERTYKEY pkey; - BOOL found_name = FALSE; - BOOL found_desc = FALSE; - char temp[128]; - temp[sizeof(temp)-1] = 0; - - hr = IPropertyStore_GetCount(store, &propcount); - - ok(hr == S_OK, "Failed with %08lx\n", hr); - ok(propcount > 0, "Propcount %ld should be greater than zero\n", propcount); - - for (prop = 0; prop < propcount; prop++) { - hr = IPropertyStore_GetAt(store, prop, &pkey); - ok(hr == S_OK, "Failed with %08lx\n", hr); - if (IsEqualPropertyKey(pkey, DEVPKEY_Device_FriendlyName)) - found_name = TRUE; - if (IsEqualPropertyKey(pkey, DEVPKEY_Device_DeviceDesc)) - found_desc = TRUE; - } - ok(found_name || - broken(!found_name) /* vista */, "DEVPKEY_Device_FriendlyName not found\n"); - ok(found_desc, "DEVPKEY_Device_DeviceDesc not found\n"); -} - -static void test_setvalue_on_wow64(IPropertyStore *store) -{ - PROPVARIANT pv; - HRESULT hr; - LONG ret; - WCHAR *guidW; - HKEY root, props, devkey; - DWORD type, regval, size; - - static const PROPERTYKEY PKEY_Bogus = { - {0x1da5d803, 0xd492, 0x4edd, {0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x00}}, 0x7f - }; - static const WCHAR bogusW[] = L"{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F00},127"; - - PropVariantInit(&pv); - - pv.vt = VT_EMPTY; - hr = IPropertyStore_GetValue(store, &PKEY_AudioEndpoint_GUID, &pv); - ok(hr == S_OK, "Failed to get Endpoint GUID: %08lx\n", hr); - - guidW = pv.pwszVal; - - pv.vt = VT_UI4; - pv.ulVal = 0xAB; - - hr = IPropertyStore_SetValue(store, &PKEY_Bogus, &pv); - ok(hr == S_OK || hr == E_ACCESSDENIED, "SetValue failed: %08lx\n", hr); - if (hr != S_OK) - { - win_skip("Missing permission to write to registry\n"); - return; - } - - pv.ulVal = 0x00; - - hr = IPropertyStore_GetValue(store, &PKEY_Bogus, &pv); - ok(hr == S_OK, "GetValue failed: %08lx\n", hr); - ok(pv.ulVal == 0xAB, "Got wrong value: 0x%lx\n", pv.ulVal); - - /* should find the key in 64-bit view */ - ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, software_renderW, 0, KEY_READ|KEY_WOW64_64KEY, &root); - ok(ret == ERROR_SUCCESS, "Couldn't open mmdevices Render key: %lu\n", ret); - - ret = RegOpenKeyExW(root, guidW, 0, KEY_READ|KEY_WOW64_64KEY, &devkey); - ok(ret == ERROR_SUCCESS, "Couldn't open mmdevice guid key: %lu\n", ret); - - ret = RegOpenKeyExW(devkey, L"Properties", 0, KEY_READ|KEY_WOW64_64KEY, &props); - ok(ret == ERROR_SUCCESS, "Couldn't open mmdevice property key: %lu\n", ret); - - /* Note: the registry key exists even without calling IPropStore::Commit */ - size = sizeof(regval); - ret = RegQueryValueExW(props, bogusW, NULL, &type, (LPBYTE)®val, &size); - ok(ret == ERROR_SUCCESS, "Couldn't get bogus propertykey value: %lu\n", ret); - ok(type == REG_DWORD, "Got wrong value type: %lu\n", type); - ok(regval == 0xAB, "Got wrong value: 0x%lx\n", regval); - - RegCloseKey(props); - RegCloseKey(devkey); - RegCloseKey(root); - - CoTaskMemFree(guidW); - - /* should NOT find the key in 32-bit view */ - ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, software_renderW, 0, KEY_READ, &root); - ok(ret == ERROR_FILE_NOT_FOUND, "Wrong error when opening mmdevices Render key: %lu\n", ret); -} - -START_TEST(propstore) -{ - HRESULT hr; - IMMDeviceEnumerator *mme = NULL; - IMMDevice *dev = NULL; - IPropertyStore *store; - BOOL is_wow64 = FALSE; - HMODULE hk32 = GetModuleHandleA("kernel32.dll"); - - pIsWow64Process = (void *)GetProcAddress(hk32, "IsWow64Process"); - - if (pIsWow64Process) - pIsWow64Process(GetCurrentProcess(), &is_wow64); - - CoInitializeEx(NULL, COINIT_MULTITHREADED); - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); - if (FAILED(hr)) - { - skip("mmdevapi not available: 0x%08lx\n", hr); - goto cleanup; - } - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eRender, eMultimedia, &dev); - ok(hr == S_OK || hr == E_NOTFOUND, "GetDefaultAudioEndpoint failed: 0x%08lx\n", hr); - if (hr != S_OK) - { - if (hr == E_NOTFOUND) - skip("No sound card available\n"); - else - skip("GetDefaultAudioEndpoint returns 0x%08lx\n", hr); - goto cleanup; - } - store = NULL; - hr = IMMDevice_OpenPropertyStore(dev, 3, &store); - ok(hr == E_INVALIDARG, "Wrong hr returned: %08lx\n", hr); - if (hr != S_OK) - /* It seems on windows returning with E_INVALIDARG doesn't - * set store to NULL, so just don't set store to non-null - * before calling this function - */ - ok(!store, "Store set to non-NULL on failure: %p/%08lx\n", store, hr); - else if (store) - IPropertyStore_Release(store); - hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, NULL); - ok(hr == E_POINTER, "Wrong hr returned: %08lx\n", hr); - - store = NULL; - hr = IMMDevice_OpenPropertyStore(dev, STGM_READWRITE, &store); - if(hr == E_ACCESSDENIED) - hr = IMMDevice_OpenPropertyStore(dev, STGM_READ, &store); - ok(hr == S_OK, "Opening valid store returned %08lx\n", hr); - if (store) - { - test_propertystore(store); - test_deviceinterface(store); - test_getat(store); - if (is_wow64) - test_setvalue_on_wow64(store); - IPropertyStore_Release(store); - } - IMMDevice_Release(dev); -cleanup: - if (mme) - IMMDeviceEnumerator_Release(mme); - CoUninitialize(); -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/tests/render.c b/pkgs/osu-wine/audio-revert/mmdevapi/tests/render.c deleted file mode 100644 index 8e000f0..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/tests/render.c +++ /dev/null @@ -1,2425 +0,0 @@ -/* - * Copyright 2010 Maarten Lankhorst for CodeWeavers - * 2011-2012 Jörg Höhle - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* This test is for audio playback specific mechanisms - * Tests: - * - IAudioClient with eRender and IAudioRenderClient - */ - -#include -#include - -#include "wine/test.h" - -#define COBJMACROS - -#ifdef STANDALONE -#include "initguid.h" -#endif - -#include "unknwn.h" -#include "uuids.h" -#include "mmdeviceapi.h" -#include "mmsystem.h" -#include "audioclient.h" -#include "audiopolicy.h" -#include "endpointvolume.h" - -static const unsigned int win_formats[][4] = { - { 8000, 8, 1}, { 8000, 8, 2}, { 8000, 16, 1}, { 8000, 16, 2}, - {11025, 8, 1}, {11025, 8, 2}, {11025, 16, 1}, {11025, 16, 2}, - {12000, 8, 1}, {12000, 8, 2}, {12000, 16, 1}, {12000, 16, 2}, - {16000, 8, 1}, {16000, 8, 2}, {16000, 16, 1}, {16000, 16, 2}, - {22050, 8, 1}, {22050, 8, 2}, {22050, 16, 1}, {22050, 16, 2}, - {44100, 8, 1}, {44100, 8, 2}, {44100, 16, 1}, {44100, 16, 2}, - {48000, 8, 1}, {48000, 8, 2}, {48000, 16, 1}, {48000, 16, 2}, - {96000, 8, 1}, {96000, 8, 2}, {96000, 16, 1}, {96000, 16, 2} -}; - -#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) - -/* undocumented error code */ -#define D3D11_ERROR_4E MAKE_HRESULT(SEVERITY_ERROR, FACILITY_DIRECT3D11, 0x4e) - -static IMMDeviceEnumerator *mme = NULL; -static IMMDevice *dev = NULL; -static HRESULT hexcl = S_OK; /* or AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED */ -static BOOL win10 = FALSE; - -static const LARGE_INTEGER ullZero; - -#define PI 3.14159265358979323846L -static DWORD wave_generate_tone(PWAVEFORMATEX pwfx, BYTE* data, UINT32 frames) -{ - static double phase = 0.; /* normalized to unit, not 2*PI */ - PWAVEFORMATEXTENSIBLE wfxe = (PWAVEFORMATEXTENSIBLE)pwfx; - DWORD cn, i; - double delta, y; - - if(!winetest_interactive) - return AUDCLNT_BUFFERFLAGS_SILENT; - if(wfxe->Format.wBitsPerSample != ((wfxe->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&wfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) ? 8 * sizeof(float) : 16)) - return AUDCLNT_BUFFERFLAGS_SILENT; - - for(delta = phase, cn = 0; cn < wfxe->Format.nChannels; - delta += .5/wfxe->Format.nChannels, cn++){ - for(i = 0; i < frames; i++){ - y = sin(2*PI*(440.* i / wfxe->Format.nSamplesPerSec + delta)); - /* assume alignment is granted */ - if(wfxe->Format.wBitsPerSample == 16) - ((short*)data)[cn+i*wfxe->Format.nChannels] = y * 32767.9; - else - ((float*)data)[cn+i*wfxe->Format.nChannels] = y; - } - } - phase += 440.* frames / wfxe->Format.nSamplesPerSec; - phase -= floor(phase); - return 0; -} - -static void test_uninitialized(IAudioClient *ac) -{ - HRESULT hr; - UINT32 num; - REFERENCE_TIME t1; - - HANDLE handle = CreateEventW(NULL, FALSE, FALSE, NULL); - IUnknown *unk; - - hr = IAudioClient_GetBufferSize(ac, &num); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized GetBufferSize call returns %08lx\n", hr); - - hr = IAudioClient_GetStreamLatency(ac, &t1); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized GetStreamLatency call returns %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &num); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized GetCurrentPadding call returns %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized Start call returns %08lx\n", hr); - - hr = IAudioClient_Stop(ac); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized Stop call returns %08lx\n", hr); - - hr = IAudioClient_Reset(ac); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized Reset call returns %08lx\n", hr); - - hr = IAudioClient_SetEventHandle(ac, handle); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized SetEventHandle call returns %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_IAudioStreamVolume, (void**)&unk); - ok(hr == AUDCLNT_E_NOT_INITIALIZED, "Uninitialized GetService call returns %08lx\n", hr); - - CloseHandle(handle); -} - -static void test_audioclient(void) -{ - IAudioClient *ac; - IAudioClient2 *ac2; - IAudioClient3 *ac3; - IUnknown *unk; - HRESULT hr; - ULONG ref; - WAVEFORMATEX *pwfx, *pwfx2; - REFERENCE_TIME t1, t2; - HANDLE handle; - BOOL offload_capable; - AudioClientProperties client_props; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient3, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac3); - ok(hr == S_OK || - broken(hr == E_NOINTERFACE) /* win8 */, - "IAudioClient3 Activation failed with %08lx\n", hr); - if(hr == S_OK) - IAudioClient3_Release(ac3); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient2, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac2); - ok(hr == S_OK || - broken(hr == E_NOINTERFACE) /* win7 */, - "IAudioClient2 Activation failed with %08lx\n", hr); - if(hr == S_OK) - IAudioClient2_Release(ac2); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - handle = CreateEventW(NULL, FALSE, FALSE, NULL); - - hr = IAudioClient_QueryInterface(ac, &IID_IUnknown, NULL); - ok(hr == E_POINTER, "QueryInterface(NULL) returned %08lx\n", hr); - - unk = (void*)(LONG_PTR)0x12345678; - hr = IAudioClient_QueryInterface(ac, &IID_NULL, (void**)&unk); - ok(hr == E_NOINTERFACE, "QueryInterface(IID_NULL) returned %08lx\n", hr); - ok(!unk, "QueryInterface(IID_NULL) returned non-null pointer %p\n", unk); - - hr = IAudioClient_QueryInterface(ac, &IID_IUnknown, (void**)&unk); - ok(hr == S_OK, "QueryInterface(IID_IUnknown) returned %08lx\n", hr); - if (unk) - { - ref = IUnknown_Release(unk); - ok(ref == 1, "Released count is %lu\n", ref); - } - - hr = IAudioClient_QueryInterface(ac, &IID_IAudioClient, (void**)&unk); - ok(hr == S_OK, "QueryInterface(IID_IAudioClient) returned %08lx\n", hr); - if (unk) - { - ref = IUnknown_Release(unk); - ok(ref == 1, "Released count is %lu\n", ref); - } - - hr = IAudioClient_GetDevicePeriod(ac, NULL, NULL); - ok(hr == E_POINTER, "Invalid GetDevicePeriod call returns %08lx\n", hr); - - hr = IAudioClient_GetDevicePeriod(ac, &t1, NULL); - ok(hr == S_OK, "Valid GetDevicePeriod call returns %08lx\n", hr); - - hr = IAudioClient_GetDevicePeriod(ac, NULL, &t2); - ok(hr == S_OK, "Valid GetDevicePeriod call returns %08lx\n", hr); - - hr = IAudioClient_GetDevicePeriod(ac, &t1, &t2); - ok(hr == S_OK, "Valid GetDevicePeriod call returns %08lx\n", hr); - trace("Returned periods: %u.%04u ms %u.%04u ms\n", - (UINT)(t1/10000), (UINT)(t1 % 10000), - (UINT)(t2/10000), (UINT)(t2 % 10000)); - - hr = IAudioClient_GetMixFormat(ac, NULL); - ok(hr == E_POINTER, "GetMixFormat returns %08lx\n", hr); - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "Valid GetMixFormat returns %08lx\n", hr); - - if (hr == S_OK) - { - trace("pwfx: %p\n", pwfx); - trace("Tag: %04x\n", pwfx->wFormatTag); - trace("bits: %u\n", pwfx->wBitsPerSample); - trace("chan: %u\n", pwfx->nChannels); - trace("rate: %lu\n", pwfx->nSamplesPerSec); - trace("align: %u\n", pwfx->nBlockAlign); - trace("extra: %u\n", pwfx->cbSize); - ok(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE, "wFormatTag is %x\n", pwfx->wFormatTag); - if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - { - WAVEFORMATEXTENSIBLE *pwfxe = (void*)pwfx; - trace("Res: %u\n", pwfxe->Samples.wReserved); - trace("Mask: %lx\n", pwfxe->dwChannelMask); - trace("Alg: %s\n", - IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)?"PCM": - (IsEqualGUID(&pwfxe->SubFormat, - &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)?"FLOAT":"Other")); - ok(IsEqualGUID(&pwfxe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT), - "got format %s\n", debugstr_guid(&pwfxe->SubFormat)); - - pwfxe->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2); - ok(hr == S_OK, "Valid IsFormatSupported(Shared) call returns %08lx\n", hr); - ok(pwfx2 == NULL, "pwfx2 is non-null\n"); - CoTaskMemFree(pwfx2); - } - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &pwfx2); - ok(hr == S_OK, "Valid IsFormatSupported(Shared) call returns %08lx\n", hr); - ok(pwfx2 == NULL, "pwfx2 is non-null\n"); - CoTaskMemFree(pwfx2); - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, NULL, NULL); - ok(hr == E_POINTER, "IsFormatSupported(NULL) call returns %08lx\n", hr); - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, NULL); - ok(hr == E_POINTER, "IsFormatSupported(Shared,NULL) call returns %08lx\n", hr); - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, NULL); - ok(hr == S_OK || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED, - "IsFormatSupported(Exclusive) call returns %08lx\n", hr); - hexcl = hr; - - pwfx2 = (WAVEFORMATEX*)0xDEADF00D; - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, pwfx, &pwfx2); - ok(hr == hexcl, "IsFormatSupported(Exclusive) call returns %08lx\n", hr); - ok(pwfx2 == NULL, "pwfx2 non-null on exclusive IsFormatSupported\n"); - - if (hexcl != AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) - hexcl = S_OK; - - hr = IAudioClient_IsFormatSupported(ac, 0xffffffff, pwfx, NULL); - ok(hr == E_INVALIDARG/*w32*/ || - broken(hr == AUDCLNT_E_UNSUPPORTED_FORMAT/*w64 response from exclusive mode driver */), - "IsFormatSupported(0xffffffff) call returns %08lx\n", hr); - } - - hr = IAudioClient_QueryInterface(ac, &IID_IAudioClient2, (void**)&ac2); - if (hr == S_OK) - { - hr = IAudioClient2_IsOffloadCapable(ac2, AudioCategory_BackgroundCapableMedia, NULL); - ok(hr == E_INVALIDARG, "IsOffloadCapable gave wrong error: %08lx\n", hr); - - hr = IAudioClient2_IsOffloadCapable(ac2, AudioCategory_BackgroundCapableMedia, &offload_capable); - ok(hr == S_OK, "IsOffloadCapable failed: %08lx\n", hr); - - hr = IAudioClient2_SetClientProperties(ac2, NULL); - ok(hr == E_POINTER, "SetClientProperties with NULL props gave wrong error: %08lx\n", hr); - - /* invalid cbSize */ - client_props.cbSize = 0; - client_props.bIsOffload = FALSE; - client_props.eCategory = AudioCategory_BackgroundCapableMedia; - client_props.Options = 0; - - hr = IAudioClient2_SetClientProperties(ac2, &client_props); - ok(hr == E_INVALIDARG, "SetClientProperties with invalid cbSize gave wrong error: %08lx\n", hr); - - /* offload consistency */ - client_props.cbSize = sizeof(client_props) - sizeof(client_props.Options); - client_props.bIsOffload = TRUE; - - hr = IAudioClient2_SetClientProperties(ac2, &client_props); - if(!offload_capable) - ok(hr == AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE, "SetClientProperties(offload) gave wrong error: %08lx\n", hr); - else - ok(hr == S_OK, "SetClientProperties(offload) failed: %08lx\n", hr); - - /* disable offload */ - client_props.bIsOffload = FALSE; - hr = IAudioClient2_SetClientProperties(ac2, &client_props); - ok(hr == S_OK, "SetClientProperties failed: %08lx\n", hr); - - /* Options field added in Win 8.1 */ - client_props.cbSize = sizeof(client_props); - hr = IAudioClient2_SetClientProperties(ac2, &client_props); - ok(hr == S_OK || - broken(hr == E_INVALIDARG) /* <= win8 */, - "SetClientProperties failed: %08lx\n", hr); - - IAudioClient2_Release(ac2); - } - else - win_skip("IAudioClient2 is not present on Win <= 7\n"); - - hr = IAudioClient_QueryInterface(ac, &IID_IAudioClient3, (void**)&ac3); - ok(hr == S_OK || - broken(hr == E_NOINTERFACE) /* win8 */, - "Failed to query IAudioClient3 interface: %08lx\n", hr); - - if(hr == S_OK) - IAudioClient3_Release(ac3); - - test_uninitialized(ac); - - hr = IAudioClient_Initialize(ac, 3, 0, 5000000, 0, pwfx, NULL); - ok(broken(hr == AUDCLNT_E_NOT_INITIALIZED) || /* <= win8 */ - hr == E_INVALIDARG, "Initialize with invalid sharemode returns %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0xffffffff, 5000000, 0, pwfx, NULL); - ok(hr == E_INVALIDARG || - hr == AUDCLNT_E_INVALID_STREAM_FLAG, "Initialize with invalid flags returns %08lx\n", hr); - - /* A period != 0 is ignored and the call succeeds. - * Since we can only initialize successfully once, skip those tests. - */ - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, NULL, NULL); - ok(hr == E_POINTER, "Initialize with null format returns %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 0, 0, pwfx, NULL); - ok(hr == S_OK, "Initialize with 0 buffer size returns %08lx\n", hr); - if(hr == S_OK){ - UINT32 num; - - hr = IAudioClient_GetBufferSize(ac, &num); - ok(hr == S_OK, "GetBufferSize from duration 0 returns %08lx\n", hr); - if(hr == S_OK) - trace("Initialize(duration=0) GetBufferSize is %u\n", num); - } - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, pwfx, NULL); - ok(hr == AUDCLNT_E_ALREADY_INITIALIZED, "Calling Initialize twice returns %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == S_OK || - broken(hr == AUDCLNT_E_DEVICE_INVALIDATED), /* Win10 >= 1607 */ - "Start on a doubly initialized stream returns %08lx\n", hr); - - IAudioClient_Release(ac); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - - if(pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)pwfx; - WAVEFORMATEX *fmt2 = NULL; - - ok(fmtex->dwChannelMask != 0, "Got empty dwChannelMask\n"); - - fmtex->dwChannelMask = 0xffff; - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, pwfx, NULL); - ok(hr == S_OK || - hr == AUDCLNT_E_UNSUPPORTED_FORMAT /* win10 */, "Initialize(dwChannelMask = 0xffff) returns %08lx\n", hr); - - IAudioClient_Release(ac); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - - fmtex->dwChannelMask = 0; - - hr = IAudioClient_IsFormatSupported(ac, AUDCLNT_SHAREMODE_SHARED, pwfx, &fmt2); - ok(hr == S_OK || broken(hr == S_FALSE /* w7 Realtek HDA */), - "IsFormatSupported(dwChannelMask = 0) call returns %08lx\n", hr); - ok(fmtex->dwChannelMask == 0, "Passed format was modified\n"); - - CoTaskMemFree(fmt2); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, pwfx, NULL); - ok(hr == S_OK, "Initialize(dwChannelMask = 0) returns %08lx\n", hr); - - IAudioClient_Release(ac); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - - CoTaskMemFree(pwfx); - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "Valid GetMixFormat returns %08lx\n", hr); - }else - skip("Skipping dwChannelMask tests\n"); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, 0, pwfx, NULL); - ok(hr == S_OK, "Valid Initialize returns %08lx\n", hr); - if (hr != S_OK) - goto cleanup; - - hr = IAudioClient_GetStreamLatency(ac, NULL); - ok(hr == E_POINTER, "GetStreamLatency(NULL) call returns %08lx\n", hr); - - hr = IAudioClient_GetStreamLatency(ac, &t2); - ok(hr == S_OK, "Valid GetStreamLatency call returns %08lx\n", hr); - trace("Returned latency: %u.%04u ms\n", - (UINT)(t2/10000), (UINT)(t2 % 10000)); - ok(t2 >= t1 || broken(t2 >= t1/2 && pwfx->nSamplesPerSec > 48000) || - broken(t2 == 0) /* (!) win10 */, - "Latency < default period, delta %ldus (%s vs %s)\n", - (LONG)((t2-t1)/10), wine_dbgstr_longlong(t2), wine_dbgstr_longlong(t1)); - /* Native appears to add the engine period to the HW latency in shared mode */ - if(t2 == 0) - win10 = TRUE; - - hr = IAudioClient_SetEventHandle(ac, NULL); - ok(hr == E_INVALIDARG, "SetEventHandle(NULL) returns %08lx\n", hr); - - hr = IAudioClient_SetEventHandle(ac, handle); - ok(hr == AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED || - broken(hr == HRESULT_FROM_WIN32(ERROR_INVALID_NAME)) || - broken(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) /* Some 2k8 */ || - broken(hr == HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME)) /* Some Vista */ - , "SetEventHandle returns %08lx\n", hr); - - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset on an initialized stream returns %08lx\n", hr); - - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset on an already reset stream returns %08lx\n", hr); - - hr = IAudioClient_Stop(ac); - ok(hr == S_FALSE, "Stop on a stopped stream returns %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start on a stopped stream returns %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == AUDCLNT_E_NOT_STOPPED, "Start twice returns %08lx\n", hr); - -cleanup: - IAudioClient_Release(ac); - CloseHandle(handle); - CoTaskMemFree(pwfx); -} - -static void test_formats(AUDCLNT_SHAREMODE mode) -{ - IAudioClient *ac; - HRESULT hr, hrs; - WAVEFORMATEX fmt, *pwfx, *pwfx2; - int i; - - fmt.wFormatTag = WAVE_FORMAT_PCM; - fmt.cbSize = 0; - - for(i = 0; i < ARRAY_SIZE(win_formats); i++) { - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - continue; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - fmt.nSamplesPerSec = win_formats[i][0]; - fmt.wBitsPerSample = win_formats[i][1]; - fmt.nChannels = win_formats[i][2]; - fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8; - fmt.nAvgBytesPerSec= fmt.nBlockAlign * fmt.nSamplesPerSec; - - pwfx2 = (WAVEFORMATEX*)0xDEADF00D; - hr = IAudioClient_IsFormatSupported(ac, mode, &fmt, &pwfx2); - hrs = hr; - /* Only shared mode suggests something ... GetMixFormat! */ - ok(hr == S_OK || (mode == AUDCLNT_SHAREMODE_SHARED - ? hr == S_FALSE || broken(hr == AUDCLNT_E_UNSUPPORTED_FORMAT && - /* 5:1 card exception when asked for 1 channel at mixer rate */ - pwfx->nChannels > 2 && fmt.nSamplesPerSec == pwfx->nSamplesPerSec) - : (hr == AUDCLNT_E_UNSUPPORTED_FORMAT || hr == hexcl)), - "IsFormatSupported(%d, %lux%2ux%u) returns %08lx\n", mode, - fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - if (hr == S_OK) - trace("IsSupported(%s, %lux%2ux%u)\n", - mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", - fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels); - - /* Change GetMixFormat wBitsPerSample only => S_OK */ - if (mode == AUDCLNT_SHAREMODE_SHARED - && fmt.nSamplesPerSec == pwfx->nSamplesPerSec - && fmt.nChannels == pwfx->nChannels) - ok(hr == S_OK, "Varying BitsPerSample %u\n", fmt.wBitsPerSample); - - ok((hr == S_FALSE)^(pwfx2 == NULL), "hr %lx<->suggest %p\n", hr, pwfx2); - if (pwfx2 == (WAVEFORMATEX*)0xDEADF00D) - pwfx2 = NULL; /* broken in Wine < 1.3.28 */ - if (pwfx2) { - ok(pwfx2->nSamplesPerSec == pwfx->nSamplesPerSec && - pwfx2->nChannels == pwfx->nChannels && - pwfx2->wBitsPerSample == pwfx->wBitsPerSample, - "Suggestion %lux%2ux%u differs from GetMixFormat\n", - pwfx2->nSamplesPerSec, pwfx2->wBitsPerSample, pwfx2->nChannels); - } - - /* Vista returns E_INVALIDARG upon AUDCLNT_STREAMFLAGS_RATEADJUST */ - hr = IAudioClient_Initialize(ac, mode, 0, 5000000, 0, &fmt, NULL); - if ((hrs == S_OK) ^ (hr == S_OK)) - trace("Initialize (%s, %lux%2ux%u) returns %08lx unlike IsFormatSupported\n", - mode == AUDCLNT_SHAREMODE_SHARED ? "shared " : "exclus.", - fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - if (mode == AUDCLNT_SHAREMODE_SHARED) - ok(hrs == S_OK ? hr == S_OK : hr == AUDCLNT_E_UNSUPPORTED_FORMAT, - "Initialize(shared, %lux%2ux%u) returns %08lx\n", - fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - else if (hrs == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED) - /* Unsupported format implies "create failed" and shadows "not allowed" */ - ok(hrs == hexcl && (hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == hrs), - "Initialize(noexcl., %lux%2ux%u) returns %08lx(%08lx)\n", - fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr, hrs); - else - /* On testbot 48000x16x1 claims support, but does not Initialize. - * Some cards Initialize 44100|48000x16x1 yet claim no support; - * F. Gouget's w7 bots do that for 12000|96000x8|16x1|2 */ - ok(hrs == S_OK ? hr == S_OK || broken(hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED) - : hr == AUDCLNT_E_ENDPOINT_CREATE_FAILED || hr == AUDCLNT_E_UNSUPPORTED_FORMAT || - broken(hr == S_OK && - ((fmt.nChannels == 1 && fmt.wBitsPerSample == 16) || - (fmt.nSamplesPerSec == 12000 || fmt.nSamplesPerSec == 96000))), - "Initialize(exclus., %lux%2ux%u) returns %08lx\n", - fmt.nSamplesPerSec, fmt.wBitsPerSample, fmt.nChannels, hr); - - /* Bug in native (Vista/w2k8/w7): after Initialize failed, better - * Release this ac and Activate a new one. - * A second call (with a known working format) would yield - * ALREADY_INITIALIZED in shared mode yet be unusable, and in exclusive - * mode some entity keeps a lock on the device, causing DEVICE_IN_USE to - * all subsequent calls until the audio engine service is restarted. */ - - CoTaskMemFree(pwfx2); - CoTaskMemFree(pwfx); - IAudioClient_Release(ac); - } -} - -static void test_references(void) -{ - IAudioClient *ac; - IAudioRenderClient *rc; - ISimpleAudioVolume *sav; - IAudioStreamVolume *asv; - IAudioClock *acl; - WAVEFORMATEX *pwfx; - HRESULT hr; - ULONG ref; - - /* IAudioRenderClient */ - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, - 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - CoTaskMemFree(pwfx); - - hr = IAudioClient_GetService(ac, &IID_IAudioRenderClient, (void**)&rc); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - if(hr != S_OK) { - IAudioClient_Release(ac); - return; - } - - IAudioRenderClient_AddRef(rc); - ref = IAudioRenderClient_Release(rc); - ok(ref != 0, "RenderClient_Release gave wrong refcount: %lu\n", ref); - - ref = IAudioClient_Release(ac); - ok(ref != 0, "Client_Release gave wrong refcount: %lu\n", ref); - - ref = IAudioRenderClient_Release(rc); - ok(ref == 0, "RenderClient_Release gave wrong refcount: %lu\n", ref); - - /* ISimpleAudioVolume */ - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, - 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - CoTaskMemFree(pwfx); - - hr = IAudioClient_GetService(ac, &IID_ISimpleAudioVolume, (void**)&sav); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - ISimpleAudioVolume_AddRef(sav); - ref = ISimpleAudioVolume_Release(sav); - ok(ref != 0, "SimpleAudioVolume_Release gave wrong refcount: %lu\n", ref); - - ref = IAudioClient_Release(ac); - ok(ref != 0, "Client_Release gave wrong refcount: %lu\n", ref); - - ref = ISimpleAudioVolume_Release(sav); - ok(ref == 0, "SimpleAudioVolume_Release gave wrong refcount: %lu\n", ref); - - /* IAudioClock */ - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, - 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - CoTaskMemFree(pwfx); - - hr = IAudioClient_GetService(ac, &IID_IAudioClock, (void**)&acl); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - IAudioClock_AddRef(acl); - ref = IAudioClock_Release(acl); - ok(ref != 0, "AudioClock_Release gave wrong refcount: %lu\n", ref); - - ref = IAudioClient_Release(ac); - ok(ref != 0, "Client_Release gave wrong refcount: %lu\n", ref); - - ref = IAudioClock_Release(acl); - ok(ref == 0, "AudioClock_Release gave wrong refcount: %lu\n", ref); - - /* IAudioStreamVolume */ - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, - 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - CoTaskMemFree(pwfx); - - hr = IAudioClient_GetService(ac, &IID_IAudioStreamVolume, (void**)&asv); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - IAudioStreamVolume_AddRef(asv); - ref = IAudioStreamVolume_Release(asv); - ok(ref != 0, "AudioStreamVolume_Release gave wrong refcount: %lu\n", ref); - - ref = IAudioClient_Release(ac); - ok(ref != 0, "Client_Release gave wrong refcount: %lu\n", ref); - - ref = IAudioStreamVolume_Release(asv); - ok(ref == 0, "AudioStreamVolume_Release gave wrong refcount: %lu\n", ref); -} - -static void test_event(void) -{ - HANDLE event; - HRESULT hr; - DWORD r; - IAudioClient *ac; - WAVEFORMATEX *pwfx; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 5000000, - 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - CoTaskMemFree(pwfx); - - event = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(event != NULL, "CreateEvent failed\n"); - - hr = IAudioClient_Start(ac); - ok(hr == AUDCLNT_E_EVENTHANDLE_NOT_SET || - hr == D3D11_ERROR_4E /* win10 */, "Start failed: %08lx\n", hr); - - hr = IAudioClient_SetEventHandle(ac, event); - ok(hr == S_OK, "SetEventHandle failed: %08lx\n", hr); - - hr = IAudioClient_SetEventHandle(ac, event); - ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_NAME) || - hr == E_UNEXPECTED /* win10 */, "SetEventHandle returns %08lx\n", hr); - - r = WaitForSingleObject(event, 40); - ok(r == WAIT_TIMEOUT, "Wait(event) before Start gave %lx\n", r); - - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start failed: %08lx\n", hr); - - r = WaitForSingleObject(event, 20); - ok(r == WAIT_OBJECT_0, "Wait(event) after Start gave %lx\n", r); - - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - ok(ResetEvent(event), "ResetEvent\n"); - - /* Still receiving events! */ - r = WaitForSingleObject(event, 20); - ok(r == WAIT_OBJECT_0, "Wait(event) after Stop gave %lx\n", r); - - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset failed: %08lx\n", hr); - - ok(ResetEvent(event), "ResetEvent\n"); - - r = WaitForSingleObject(event, 120); - ok(r == WAIT_OBJECT_0, "Wait(event) after Reset gave %lx\n", r); - - hr = IAudioClient_SetEventHandle(ac, NULL); - ok(hr == E_INVALIDARG, "SetEventHandle(NULL) returns %08lx\n", hr); - - r = WaitForSingleObject(event, 70); - ok(r == WAIT_OBJECT_0, "Wait(NULL event) gave %lx\n", r); - - /* test releasing a playing stream */ - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start failed: %08lx\n", hr); - IAudioClient_Release(ac); - - CloseHandle(event); -} - -static void test_padding(void) -{ - HRESULT hr; - IAudioClient *ac; - IAudioRenderClient *arc; - WAVEFORMATEX *pwfx; - REFERENCE_TIME minp, defp; - BYTE *buf, silence; - UINT32 psize, pad, written, i; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - 0, 5000000, 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - if(hr != S_OK) - return; - - if(pwfx->wBitsPerSample == 8) - silence = 128; - else - silence = 0; - - /** GetDevicePeriod - * Default (= shared) device period is 10ms (e.g. 441 frames at 44100), - * except when the HW/OS forces a particular alignment, - * e.g. 10.1587ms is 28 * 16 = 448 frames at 44100 with HDA. - * 441 observed with Vista, 448 with w7 on the same HW! */ - hr = IAudioClient_GetDevicePeriod(ac, &defp, &minp); - ok(hr == S_OK, "GetDevicePeriod failed: %08lx\n", hr); - /* some wineXYZ.drv use 20ms, not seen on native */ - ok(defp == 100000 || broken(defp == 101587) || defp == 200000, - "Expected 10ms default period: %lu\n", (ULONG)defp); - ok(minp != 0, "Minimum period is 0\n"); - ok(minp <= defp, "Minimum period is greater than default period\n"); - - hr = IAudioClient_GetService(ac, &IID_IAudioRenderClient, (void**)&arc); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - psize = MulDiv(defp, pwfx->nSamplesPerSec, 10000000) * 10; - - written = 0; - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - ok(pad == written, "GetCurrentPadding returned %u, should be %u\n", pad, written); - - hr = IAudioRenderClient_GetBuffer(arc, psize, &buf); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - ok(buf != NULL, "NULL buffer returned\n"); - if(!win10){ - /* win10 appears not to clear the buffer */ - for(i = 0; i < psize * pwfx->nBlockAlign; ++i){ - if(buf[i] != silence){ - ok(0, "buffer has data in it already, i: %u, value: %f\n", i, *((float*)buf)); - break; - } - } - } - - hr = IAudioRenderClient_GetBuffer(arc, 0, &buf); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "GetBuffer 0 size failed: %08lx\n", hr); - ok(buf == NULL, "GetBuffer 0 gave %p\n", buf); - /* MSDN instead documents buf remains untouched */ - - hr = IAudioClient_Reset(ac); - ok(hr == AUDCLNT_E_BUFFER_OPERATION_PENDING, "Reset failed: %08lx\n", hr); - - hr = IAudioRenderClient_ReleaseBuffer(arc, psize, - AUDCLNT_BUFFERFLAGS_SILENT); - ok(hr == S_OK, "ReleaseBuffer failed: %08lx\n", hr); - if(hr == S_OK) written += psize; - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - ok(pad == written, "GetCurrentPadding returned %u, should be %u\n", pad, written); - - psize = MulDiv(minp, pwfx->nSamplesPerSec, 10000000) * 10; - - hr = IAudioRenderClient_GetBuffer(arc, psize, &buf); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - ok(buf != NULL, "NULL buffer returned\n"); - - hr = IAudioRenderClient_ReleaseBuffer(arc, psize, - AUDCLNT_BUFFERFLAGS_SILENT); - ok(hr == S_OK, "ReleaseBuffer failed: %08lx\n", hr); - written += psize; - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - ok(pad == written, "GetCurrentPadding returned %u, should be %u\n", pad, written); - - /* overfull buffer. requested 1/2s buffer size, so try - * to get a 1/2s buffer, which should fail */ - psize = pwfx->nSamplesPerSec / 2; - buf = (void*)0xDEADF00D; - hr = IAudioRenderClient_GetBuffer(arc, psize, &buf); - ok(hr == AUDCLNT_E_BUFFER_TOO_LARGE, "GetBuffer gave wrong error: %08lx\n", hr); - ok(buf == NULL, "NULL expected %p\n", buf); - - hr = IAudioRenderClient_ReleaseBuffer(arc, psize, 0); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "ReleaseBuffer gave wrong error: %08lx\n", hr); - - psize = MulDiv(minp, pwfx->nSamplesPerSec, 10000000) * 2; - - hr = IAudioRenderClient_GetBuffer(arc, psize, &buf); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - ok(buf != NULL, "NULL buffer returned\n"); - - hr = IAudioRenderClient_ReleaseBuffer(arc, 0, 0); - ok(hr == S_OK, "ReleaseBuffer 0 gave wrong error: %08lx\n", hr); - - buf = (void*)0xDEADF00D; - hr = IAudioRenderClient_GetBuffer(arc, 0, &buf); - ok(hr == S_OK, "GetBuffer 0 size failed: %08lx\n", hr); - ok(buf == NULL, "GetBuffer 0 gave %p\n", buf); - /* MSDN instead documents buf remains untouched */ - - buf = (void*)0xDEADF00D; - hr = IAudioRenderClient_GetBuffer(arc, 0, &buf); - ok(hr == S_OK, "GetBuffer 0 size #2 failed: %08lx\n", hr); - ok(buf == NULL, "GetBuffer 0 #2 gave %p\n", buf); - - hr = IAudioRenderClient_ReleaseBuffer(arc, psize, 0); - ok(hr == AUDCLNT_E_OUT_OF_ORDER, "ReleaseBuffer not size 0 gave %08lx\n", hr); - - hr = IAudioRenderClient_GetBuffer(arc, psize, &buf); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - ok(buf != NULL, "NULL buffer returned\n"); - - hr = IAudioRenderClient_ReleaseBuffer(arc, 0, 0); - ok(hr == S_OK, "ReleaseBuffer 0 gave wrong error: %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - ok(pad == written, "GetCurrentPadding returned %u, should be %u\n", pad, written); - - hr = IAudioRenderClient_GetBuffer(arc, psize, &buf); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - ok(buf != NULL, "NULL buffer returned\n"); - - hr = IAudioRenderClient_ReleaseBuffer(arc, psize+1, AUDCLNT_BUFFERFLAGS_SILENT); - ok(hr == AUDCLNT_E_INVALID_SIZE, "ReleaseBuffer too large error: %08lx\n", hr); - /* todo_wine means Wine may overwrite memory */ - if(hr == S_OK) written += psize+1; - - /* Buffer still hold */ - hr = IAudioRenderClient_ReleaseBuffer(arc, psize/2, AUDCLNT_BUFFERFLAGS_SILENT); - ok(hr == S_OK, "ReleaseBuffer after error: %08lx\n", hr); - if(hr == S_OK) written += psize/2; - - hr = IAudioRenderClient_ReleaseBuffer(arc, 0, 0); - ok(hr == S_OK, "ReleaseBuffer 0 gave wrong error: %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - ok(pad == written, "GetCurrentPadding returned %u, should be %u\n", pad, written); - - CoTaskMemFree(pwfx); - - IAudioRenderClient_Release(arc); - IAudioClient_Release(ac); -} - -static void test_clock(int share) -{ - HRESULT hr; - IAudioClient *ac; - IAudioClock *acl; - IAudioRenderClient *arc; - UINT64 freq, pos, pcpos0, pcpos, last; - UINT32 pad, gbsize, bufsize, fragment, parts, avail, slept = 0, sum = 0; - BYTE *data; - WAVEFORMATEX *pwfx; - LARGE_INTEGER hpctime, hpctime0, hpcfreq; - REFERENCE_TIME minp, defp, t1, t2; - REFERENCE_TIME duration = 5000000, period = 150000; - int i; - - ok(QueryPerformanceFrequency(&hpcfreq), "PerfFrequency failed\n"); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetDevicePeriod(ac, &defp, &minp); - ok(hr == S_OK, "GetDevicePeriod failed: %08lx\n", hr); - ok(minp <= period, "desired period %lu too small for %lu\n", (ULONG)period, (ULONG)minp); - - if (share) { - trace("Testing shared mode\n"); - /* period is ignored */ - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - 0, duration, period, pwfx, NULL); - period = defp; - } else { - pwfx->wFormatTag = WAVE_FORMAT_PCM; - pwfx->nChannels = 2; - pwfx->cbSize = 0; - pwfx->wBitsPerSample = 16; /* no floating point */ - pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8; - pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign; - trace("Testing exclusive mode at %lu\n", pwfx->nSamplesPerSec); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_EXCLUSIVE, - 0, duration, period, pwfx, NULL); - } - ok(share ? hr == S_OK : hr == hexcl || hr == AUDCLNT_E_DEVICE_IN_USE, "Initialize failed: %08lx\n", hr); - if (hr != S_OK) { - CoTaskMemFree(pwfx); - IAudioClient_Release(ac); - if(hr == AUDCLNT_E_DEVICE_IN_USE) - skip("Device in use, no %s access\n", share ? "shared" : "exclusive"); - return; - } - - /** GetStreamLatency - * Shared mode: 1x period + a little, but some 192000 devices return 5.3334ms. - * Exclusive mode: testbot returns 2x period + a little, but - * some HDA drivers return 1x period, some + a little. */ - hr = IAudioClient_GetStreamLatency(ac, &t2); - ok(hr == S_OK, "GetStreamLatency failed: %08lx\n", hr); - trace("Latency: %u.%04u ms\n", (UINT)(t2/10000), (UINT)(t2 % 10000)); - ok(t2 >= period || broken(t2 >= period/2 && share && pwfx->nSamplesPerSec > 48000) || - broken(t2 == 0) /* win10 */, - "Latency < default period, delta %ldus\n", (long)((t2-period)/10)); - - /** GetBufferSize - * BufferSize must be rounded up, maximum 2s says MSDN. - * Both is wrong. Rounding may lead to size a little smaller than duration; - * duration > 2s is accepted in shared mode. - * Shared mode: round solely w.r.t. mixer rate, - * duration is no multiple of period. - * Exclusive mode: size appears as a multiple of some fragment that - * is either the rounded period or a fixed constant like 1024, - * whatever the driver implements. */ - hr = IAudioClient_GetBufferSize(ac, &gbsize); - ok(hr == S_OK, "GetBufferSize failed: %08lx\n", hr); - - bufsize = MulDiv(duration, pwfx->nSamplesPerSec, 10000000); - fragment = MulDiv(period, pwfx->nSamplesPerSec, 10000000); - parts = MulDiv(bufsize, 1, fragment); /* instead of (duration, 1, period) */ - trace("BufferSize %u estimated fragment %u x %u = %u\n", gbsize, fragment, parts, fragment * parts); - /* fragment size (= period in frames) is rounded up. - * BufferSize must be rounded up, maximum 2s says MSDN - * but it is rounded down modulo fragment ! */ - if (share) - ok(gbsize == bufsize, - "BufferSize %u at rate %lu\n", gbsize, pwfx->nSamplesPerSec); - else - flaky - ok(gbsize == parts * fragment || gbsize == MulDiv(bufsize, 1, 1024) * 1024, - "BufferSize %u misfits fragment size %u at rate %lu\n", gbsize, fragment, pwfx->nSamplesPerSec); - - /* In shared mode, GetCurrentPadding decreases in multiples of - * fragment size (i.e. updated only at period ticks), whereas - * GetPosition appears to be reporting continuous positions. - * In exclusive mode, testbot behaves likewise, but native's Intel - * HDA driver shows no such deltas, GetCurrentPadding closely - * matches GetPosition, as in - * GetCurrentPadding = GetPosition - frames held in mmdevapi */ - - hr = IAudioClient_GetService(ac, &IID_IAudioClock, (void**)&acl); - ok(hr == S_OK, "GetService(IAudioClock) failed: %08lx\n", hr); - - hr = IAudioClock_GetFrequency(acl, &freq); - ok(hr == S_OK, "GetFrequency failed: %08lx\n", hr); - trace("Clock Frequency %u\n", (UINT)freq); - - /* MSDN says it's arbitrary units, but shared mode is unlikely to change */ - if (share) - ok(freq == pwfx->nSamplesPerSec * pwfx->nBlockAlign, - "Clock Frequency %u\n", (UINT)freq); - else - ok(freq == pwfx->nSamplesPerSec, - "Clock Frequency %u\n", (UINT)freq); - - hr = IAudioClock_GetPosition(acl, NULL, NULL); - ok(hr == E_POINTER, "GetPosition wrong error: %08lx\n", hr); - - pcpos0 = 0; - hr = IAudioClock_GetPosition(acl, &pos, &pcpos0); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - ok(pos == 0, "GetPosition returned non-zero pos before being started\n"); - ok(pcpos0 != 0, "GetPosition returned zero pcpos\n"); - - hr = IAudioClient_GetService(ac, &IID_IAudioRenderClient, (void**)&arc); - ok(hr == S_OK, "GetService(IAudioRenderClient) failed: %08lx\n", hr); - - hr = IAudioRenderClient_GetBuffer(arc, gbsize+1, &data); - ok(hr == AUDCLNT_E_BUFFER_TOO_LARGE, "GetBuffer too large failed: %08lx\n", hr); - - avail = gbsize; - data = NULL; - hr = IAudioRenderClient_GetBuffer(arc, avail, &data); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - trace("data at %p\n", data); - - hr = IAudioRenderClient_ReleaseBuffer(arc, avail, winetest_debug>2 ? - wave_generate_tone(pwfx, data, avail) : AUDCLNT_BUFFERFLAGS_SILENT); - ok(hr == S_OK, "ReleaseBuffer failed: %08lx\n", hr); - if(hr == S_OK) sum += avail; - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - ok(pad == sum, "padding %u prior to start\n", pad); - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - ok(pos == 0, "GetPosition returned non-zero pos before being started\n"); - - hr = IAudioClient_Start(ac); /* #1 */ - ok(hr == S_OK, "Start failed: %08lx\n", hr); - - Sleep(100); - slept += 100; - - hr = IAudioClient_GetStreamLatency(ac, &t1); - ok(hr == S_OK, "GetStreamLatency failed: %08lx\n", hr); - ok(t1 == t2, "Latency not constant, delta %ld\n", (long)(t1-t2)); - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - ok(pos > 0, "Position %u vs. last %u\n", (UINT)pos,0); - /* in rare cases is slept*1.1 not enough with dmix */ - flaky - ok(pos*1000/freq <= slept*1.4, "Position %u too far after playing %ums\n", (UINT)pos, slept); - last = pos; - - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - ok(pos >= last, "Position %u vs. last %u\n", (UINT)pos,(UINT)last); - last = pos; - if(/*share &&*/ winetest_debug>1) - ok(pos*1000/freq <= slept*1.1, "Position %u too far after stop %ums\n", (UINT)pos, slept); - - hr = IAudioClient_Start(ac); /* #2 */ - ok(hr == S_OK, "Start failed: %08lx\n", hr); - - Sleep(100); - slept += 100; - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - trace("padding %u past sleep #2\n", pad); - - /** IAudioClient_Stop - * Exclusive mode: the audio engine appears to drop frames, - * bumping GetPosition to a higher value than time allows, even - * allowing GetPosition > sum Released - GetCurrentPadding (testbot) - * Shared mode: no drop observed (or too small to be visible). - * GetPosition = sum Released - GetCurrentPadding - * Bugs: Some USB headset system drained the whole buffer, leaving - * padding 0 and bumping pos to sum minus 17 frames! */ - - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - trace("padding %u position %u past stop #2\n", pad, (UINT)pos); - ok(pos * pwfx->nSamplesPerSec <= sum * freq, "Position %u > written %u\n", (UINT)pos, sum); - /* Prove that Stop must not drop frames (in shared mode). */ - ok(pad ? pos > last : pos >= last, "Position %u vs. last %u\n", (UINT)pos,(UINT)last); - if (share && pad > 0 && winetest_debug>1) - ok(pos*1000/freq <= slept*1.1, "Position %u too far after playing %ums\n", (UINT)pos, slept); - /* in exclusive mode, testbot's w7 machines yield pos > sum-pad */ - if(/*share &&*/ winetest_debug>1) - ok(pos * pwfx->nSamplesPerSec == (sum-pad) * freq, - "Position %u after stop vs. %u padding\n", (UINT)pos, pad); - last = pos; - - Sleep(100); - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - ok(pos == last, "Position %u should stop.\n", (UINT)pos); - - /* Restart from 0 */ - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset failed: %08lx\n", hr); - slept = sum = 0; - - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset on an already reset stream returns %08lx\n", hr); - - hr = IAudioClock_GetPosition(acl, &pos, &pcpos); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - ok(pos == 0, "GetPosition returned non-zero pos after Reset\n"); - ok(pcpos > pcpos0, "pcpos should increase\n"); - - avail = gbsize; /* implies GetCurrentPadding == 0 */ - hr = IAudioRenderClient_GetBuffer(arc, avail, &data); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - trace("data at %p\n", data); - - hr = IAudioRenderClient_ReleaseBuffer(arc, avail, winetest_debug>2 ? - wave_generate_tone(pwfx, data, avail) : AUDCLNT_BUFFERFLAGS_SILENT); - ok(hr == S_OK, "ReleaseBuffer failed: %08lx\n", hr); - if(hr == S_OK) sum += avail; - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - ok(pad == sum, "padding %u prior to start\n", pad); - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - ok(pos == 0, "GetPosition returned non-zero pos after Reset\n"); - last = pos; - - hr = IAudioClient_Start(ac); /* #3 */ - ok(hr == S_OK, "Start failed: %08lx\n", hr); - - Sleep(100); - slept += 100; - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - trace("position %u past %ums sleep #3\n", (UINT)pos, slept); - ok(pos > last, "Position %u vs. last %u\n", (UINT)pos,(UINT)last); - ok(pos * pwfx->nSamplesPerSec <= sum * freq, "Position %u > written %u\n", (UINT)pos, sum); - if (winetest_debug>1) - ok(pos*1000/freq <= slept*1.1, "Position %u too far after playing %ums\n", (UINT)pos, slept); - else - skip("Rerun with WINETEST_DEBUG=2 for GetPosition tests.\n"); - last = pos; - - hr = IAudioClient_Reset(ac); - ok(hr == AUDCLNT_E_NOT_STOPPED, "Reset while playing: %08lx\n", hr); - - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - - hr = IAudioClock_GetPosition(acl, &pos, &pcpos); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - trace("padding %u position %u past stop #3\n", pad, (UINT)pos); - ok(pos >= last, "Position %u vs. last %u\n", (UINT)pos,(UINT)last); - ok(pcpos > pcpos0, "pcpos should increase\n"); - ok(pos * pwfx->nSamplesPerSec <= sum * freq, "Position %u > written %u\n", (UINT)pos, sum); - if (pad > 0 && winetest_debug>1) - ok(pos*1000/freq <= slept*1.1, "Position %u too far after stop %ums\n", (UINT)pos, slept); - if(winetest_debug>1) - ok(pos * pwfx->nSamplesPerSec == (sum-pad) * freq, - "Position %u after stop vs. %u padding\n", (UINT)pos, pad); - last = pos; - - /* Begin the big loop */ - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset failed: %08lx\n", hr); - slept = last = sum = 0; - pcpos0 = pcpos; - - ok(QueryPerformanceCounter(&hpctime0), "PerfCounter unavailable\n"); - - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset on an already reset stream returns %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start failed: %08lx\n", hr); - - avail = pwfx->nSamplesPerSec * 15 / 16 / 2; - data = NULL; - hr = IAudioRenderClient_GetBuffer(arc, avail, &data); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - trace("data at %p for prefill %u\n", data, avail); - - if (winetest_debug>2) { - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - Sleep(20); - slept += 20; - - hr = IAudioClient_Reset(ac); - ok(hr == AUDCLNT_E_BUFFER_OPERATION_PENDING, "Reset failed: %08lx\n", hr); - - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start failed: %08lx\n", hr); - } - - /* Despite passed time, data must still point to valid memory... */ - hr = IAudioRenderClient_ReleaseBuffer(arc, avail, - wave_generate_tone(pwfx, data, avail)); - ok(hr == S_OK, "ReleaseBuffer after stop+start failed: %08lx\n", hr); - if(hr == S_OK) sum += avail; - - /* GetCurrentPadding(GCP) == 0 does not mean an underrun happened, as the - * mixer may still have a little data. We believe an underrun will occur - * when the mixer finds GCP smaller than a period size at the *end* of a - * period cycle, i.e. shortly before calling SetEvent to signal the app - * that it has ~10ms to supply data for the next cycle. IOW, a zero GCP - * with no data written for over a period causes an underrun. */ - - Sleep(350); - slept += 350; - ok(QueryPerformanceCounter(&hpctime), "PerfCounter failed\n"); - trace("hpctime %lu after %ums\n", - (ULONG)((hpctime.QuadPart-hpctime0.QuadPart)*1000/hpcfreq.QuadPart), slept); - - hr = IAudioClock_GetPosition(acl, &pos, &pcpos); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - ok(pos > last, "Position %u vs. last %u\n", (UINT)pos,(UINT)last); - last = pos; - - for(i=0; i < 9; i++) { - Sleep(100); - slept += 100; - - hr = IAudioClock_GetPosition(acl, &pos, &pcpos); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - - ok(QueryPerformanceCounter(&hpctime), "PerfCounter failed\n"); - trace("hpctime %lu pcpos %lu\n", - (ULONG)((hpctime.QuadPart-hpctime0.QuadPart)*1000/hpcfreq.QuadPart), - (ULONG)((pcpos-pcpos0)/10000)); - - /* Use sum-pad to see whether position is ahead padding or not. */ - trace("padding %u position %u/%u slept %ums iteration %d\n", pad, (UINT)pos, sum-pad, slept, i); - ok(pad ? pos > last : pos >= last, "No position increase at iteration %d\n", i); - ok(pos * pwfx->nSamplesPerSec <= sum * freq, "Position %u > written %u\n", (UINT)pos, sum); - if (winetest_debug>1) { - /* Padding does not lag behind by much */ - ok(pos * pwfx->nSamplesPerSec <= (sum-pad+fragment) * freq, "Position %u > written %u\n", (UINT)pos, sum); - ok(pos*1000/freq <= slept*1.1, "Position %u too far after %ums\n", (UINT)pos, slept); - if (pad) /* not in case of underrun */ - ok((pos-last)*1000/freq >= 90 && 110 >= (pos-last)*1000/freq, - "Position delta %ld not regular: %ld ms\n", (long)(pos-last), (long)((pos-last)*1000/freq)); - } - last = pos; - - hr = IAudioClient_GetStreamLatency(ac, &t1); - ok(hr == S_OK, "GetStreamLatency failed: %08lx\n", hr); - ok(t1 == t2, "Latency not constant, delta %ld\n", (long)(t1-t2)); - - avail = pwfx->nSamplesPerSec * 15 / 16 / 2; - data = NULL; - hr = IAudioRenderClient_GetBuffer(arc, avail, &data); - /* ok(hr == AUDCLNT_E_BUFFER_TOO_LARGE || (hr == S_OK && i==0) without todo_wine */ - ok(hr == S_OK || hr == AUDCLNT_E_BUFFER_TOO_LARGE, - "GetBuffer large (%u) failed: %08lx\n", avail, hr); - if(hr == S_OK && i) ok(FALSE, "GetBuffer large (%u) at iteration %d\n", avail, i); - /* Only the first iteration should allow that large a buffer - * as prefill was drained during the first 350+100ms sleep. - * Afterwards, only 100ms of data should find room per iteration. */ - - if(hr == S_OK) { - trace("data at %p\n", data); - } else { - avail = gbsize - pad; - hr = IAudioRenderClient_GetBuffer(arc, avail, &data); - ok(hr == S_OK, "GetBuffer small %u failed: %08lx\n", avail, hr); - trace("data at %p (small %u)\n", data, avail); - } - ok(data != NULL, "NULL buffer returned\n"); - if(i % 3 && !winetest_interactive) { - memset(data, 0, avail * pwfx->nBlockAlign); - hr = IAudioRenderClient_ReleaseBuffer(arc, avail, 0); - } else { - hr = IAudioRenderClient_ReleaseBuffer(arc, avail, - wave_generate_tone(pwfx, data, avail)); - } - ok(hr == S_OK, "ReleaseBuffer failed: %08lx\n", hr); - if(hr == S_OK) sum += avail; - } - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - trace("position %u\n", (UINT)pos); - - Sleep(1000); /* 500ms buffer underrun past full buffer */ - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - - hr = IAudioClock_GetPosition(acl, &pos, NULL); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - trace("position %u past underrun, %u padding left, %u frames written\n", (UINT)pos, pad, sum); - - if (share) { - /* Following underrun, all samples were played */ - ok(pad == 0, "GetCurrentPadding returned %u, should be 0\n", pad); - ok(pos * pwfx->nSamplesPerSec == sum * freq, - "Position %u at end vs. %u submitted frames\n", (UINT)pos, sum); - } else { - /* Vista and w2k8 leave partial fragments behind */ - ok(pad == 0 /* w7, w2k8R2 */|| - pos * pwfx->nSamplesPerSec == (sum-pad) * freq, "GetCurrentPadding returned %u, should be 0\n", pad); - /* expect at most 5 fragments (75ms) away */ - ok(pos * pwfx->nSamplesPerSec <= sum * freq && - pos * pwfx->nSamplesPerSec + 5 * fragment * freq >= sum * freq, - "Position %u at end vs. %u submitted frames\n", (UINT)pos, sum); - } - - hr = IAudioClient_GetStreamLatency(ac, &t1); - ok(hr == S_OK, "GetStreamLatency failed: %08lx\n", hr); - ok(t1 == t2, "Latency not constant, delta %ld\n", (long)(t1-t2)); - - ok(QueryPerformanceCounter(&hpctime), "PerfCounter failed\n"); - trace("hpctime %lu after underrun\n", (ULONG)((hpctime.QuadPart-hpctime0.QuadPart)*1000/hpcfreq.QuadPart)); - - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - CoTaskMemFree(pwfx); - - IAudioClock_Release(acl); - IAudioRenderClient_Release(arc); - IAudioClient_Release(ac); -} - -static void test_session(void) -{ - IAudioClient *ses1_ac1, *ses1_ac2, *cap_ac; - IAudioSessionControl2 *ses1_ctl, *ses1_ctl2, *cap_ctl = NULL; - IMMDevice *cap_dev; - GUID ses1_guid; - AudioSessionState state; - WAVEFORMATEX *pwfx; - ULONG ref; - HRESULT hr; - - hr = CoCreateGuid(&ses1_guid); - ok(hr == S_OK, "CoCreateGuid failed: %08lx\n", hr); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ses1_ac1); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if (FAILED(hr)) return; - - hr = IAudioClient_GetMixFormat(ses1_ac1, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ses1_ac1, AUDCLNT_SHAREMODE_SHARED, - 0, 5000000, 0, pwfx, &ses1_guid); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - if(hr == S_OK){ - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ses1_ac2); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - } - if(hr != S_OK){ - skip("Unable to open the same device twice. Skipping session tests\n"); - - ref = IAudioClient_Release(ses1_ac1); - ok(ref == 0, "AudioClient wasn't released: %lu\n", ref); - CoTaskMemFree(pwfx); - return; - } - - hr = IAudioClient_Initialize(ses1_ac2, AUDCLNT_SHAREMODE_SHARED, - 0, 5000000, 0, pwfx, &ses1_guid); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eCapture, - eMultimedia, &cap_dev); - if(hr == S_OK){ - hr = IMMDevice_Activate(cap_dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&cap_ac); - ok((hr == S_OK)^(cap_ac == NULL), "Activate %08lx &out pointer\n", hr); - ok(hr == S_OK, "Activate failed: %08lx\n", hr); - IMMDevice_Release(cap_dev); - } - if(hr == S_OK){ - WAVEFORMATEX *cap_pwfx; - - hr = IAudioClient_GetMixFormat(cap_ac, &cap_pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(cap_ac, AUDCLNT_SHAREMODE_SHARED, - 0, 5000000, 0, cap_pwfx, &ses1_guid); - ok(hr == S_OK, "Initialize failed for capture in rendering session: %08lx\n", hr); - CoTaskMemFree(cap_pwfx); - } - if(hr == S_OK){ - hr = IAudioClient_GetService(cap_ac, &IID_IAudioSessionControl, (void**)&cap_ctl); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - if(FAILED(hr)) - cap_ctl = NULL; - }else - skip("No capture session: %08lx; skipping capture device in render session tests\n", hr); - - hr = IAudioClient_GetService(ses1_ac1, &IID_IAudioSessionControl2, (void**)&ses1_ctl); - ok(hr == E_NOINTERFACE, "GetService gave wrong error: %08lx\n", hr); - - hr = IAudioClient_GetService(ses1_ac1, &IID_IAudioSessionControl, (void**)&ses1_ctl); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ses1_ac1, &IID_IAudioSessionControl, (void**)&ses1_ctl2); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - ok(ses1_ctl == ses1_ctl2, "Got different controls: %p %p\n", ses1_ctl, ses1_ctl2); - ref = IAudioSessionControl2_Release(ses1_ctl2); - ok(ref != 0, "AudioSessionControl was destroyed\n"); - - hr = IAudioClient_GetService(ses1_ac2, &IID_IAudioSessionControl, (void**)&ses1_ctl2); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - hr = IAudioSessionControl2_GetState(ses1_ctl, NULL); - ok(hr == NULL_PTR_ERR, "GetState gave wrong error: %08lx\n", hr); - - hr = IAudioSessionControl2_GetState(ses1_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - hr = IAudioSessionControl2_GetState(ses1_ctl2, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - if(cap_ctl){ - hr = IAudioSessionControl2_GetState(cap_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - } - - hr = IAudioClient_Start(ses1_ac1); - ok(hr == S_OK, "Start failed: %08lx\n", hr); - - hr = IAudioSessionControl2_GetState(ses1_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateActive, "Got wrong state: %d\n", state); - - hr = IAudioSessionControl2_GetState(ses1_ctl2, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateActive, "Got wrong state: %d\n", state); - - if(cap_ctl){ - hr = IAudioSessionControl2_GetState(cap_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - } - - hr = IAudioClient_Stop(ses1_ac1); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - hr = IAudioSessionControl2_GetState(ses1_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - hr = IAudioSessionControl2_GetState(ses1_ctl2, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - if(cap_ctl){ - hr = IAudioSessionControl2_GetState(cap_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - hr = IAudioClient_Start(cap_ac); - ok(hr == S_OK, "Start failed: %08lx\n", hr); - - hr = IAudioSessionControl2_GetState(ses1_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - hr = IAudioSessionControl2_GetState(ses1_ctl2, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - hr = IAudioSessionControl2_GetState(cap_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateActive, "Got wrong state: %d\n", state); - - hr = IAudioClient_Stop(cap_ac); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - hr = IAudioSessionControl2_GetState(ses1_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - hr = IAudioSessionControl2_GetState(ses1_ctl2, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - hr = IAudioSessionControl2_GetState(cap_ctl, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - ref = IAudioSessionControl2_Release(cap_ctl); - ok(ref == 0, "AudioSessionControl wasn't released: %lu\n", ref); - - ref = IAudioClient_Release(cap_ac); - ok(ref == 0, "AudioClient wasn't released: %lu\n", ref); - } - - ref = IAudioSessionControl2_Release(ses1_ctl); - ok(ref == 0, "AudioSessionControl wasn't released: %lu\n", ref); - - ref = IAudioClient_Release(ses1_ac1); - ok(ref == 0, "AudioClient wasn't released: %lu\n", ref); - - ref = IAudioClient_Release(ses1_ac2); - ok(ref == 1, "AudioClient had wrong refcount: %lu\n", ref); - - /* we've released all of our IAudioClient references, so check GetState */ - hr = IAudioSessionControl2_GetState(ses1_ctl2, &state); - ok(hr == S_OK, "GetState failed: %08lx\n", hr); - ok(state == AudioSessionStateInactive, "Got wrong state: %d\n", state); - - ref = IAudioSessionControl2_Release(ses1_ctl2); - ok(ref == 0, "AudioSessionControl wasn't released: %lu\n", ref); - - CoTaskMemFree(pwfx); -} - -static void test_streamvolume(void) -{ - IAudioClient *ac; - IAudioStreamVolume *asv; - WAVEFORMATEX *fmt; - UINT32 chans, i; - HRESULT hr; - float vol, *vols; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, - 0, fmt, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - if(hr == S_OK){ - hr = IAudioClient_GetService(ac, &IID_IAudioStreamVolume, (void**)&asv); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - } - if(hr != S_OK){ - IAudioClient_Release(ac); - CoTaskMemFree(fmt); - return; - } - - hr = IAudioStreamVolume_GetChannelCount(asv, NULL); - ok(hr == E_POINTER, "GetChannelCount gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelCount(asv, &chans); - ok(hr == S_OK, "GetChannelCount failed: %08lx\n", hr); - ok(chans == fmt->nChannels, "GetChannelCount gave wrong number of channels: %d\n", chans); - - hr = IAudioStreamVolume_GetChannelVolume(asv, fmt->nChannels, NULL); - ok(hr == E_POINTER, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, fmt->nChannels, &vol); - ok(hr == E_INVALIDARG, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, 0, NULL); - ok(hr == E_POINTER, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, 0, &vol); - ok(hr == S_OK, "GetChannelVolume failed: %08lx\n", hr); - ok(vol == 1.f, "Channel volume was not 1: %f\n", vol); - - hr = IAudioStreamVolume_SetChannelVolume(asv, fmt->nChannels, -1.f); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetChannelVolume(asv, 0, -1.f); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetChannelVolume(asv, 0, 2.f); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetChannelVolume(asv, 0, 0.2f); - ok(hr == S_OK, "SetChannelVolume failed: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, 0, &vol); - ok(hr == S_OK, "GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "Channel volume wasn't 0.2: %f\n", vol); - - hr = IAudioStreamVolume_GetAllVolumes(asv, 0, NULL); - ok(hr == E_POINTER, "GetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetAllVolumes(asv, fmt->nChannels, NULL); - ok(hr == E_POINTER, "GetAllVolumes gave wrong error: %08lx\n", hr); - - vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float)); - ok(vols != NULL, "HeapAlloc failed\n"); - - hr = IAudioStreamVolume_GetAllVolumes(asv, fmt->nChannels - 1, vols); - ok(hr == E_INVALIDARG, "GetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_GetAllVolumes(asv, fmt->nChannels, vols); - ok(hr == S_OK, "GetAllVolumes failed: %08lx\n", hr); - ok(fabsf(vols[0] - 0.2f) < 0.05f, "Channel 0 volume wasn't 0.2: %f\n", vol); - for(i = 1; i < fmt->nChannels; ++i) - ok(vols[i] == 1.f, "Channel %d volume is not 1: %f\n", i, vols[i]); - - hr = IAudioStreamVolume_SetAllVolumes(asv, 0, NULL); - ok(hr == E_POINTER, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetAllVolumes(asv, fmt->nChannels, NULL); - ok(hr == E_POINTER, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetAllVolumes(asv, fmt->nChannels - 1, vols); - ok(hr == E_INVALIDARG, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IAudioStreamVolume_SetAllVolumes(asv, fmt->nChannels, vols); - ok(hr == S_OK, "SetAllVolumes failed: %08lx\n", hr); - - HeapFree(GetProcessHeap(), 0, vols); - IAudioStreamVolume_Release(asv); - IAudioClient_Release(ac); - CoTaskMemFree(fmt); -} - -static void test_channelvolume(void) -{ - IAudioClient *ac; - IChannelAudioVolume *acv; - WAVEFORMATEX *fmt; - UINT32 chans, i; - HRESULT hr; - float vol, *vols; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - if(hr == S_OK){ - hr = IAudioClient_GetService(ac, &IID_IChannelAudioVolume, (void**)&acv); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - } - if(hr != S_OK){ - IAudioClient_Release(ac); - CoTaskMemFree(fmt); - return; - } - - hr = IChannelAudioVolume_GetChannelCount(acv, NULL); - ok(hr == NULL_PTR_ERR, "GetChannelCount gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelCount(acv, &chans); - ok(hr == S_OK, "GetChannelCount failed: %08lx\n", hr); - ok(chans == fmt->nChannels, "GetChannelCount gave wrong number of channels: %d\n", chans); - - hr = IChannelAudioVolume_GetChannelVolume(acv, fmt->nChannels, NULL); - ok(hr == NULL_PTR_ERR, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(acv, fmt->nChannels, &vol); - ok(hr == E_INVALIDARG, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(acv, 0, NULL); - ok(hr == NULL_PTR_ERR, "GetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(acv, 0, &vol); - ok(hr == S_OK, "GetChannelVolume failed: %08lx\n", hr); - ok(vol == 1.f, "Channel volume was not 1: %f\n", vol); - - hr = IChannelAudioVolume_SetChannelVolume(acv, fmt->nChannels, -1.f, NULL); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(acv, 0, -1.f, NULL); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(acv, 0, 2.f, NULL); - ok(hr == E_INVALIDARG, "SetChannelVolume gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(acv, 0, 0.2f, NULL); - ok(hr == S_OK, "SetChannelVolume failed: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(acv, 0, &vol); - ok(hr == S_OK, "GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "Channel volume wasn't 0.2: %f\n", vol); - - hr = IChannelAudioVolume_GetAllVolumes(acv, 0, NULL); - ok(hr == NULL_PTR_ERR, "GetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetAllVolumes(acv, fmt->nChannels, NULL); - ok(hr == NULL_PTR_ERR, "GetAllVolumes gave wrong error: %08lx\n", hr); - - vols = HeapAlloc(GetProcessHeap(), 0, fmt->nChannels * sizeof(float)); - ok(vols != NULL, "HeapAlloc failed\n"); - - hr = IChannelAudioVolume_GetAllVolumes(acv, fmt->nChannels - 1, vols); - ok(hr == E_INVALIDARG, "GetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_GetAllVolumes(acv, fmt->nChannels, vols); - ok(hr == S_OK, "GetAllVolumes failed: %08lx\n", hr); - ok(fabsf(vols[0] - 0.2f) < 0.05f, "Channel 0 volume wasn't 0.2: %f\n", vol); - for(i = 1; i < fmt->nChannels; ++i) - ok(vols[i] == 1.f, "Channel %d volume is not 1: %f\n", i, vols[i]); - - hr = IChannelAudioVolume_SetAllVolumes(acv, 0, NULL, NULL); - ok(hr == NULL_PTR_ERR, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetAllVolumes(acv, fmt->nChannels, NULL, NULL); - ok(hr == NULL_PTR_ERR, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetAllVolumes(acv, fmt->nChannels - 1, vols, NULL); - ok(hr == E_INVALIDARG, "SetAllVolumes gave wrong error: %08lx\n", hr); - - hr = IChannelAudioVolume_SetAllVolumes(acv, fmt->nChannels, vols, NULL); - ok(hr == S_OK, "SetAllVolumes failed: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(acv, 0, 1.0f, NULL); - ok(hr == S_OK, "SetChannelVolume failed: %08lx\n", hr); - - HeapFree(GetProcessHeap(), 0, vols); - IChannelAudioVolume_Release(acv); - IAudioClient_Release(ac); - CoTaskMemFree(fmt); -} - -static void test_simplevolume(void) -{ - IAudioClient *ac; - ISimpleAudioVolume *sav; - WAVEFORMATEX *fmt; - HRESULT hr; - float vol; - BOOL mute; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - if(hr == S_OK){ - hr = IAudioClient_GetService(ac, &IID_ISimpleAudioVolume, (void**)&sav); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - } - if(hr != S_OK){ - IAudioClient_Release(ac); - CoTaskMemFree(fmt); - return; - } - - hr = ISimpleAudioVolume_GetMasterVolume(sav, NULL); - ok(hr == NULL_PTR_ERR, "GetMasterVolume gave wrong error: %08lx\n", hr); - - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - ok(vol == 1.f, "Master volume wasn't 1: %f\n", vol); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, -1.f, NULL); - ok(hr == E_INVALIDARG, "SetMasterVolume gave wrong error: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 2.f, NULL); - ok(hr == E_INVALIDARG, "SetMasterVolume gave wrong error: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 0.2f, NULL); - ok(hr == S_OK, "SetMasterVolume failed: %08lx\n", hr); - - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "Master volume wasn't 0.2: %f\n", vol); - - hr = ISimpleAudioVolume_GetMute(sav, NULL); - ok(hr == NULL_PTR_ERR, "GetMute gave wrong error: %08lx\n", hr); - - mute = TRUE; - hr = ISimpleAudioVolume_GetMute(sav, &mute); - ok(hr == S_OK, "GetMute failed: %08lx\n", hr); - ok(mute == FALSE, "Session is already muted\n"); - - hr = ISimpleAudioVolume_SetMute(sav, TRUE, NULL); - ok(hr == S_OK, "SetMute failed: %08lx\n", hr); - - mute = FALSE; - hr = ISimpleAudioVolume_GetMute(sav, &mute); - ok(hr == S_OK, "GetMute failed: %08lx\n", hr); - ok(mute == TRUE, "Session should have been muted\n"); - - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "Master volume wasn't 0.2: %f\n", vol); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 1.f, NULL); - ok(hr == S_OK, "SetMasterVolume failed: %08lx\n", hr); - - mute = FALSE; - hr = ISimpleAudioVolume_GetMute(sav, &mute); - ok(hr == S_OK, "GetMute failed: %08lx\n", hr); - ok(mute == TRUE, "Session should have been muted\n"); - - hr = ISimpleAudioVolume_SetMute(sav, FALSE, NULL); - ok(hr == S_OK, "SetMute failed: %08lx\n", hr); - - ISimpleAudioVolume_Release(sav); - IAudioClient_Release(ac); - CoTaskMemFree(fmt); -} - -static void test_volume_dependence(void) -{ - IAudioClient *ac, *ac2; - ISimpleAudioVolume *sav; - IChannelAudioVolume *cav; - IAudioStreamVolume *asv; - WAVEFORMATEX *fmt; - HRESULT hr; - float vol; - GUID session; - UINT32 nch; - - hr = CoCreateGuid(&session); - ok(hr == S_OK, "CoCreateGuid failed: %08lx\n", hr); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, &session); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - if(hr == S_OK){ - hr = IAudioClient_GetService(ac, &IID_ISimpleAudioVolume, (void**)&sav); - ok(hr == S_OK, "GetService (SimpleAudioVolume) failed: %08lx\n", hr); - } - if(hr != S_OK){ - IAudioClient_Release(ac); - CoTaskMemFree(fmt); - return; - } - - hr = IAudioClient_GetService(ac, &IID_IChannelAudioVolume, (void**)&cav); - ok(hr == S_OK, "GetService (ChannelAudioVolume) failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_IAudioStreamVolume, (void**)&asv); - ok(hr == S_OK, "GetService (AudioStreamVolume) failed: %08lx\n", hr); - - hr = IAudioStreamVolume_SetChannelVolume(asv, 0, 0.2f); - ok(hr == S_OK, "ASV_SetChannelVolume failed: %08lx\n", hr); - - hr = IChannelAudioVolume_SetChannelVolume(cav, 0, 0.4f, NULL); - ok(hr == S_OK, "CAV_SetChannelVolume failed: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 0.6f, NULL); - ok(hr == S_OK, "SAV_SetMasterVolume failed: %08lx\n", hr); - - hr = IAudioStreamVolume_GetChannelVolume(asv, 0, &vol); - ok(hr == S_OK, "ASV_GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.2f) < 0.05f, "ASV_GetChannelVolume gave wrong volume: %f\n", vol); - - hr = IChannelAudioVolume_GetChannelVolume(cav, 0, &vol); - ok(hr == S_OK, "CAV_GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.4f) < 0.05f, "CAV_GetChannelVolume gave wrong volume: %f\n", vol); - - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "SAV_GetMasterVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.6f) < 0.05f, "SAV_GetMasterVolume gave wrong volume: %f\n", vol); - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac2); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - - if(hr == S_OK){ - hr = IAudioClient_Initialize(ac2, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, &session); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - if(hr != S_OK) - IAudioClient_Release(ac2); - } - - if(hr == S_OK){ - IChannelAudioVolume *cav2; - IAudioStreamVolume *asv2; - - hr = IAudioClient_GetService(ac2, &IID_IChannelAudioVolume, (void**)&cav2); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac2, &IID_IAudioStreamVolume, (void**)&asv2); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - - hr = IChannelAudioVolume_GetChannelVolume(cav2, 0, &vol); - ok(hr == S_OK, "CAV_GetChannelVolume failed: %08lx\n", hr); - ok(fabsf(vol - 0.4f) < 0.05f, "CAV_GetChannelVolume gave wrong volume: %f\n", vol); - - hr = IAudioStreamVolume_GetChannelVolume(asv2, 0, &vol); - ok(hr == S_OK, "ASV_GetChannelVolume failed: %08lx\n", hr); - ok(vol == 1.f, "ASV_GetChannelVolume gave wrong volume: %f\n", vol); - - hr = IChannelAudioVolume_GetChannelCount(cav2, &nch); - ok(hr == S_OK, "CAV_GetChannelCount failed: %08lx\n", hr); - ok(nch == fmt->nChannels, "Got wrong channel count, expected %u: %u\n", fmt->nChannels, nch); - - hr = IAudioStreamVolume_GetChannelCount(asv2, &nch); - ok(hr == S_OK, "ASV_GetChannelCount failed: %08lx\n", hr); - ok(nch == fmt->nChannels, "Got wrong channel count, expected %u: %u\n", fmt->nChannels, nch); - - IAudioStreamVolume_Release(asv2); - IChannelAudioVolume_Release(cav2); - IAudioClient_Release(ac2); - }else - skip("Unable to open the same device twice. Skipping session volume control tests\n"); - - hr = IChannelAudioVolume_SetChannelVolume(cav, 0, 1.f, NULL); - ok(hr == S_OK, "CAV_SetChannelVolume failed: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 1.f, NULL); - ok(hr == S_OK, "SAV_SetMasterVolume failed: %08lx\n", hr); - - CoTaskMemFree(fmt); - ISimpleAudioVolume_Release(sav); - IChannelAudioVolume_Release(cav); - IAudioStreamVolume_Release(asv); - IAudioClient_Release(ac); -} - -static void test_session_creation(void) -{ - IMMDevice *cap_dev; - IAudioClient *ac; - IAudioSessionManager *sesm; - ISimpleAudioVolume *sav; - GUID session_guid; - float vol; - HRESULT hr; - WAVEFORMATEX *fmt; - - CoCreateGuid(&session_guid); - - hr = IMMDevice_Activate(dev, &IID_IAudioSessionManager, - CLSCTX_INPROC_SERVER, NULL, (void**)&sesm); - ok((hr == S_OK)^(sesm == NULL), "Activate %08lx &out pointer\n", hr); - ok(hr == S_OK, "Activate failed: %08lx\n", hr); - - hr = IAudioSessionManager_GetSimpleAudioVolume(sesm, &session_guid, - FALSE, &sav); - ok(hr == S_OK, "GetSimpleAudioVolume failed: %08lx\n", hr); - - hr = ISimpleAudioVolume_SetMasterVolume(sav, 0.6f, NULL); - ok(hr == S_OK, "SetMasterVolume failed: %08lx\n", hr); - - /* Release completely to show session persistence */ - ISimpleAudioVolume_Release(sav); - IAudioSessionManager_Release(sesm); - - /* test if we can create a capture audioclient in the session we just - * created from a SessionManager derived from a render device */ - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eCapture, - eMultimedia, &cap_dev); - if(hr == S_OK){ - WAVEFORMATEX *cap_pwfx; - IAudioClient *cap_ac; - ISimpleAudioVolume *cap_sav; - IAudioSessionManager *cap_sesm; - - hr = IMMDevice_Activate(cap_dev, &IID_IAudioSessionManager, - CLSCTX_INPROC_SERVER, NULL, (void**)&cap_sesm); - ok((hr == S_OK)^(cap_sesm == NULL), "Activate %08lx &out pointer\n", hr); - ok(hr == S_OK, "Activate failed: %08lx\n", hr); - - hr = IAudioSessionManager_GetSimpleAudioVolume(cap_sesm, &session_guid, - FALSE, &cap_sav); - ok(hr == S_OK, "GetSimpleAudioVolume failed: %08lx\n", hr); - - vol = 0.5f; - hr = ISimpleAudioVolume_GetMasterVolume(cap_sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - - ISimpleAudioVolume_Release(cap_sav); - IAudioSessionManager_Release(cap_sesm); - - hr = IMMDevice_Activate(cap_dev, &IID_IAudioClient, - CLSCTX_INPROC_SERVER, NULL, (void**)&cap_ac); - ok(hr == S_OK, "Activate failed: %08lx\n", hr); - - IMMDevice_Release(cap_dev); - - hr = IAudioClient_GetMixFormat(cap_ac, &cap_pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(cap_ac, AUDCLNT_SHAREMODE_SHARED, - 0, 5000000, 0, cap_pwfx, &session_guid); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - CoTaskMemFree(cap_pwfx); - - if(hr == S_OK){ - hr = IAudioClient_GetService(cap_ac, &IID_ISimpleAudioVolume, - (void**)&cap_sav); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - } - if(hr == S_OK){ - vol = 0.5f; - hr = ISimpleAudioVolume_GetMasterVolume(cap_sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - - ISimpleAudioVolume_Release(cap_sav); - } - - IAudioClient_Release(cap_ac); - } - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok((hr == S_OK)^(ac == NULL), "Activate %08lx &out pointer\n", hr); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &fmt); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_NOPERSIST, 5000000, 0, fmt, &session_guid); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_ISimpleAudioVolume, (void**)&sav); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - if(hr == S_OK){ - vol = 0.5f; - hr = ISimpleAudioVolume_GetMasterVolume(sav, &vol); - ok(hr == S_OK, "GetMasterVolume failed: %08lx\n", hr); - ok(fabs(vol - 0.6f) < 0.05f, "Got wrong volume: %f\n", vol); - - ISimpleAudioVolume_Release(sav); - } - - CoTaskMemFree(fmt); - IAudioClient_Release(ac); -} - -static void test_worst_case(void) -{ - HANDLE event; - HRESULT hr; - IAudioClient *ac; - IAudioRenderClient *arc; - IAudioClock *acl; - WAVEFORMATEX *pwfx; - REFERENCE_TIME defp; - UINT64 freq, pos, pcpos0, pcpos; - BYTE *data; - DWORD r; - UINT32 pad, fragment, sum; - int i,j; - - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 500000, 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetDevicePeriod(ac, &defp, NULL); - ok(hr == S_OK, "GetDevicePeriod failed: %08lx\n", hr); - - fragment = MulDiv(defp, pwfx->nSamplesPerSec, 10000000); - - event = CreateEventW(NULL, FALSE, FALSE, NULL); - ok(event != NULL, "CreateEvent failed\n"); - - hr = IAudioClient_SetEventHandle(ac, event); - ok(hr == S_OK, "SetEventHandle failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_IAudioRenderClient, (void**)&arc); - ok(hr == S_OK, "GetService(IAudioRenderClient) failed: %08lx\n", hr); - - hr = IAudioClient_GetService(ac, &IID_IAudioClock, (void**)&acl); - ok(hr == S_OK, "GetService(IAudioClock) failed: %08lx\n", hr); - - hr = IAudioClock_GetFrequency(acl, &freq); - ok(hr == S_OK, "GetFrequency failed: %08lx\n", hr); - - for(j = 0; j <= (winetest_interactive ? 9 : 2); j++){ - sum = 0; - trace("Should play %lums continuous tone with fragment size %u.\n", - (ULONG)(defp/100), fragment); - - hr = IAudioClock_GetPosition(acl, &pos, &pcpos0); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - - /* XAudio2 prefills one period, play without it */ - if(winetest_debug>2){ - hr = IAudioRenderClient_GetBuffer(arc, fragment, &data); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - - hr = IAudioRenderClient_ReleaseBuffer(arc, fragment, AUDCLNT_BUFFERFLAGS_SILENT); - ok(hr == S_OK, "ReleaseBuffer failed: %08lx\n", hr); - if(hr == S_OK) - sum += fragment; - } - - hr = IAudioClient_Start(ac); - ok(hr == S_OK, "Start failed: %08lx\n", hr); - - for(i = 0; i <= 99; i++){ /* 100 x 10ms = 1 second */ - r = WaitForSingleObject(event, 60 + defp / 10000); - flaky_wine - ok(r == WAIT_OBJECT_0, "Wait iteration %d gave %lx\n", i, r); - - /* the app has nearly one period time to feed data */ - Sleep((i % 10) * defp / 120000); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - - /* XAudio2 writes only when there's little data left */ - if(pad <= fragment){ - hr = IAudioRenderClient_GetBuffer(arc, fragment, &data); - ok(hr == S_OK, "GetBuffer failed: %08lx\n", hr); - - hr = IAudioRenderClient_ReleaseBuffer(arc, fragment, - wave_generate_tone(pwfx, data, fragment)); - ok(hr == S_OK, "ReleaseBuffer failed: %08lx\n", hr); - if(hr == S_OK) - sum += fragment; - } - } - - hr = IAudioClient_Stop(ac); - ok(hr == S_OK, "Stop failed: %08lx\n", hr); - - hr = IAudioClient_GetCurrentPadding(ac, &pad); - ok(hr == S_OK, "GetCurrentPadding failed: %08lx\n", hr); - - hr = IAudioClock_GetPosition(acl, &pos, &pcpos); - ok(hr == S_OK, "GetPosition failed: %08lx\n", hr); - - Sleep(100); - - trace("Released %u=%ux%u -%u frames at %lu worth %ums in %lums\n", - sum, sum/fragment, fragment, pad, - pwfx->nSamplesPerSec, MulDiv(sum-pad, 1000, pwfx->nSamplesPerSec), - (ULONG)((pcpos-pcpos0)/10000)); - - ok(pos * pwfx->nSamplesPerSec == (sum-pad) * freq, - "Position %u at end vs. %u-%u submitted frames\n", (UINT)pos, sum, pad); - - hr = IAudioClient_Reset(ac); - ok(hr == S_OK, "Reset failed: %08lx\n", hr); - - Sleep(250); - } - - CoTaskMemFree(pwfx); - IAudioClient_Release(ac); - IAudioClock_Release(acl); - IAudioRenderClient_Release(arc); -} - -static void test_marshal(void) -{ - IStream *pStream; - IAudioClient *ac, *acDest; - IAudioRenderClient *rc, *rcDest; - WAVEFORMATEX *pwfx; - HRESULT hr; - - /* IAudioRenderClient */ - hr = IMMDevice_Activate(dev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, - NULL, (void**)&ac); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioClient_GetMixFormat(ac, &pwfx); - ok(hr == S_OK, "GetMixFormat failed: %08lx\n", hr); - - hr = IAudioClient_Initialize(ac, AUDCLNT_SHAREMODE_SHARED, 0, 5000000, - 0, pwfx, NULL); - ok(hr == S_OK, "Initialize failed: %08lx\n", hr); - - CoTaskMemFree(pwfx); - - hr = IAudioClient_GetService(ac, &IID_IAudioRenderClient, (void**)&rc); - ok(hr == S_OK, "GetService failed: %08lx\n", hr); - if(hr != S_OK) { - IAudioClient_Release(ac); - return; - } - - hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream); - ok(hr == S_OK, "CreateStreamOnHGlobal failed 0x%08lx\n", hr); - - /* marshal IAudioClient */ - - hr = CoMarshalInterface(pStream, &IID_IAudioClient, (IUnknown*)ac, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); - ok(hr == S_OK, "CoMarshalInterface IAudioClient failed 0x%08lx\n", hr); - - IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - hr = CoUnmarshalInterface(pStream, &IID_IAudioClient, (void **)&acDest); - ok(hr == S_OK, "CoUnmarshalInterface IAudioClient failed 0x%08lx\n", hr); - if (hr == S_OK) - IAudioClient_Release(acDest); - - IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - /* marshal IAudioRenderClient */ - - hr = CoMarshalInterface(pStream, &IID_IAudioRenderClient, (IUnknown*)rc, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); - ok(hr == S_OK, "CoMarshalInterface IAudioRenderClient failed 0x%08lx\n", hr); - - IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL); - hr = CoUnmarshalInterface(pStream, &IID_IAudioRenderClient, (void **)&rcDest); - ok(hr == S_OK, "CoUnmarshalInterface IAudioRenderClient failed 0x%08lx\n", hr); - if (hr == S_OK) - IAudioRenderClient_Release(rcDest); - - - IStream_Release(pStream); - - IAudioClient_Release(ac); - IAudioRenderClient_Release(rc); - -} - -static void test_endpointvolume(void) -{ - HRESULT hr; - IAudioEndpointVolume *aev; - float mindb, maxdb, increment, volume; - BOOL mute; - - hr = IMMDevice_Activate(dev, &IID_IAudioEndpointVolume, - CLSCTX_INPROC_SERVER, NULL, (void**)&aev); - ok(hr == S_OK, "Activation failed with %08lx\n", hr); - if(hr != S_OK) - return; - - hr = IAudioEndpointVolume_GetVolumeRange(aev, &mindb, NULL, NULL); - ok(hr == E_POINTER, "GetVolumeRange should have failed with E_POINTER: 0x%08lx\n", hr); - - hr = IAudioEndpointVolume_GetVolumeRange(aev, &mindb, &maxdb, &increment); - ok(hr == S_OK, "GetVolumeRange failed: 0x%08lx\n", hr); - trace("got range: [%f,%f]/%f\n", mindb, maxdb, increment); - - hr = IAudioEndpointVolume_SetMasterVolumeLevel(aev, mindb - increment, NULL); - ok(hr == E_INVALIDARG, "SetMasterVolumeLevel failed: 0x%08lx\n", hr); - - hr = IAudioEndpointVolume_GetMasterVolumeLevel(aev, &volume); - ok(hr == S_OK, "GetMasterVolumeLevel failed: 0x%08lx\n", hr); - - hr = IAudioEndpointVolume_SetMasterVolumeLevel(aev, volume, NULL); - ok(hr == S_OK, "SetMasterVolumeLevel failed: 0x%08lx\n", hr); - - hr = IAudioEndpointVolume_GetMute(aev, &mute); - ok(hr == S_OK, "GetMute failed: %08lx\n", hr); - - hr = IAudioEndpointVolume_SetMute(aev, mute, NULL); - ok(hr == S_OK || hr == S_FALSE, "SetMute failed: %08lx\n", hr); - - IAudioEndpointVolume_Release(aev); -} - -START_TEST(render) -{ - HRESULT hr; - DWORD mode; - - CoInitializeEx(NULL, COINIT_MULTITHREADED); - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); - if (FAILED(hr)) - { - skip("mmdevapi not available: 0x%08lx\n", hr); - goto cleanup; - } - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eRender, eMultimedia, &dev); - ok(hr == S_OK || hr == E_NOTFOUND, "GetDefaultAudioEndpoint failed: 0x%08lx\n", hr); - if (hr != S_OK || !dev) - { - if (hr == E_NOTFOUND) - skip("No sound card available\n"); - else - skip("GetDefaultAudioEndpoint returns 0x%08lx\n", hr); - goto cleanup; - } - - test_audioclient(); - test_formats(AUDCLNT_SHAREMODE_EXCLUSIVE); - test_formats(AUDCLNT_SHAREMODE_SHARED); - test_references(); - test_marshal(); - if (GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode)) - { - trace("Output to a MS-DOS console is particularly slow and disturbs timing.\n"); - trace("Please redirect output to a file.\n"); - } - test_event(); - test_padding(); - test_clock(1); - test_clock(0); - test_session(); - test_streamvolume(); - test_channelvolume(); - test_simplevolume(); - test_volume_dependence(); - test_session_creation(); - test_worst_case(); - test_endpointvolume(); - - IMMDevice_Release(dev); - -cleanup: - if (mme) - IMMDeviceEnumerator_Release(mme); - CoUninitialize(); -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/tests/spatialaudio.c b/pkgs/osu-wine/audio-revert/mmdevapi/tests/spatialaudio.c deleted file mode 100644 index a382b57..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/tests/spatialaudio.c +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright 2021 Arkadiusz Hiler for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include - -#include "wine/test.h" - -#define COBJMACROS - -#ifdef STANDALONE -#include "initguid.h" -#endif - -#include "mmdeviceapi.h" -#include "spatialaudioclient.h" -#include "mmsystem.h" - -static IMMDeviceEnumerator *mme = NULL; -static IMMDevice *dev = NULL; -static ISpatialAudioClient *sac = NULL; -static UINT32 max_dyn_count; -static HANDLE event; -static WAVEFORMATEX format; - -static void test_formats(void) -{ - HRESULT hr; - IAudioFormatEnumerator *afe; - UINT32 format_count = 0; - WAVEFORMATEX *fmt = NULL; - - hr = ISpatialAudioClient_GetSupportedAudioObjectFormatEnumerator(sac, &afe); - ok(hr == S_OK, "Getting format enumerator failed: 0x%08lx\n", hr); - - hr = IAudioFormatEnumerator_GetCount(afe, &format_count); - ok(hr == S_OK, "Getting format count failed: 0x%08lx\n", hr); - ok(format_count == 1, "Got wrong format count, expected 1 got %u\n", format_count); - - hr = IAudioFormatEnumerator_GetFormat(afe, 0, &fmt); - ok(hr == S_OK, "Getting format failed: 0x%08lx\n", hr); - ok(fmt != NULL, "Expected to get non-NULL format\n"); - - ok(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT, "Wrong format, expected WAVE_FORMAT_IEEE_FLOAT got %hx\n", fmt->wFormatTag); - ok(fmt->nChannels == 1, "Wrong number of channels, expected 1 got %hu\n", fmt->nChannels); - ok(fmt->nSamplesPerSec == 48000, "Wrong sample ret, expected 48000 got %lu\n", fmt->nSamplesPerSec); - ok(fmt->wBitsPerSample == 32, "Wrong bits per sample, expected 32 got %hu\n", fmt->wBitsPerSample); - ok(fmt->nBlockAlign == 4, "Wrong block align, expected 4 got %hu\n", fmt->nBlockAlign); - ok(fmt->nAvgBytesPerSec == 192000, "Wrong avg bytes per sec, expected 192000 got %lu\n", fmt->nAvgBytesPerSec); - ok(fmt->cbSize == 0, "Wrong cbSize for simple format, expected 0, got %hu\n", fmt->cbSize); - - memcpy(&format, fmt, sizeof(format)); - - IAudioFormatEnumerator_Release(afe); -} - -static void fill_activation_params(SpatialAudioObjectRenderStreamActivationParams *activation_params) -{ - activation_params->StaticObjectTypeMask = \ - AudioObjectType_FrontLeft | - AudioObjectType_FrontRight | - AudioObjectType_FrontCenter | - AudioObjectType_LowFrequency | - AudioObjectType_SideLeft | - AudioObjectType_SideRight | - AudioObjectType_BackLeft | - AudioObjectType_BackRight | - AudioObjectType_TopFrontLeft | - AudioObjectType_TopFrontRight | - AudioObjectType_TopBackLeft | - AudioObjectType_TopBackRight; - - activation_params->MinDynamicObjectCount = 0; - activation_params->MaxDynamicObjectCount = 0; - activation_params->Category = AudioCategory_GameEffects; - activation_params->EventHandle = event; - activation_params->NotifyObject = NULL; - - activation_params->ObjectFormat = &format; -} - -typedef struct NotifyObject -{ - ISpatialAudioObjectRenderStreamNotify ISpatialAudioObjectRenderStreamNotify_iface; - LONG ref; -} NotifyObject; - -static WINAPI HRESULT notifyobj_QueryInterface( - ISpatialAudioObjectRenderStreamNotify *This, - REFIID riid, - void **ppvObject) -{ - return S_OK; -} - -static WINAPI ULONG notifyobj_AddRef( - ISpatialAudioObjectRenderStreamNotify *This) -{ - NotifyObject *obj = CONTAINING_RECORD(This, NotifyObject, ISpatialAudioObjectRenderStreamNotify_iface); - ULONG ref = InterlockedIncrement(&obj->ref); - return ref; -} - -static WINAPI ULONG notifyobj_Release( - ISpatialAudioObjectRenderStreamNotify *This) -{ - NotifyObject *obj = CONTAINING_RECORD(This, NotifyObject, ISpatialAudioObjectRenderStreamNotify_iface); - ULONG ref = InterlockedDecrement(&obj->ref); - return ref; -} - -static WINAPI HRESULT notifyobj_OnAvailableDynamicObjectCountChange( - ISpatialAudioObjectRenderStreamNotify *This, - ISpatialAudioObjectRenderStreamBase *stream, - LONGLONG deadline, - UINT32 object_count) -{ - ok(FALSE, "Expected to never be notified of dynamic object count change\n"); - return S_OK; -} - -static const ISpatialAudioObjectRenderStreamNotifyVtbl notifyobjvtbl = -{ - notifyobj_QueryInterface, - notifyobj_AddRef, - notifyobj_Release, - notifyobj_OnAvailableDynamicObjectCountChange -}; - -static void test_stream_activation(void) -{ - HRESULT hr; - WAVEFORMATEX wrong_format; - ISpatialAudioObjectRenderStream *sas = NULL; - - SpatialAudioObjectRenderStreamActivationParams activation_params; - PROPVARIANT activation_params_prop; - NotifyObject notify_object; - - PropVariantInit(&activation_params_prop); - activation_params_prop.vt = VT_BLOB; - activation_params_prop.blob.cbSize = sizeof(activation_params); - activation_params_prop.blob.pBlobData = (BYTE*) &activation_params; - - /* correct params */ - fill_activation_params(&activation_params); - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08lx\n", hr); - ok(ISpatialAudioObjectRenderStream_Release(sas) == 0, "Expected to release the last reference\n"); - - /* event handle */ - fill_activation_params(&activation_params); - activation_params.EventHandle = NULL; - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - ok(hr == E_INVALIDARG, "Expected lack of no EventHandle to be invalid: 0x%08lx\n", hr); - ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n"); - - activation_params.EventHandle = INVALID_HANDLE_VALUE; - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - ok(hr == E_INVALIDARG, "Expected INVALID_HANDLE_VALUE to be invalid: 0x%08lx\n", hr); - ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n"); - - /* must use only queried sample rate */ - fill_activation_params(&activation_params); - memcpy(&wrong_format, &format, sizeof(format)); - activation_params.ObjectFormat = &wrong_format; - wrong_format.nSamplesPerSec = 44100; - wrong_format.nAvgBytesPerSec = wrong_format.nSamplesPerSec * wrong_format.nBlockAlign; - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "Expected format to be unsupported: 0x%08lx\n", hr); - ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n"); - - /* dynamic objects are not supported */ - if (max_dyn_count == 0) - { - fill_activation_params(&activation_params); - activation_params.StaticObjectTypeMask |= AudioObjectType_Dynamic; - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - ok(hr == E_INVALIDARG, "Expected dynamic objects type be invalid: 0x%08lx\n", hr); - ok(sas == NULL, "Expected spatial audio stream to be set to NULL upon failed activation\n"); - } - - activation_params.MinDynamicObjectCount = max_dyn_count + 1; - activation_params.MaxDynamicObjectCount = max_dyn_count + 1; - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - if (max_dyn_count) - ok(hr == AUDCLNT_E_UNSUPPORTED_FORMAT, "Expected dynamic object count exceeding max to be unsupported: 0x%08lx\n", hr); - else - ok(hr == E_INVALIDARG, "Expected setting dynamic object count to be invalid: 0x%08lx\n", hr); - - /* ISpatialAudioObjectRenderStreamNotify */ - fill_activation_params(&activation_params); - notify_object.ISpatialAudioObjectRenderStreamNotify_iface.lpVtbl = ¬ifyobjvtbl; - notify_object.ref = 0; - activation_params.NotifyObject = ¬ify_object.ISpatialAudioObjectRenderStreamNotify_iface; - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08lx\n", hr); - ok(notify_object.ref == 1, "Expected to get increased NotifyObject's ref count\n"); - ok(ISpatialAudioObjectRenderStream_Release(sas) == 0, "Expected to release the last reference\n"); - ok(notify_object.ref == 0, "Expected to get lowered NotifyObject's ref count\n"); -} - -static void test_audio_object_activation(void) -{ - HRESULT hr; - BOOL is_active; - ISpatialAudioObjectRenderStream *sas = NULL; - ISpatialAudioObject *sao1, *sao2; - - SpatialAudioObjectRenderStreamActivationParams activation_params; - PROPVARIANT activation_params_prop; - - PropVariantInit(&activation_params_prop); - activation_params_prop.vt = VT_BLOB; - activation_params_prop.blob.cbSize = sizeof(activation_params); - activation_params_prop.blob.pBlobData = (BYTE*) &activation_params; - - fill_activation_params(&activation_params); - activation_params.StaticObjectTypeMask &= ~AudioObjectType_FrontRight; - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao1); - ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08lx\n", hr); - hr = ISpatialAudioObject_IsActive(sao1, &is_active); - todo_wine ok(hr == S_OK, "Failed to check if spatial audio object is active: 0x%08lx\n", hr); - if (hr == S_OK) - ok(is_active, "Expected spatial audio object to be active\n"); - - hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao2); - ok(hr == SPTLAUDCLNT_E_OBJECT_ALREADY_ACTIVE, "Expected audio object to be already active: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontRight, &sao2); - ok(hr == SPTLAUDCLNT_E_STATIC_OBJECT_NOT_AVAILABLE, "Expected static object to be not available: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_Dynamic, &sao2); - ok(hr == SPTLAUDCLNT_E_NO_MORE_OBJECTS, "Expected to not have no more dynamic objects: 0x%08lx\n", hr); - - ISpatialAudioObject_Release(sao1); - ISpatialAudioObjectRenderStream_Release(sas); -} - -static BOOL is_buffer_zeroed(const BYTE *buffer, UINT32 buffer_length) -{ - UINT32 i; - - for (i = 0; i < buffer_length; i++) - { - if (buffer[i] != 0) - return FALSE; - } - - return TRUE; -} - -static void test_audio_object_buffers(void) -{ - UINT32 dyn_object_count, frame_count, max_frame_count, buffer_length; - SpatialAudioObjectRenderStreamActivationParams activation_params; - ISpatialAudioObjectRenderStream *sas = NULL; - PROPVARIANT activation_params_prop; - ISpatialAudioObject *sao[4]; - BYTE *buffer; - INT i, j, k; - HRESULT hr; - - PropVariantInit(&activation_params_prop); - activation_params_prop.vt = VT_BLOB; - activation_params_prop.blob.cbSize = sizeof(activation_params); - activation_params_prop.blob.pBlobData = (BYTE*) &activation_params; - - fill_activation_params(&activation_params); - hr = ISpatialAudioClient_ActivateSpatialAudioStream(sac, &activation_params_prop, &IID_ISpatialAudioObjectRenderStream, (void**)&sas); - ok(hr == S_OK, "Failed to activate spatial audio stream: 0x%08lx\n", hr); - - hr = ISpatialAudioClient_GetMaxFrameCount(sac, &format, &max_frame_count); - ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); - frame_count = format.nSamplesPerSec / 100; /* 10ms */ - /* Most of the time the frame count matches the 10ms interval exactly. - * However (seen on some Testbot machines) it might be a bit higher for some reason. */ - ok(max_frame_count <= frame_count + frame_count / 4, "Got unexpected frame count %u.\n", frame_count); - - /* The tests below which check frame count from _BeginUpdatingAudioObjects fail on some Testbot machines - * with max_frame_count from _GetMaxFrameCount(). */ - max_frame_count = frame_count + frame_count / 4; - - hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontLeft, &sao[0]); - ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_Start(sas); - ok(hr == S_OK, "Failed to activate spatial audio render stream: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_FrontRight, &sao[1]); - ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08lx\n", hr); - - hr = WaitForSingleObject(event, 200); - ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideLeft, &sao[2]); - ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count); - ok(hr == S_OK, "Failed to begin updating audio objects: 0x%08lx\n", hr); - ok(dyn_object_count == 0, "Unexpected dynamic objects\n"); - ok(frame_count <= max_frame_count, "Got unexpected frame count %u.\n", frame_count); - - hr = ISpatialAudioObjectRenderStream_ActivateSpatialAudioObject(sas, AudioObjectType_SideRight, &sao[3]); - ok(hr == S_OK, "Failed to activate spatial audio object: 0x%08lx\n", hr); - - for (i = 0; i < ARRAYSIZE(sao); i++) - { - hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length); - ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08lx\n", hr); - ok(buffer != NULL, "Expected to get a non-NULL buffer\n"); - ok(buffer_length == frame_count * format.wBitsPerSample / 8, "Expected buffer length to be sample_size * frame_count = %hu but got %u\n", - frame_count * format.wBitsPerSample / 8, buffer_length); - ok(is_buffer_zeroed(buffer, buffer_length), "Expected audio object's buffer to be zeroed\n"); - } - - hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas); - ok(hr == S_OK, "Failed to end updating audio objects: 0x%08lx\n", hr); - - /* Emulate underrun and test frame count approximate limit. */ - - /* Force 1ms Sleep() timer resolution. */ - timeBeginPeriod(1); - for (j = 0; j < 20; ++j) - { - hr = WaitForSingleObject(event, 200); - ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08lx, j %u.\n", hr, j); - - hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count); - ok(hr == S_OK, "Failed to begin updating audio objects: 0x%08lx\n", hr); - ok(dyn_object_count == 0, "Unexpected dynamic objects\n"); - ok(frame_count <= max_frame_count, "Got unexpected frame_count %u.\n", frame_count); - - /* Audio starts crackling with delays 10ms and above. However, setting such delay (that is, the delay - * which skips the whole quantum) breaks SA on some Testbot machines: _BeginUpdatingAudioObjects fails - * with SPTLAUDCLNT_E_INTERNAL starting from some iteration or WaitForSingleObject timeouts. That seems - * to work on the real hardware though. */ - Sleep(5); - - for (i = 0; i < ARRAYSIZE(sao); i++) - { - hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length); - ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08lx, i %d\n", hr, i); - ok(buffer != NULL, "Expected to get a non-NULL buffer\n"); - ok(buffer_length == frame_count * format.wBitsPerSample / 8, - "Expected buffer length to be sample_size * frame_count = %hu but got %u\n", - frame_count * format.wBitsPerSample / 8, buffer_length); - - /* Enable to hear the test sound. */ - if (0) - { - if (format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - { - for (k = 0; k < frame_count; ++k) - { - float time_sec = 10.0f / 1000.0f * (j + (float)k / frame_count); - - /* 440Hz tone. */ - ((float *)buffer)[k] = sinf(2.0f * M_PI * time_sec * 440.0f); - } - } - } - } - hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas); - ok(hr == S_OK, "Failed to end updating audio objects: 0x%08lx\n", hr); - } - timeEndPeriod(1); - - hr = WaitForSingleObject(event, 200); - ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count); - ok(hr == S_OK, "Failed to begin updating audio objects: 0x%08lx\n", hr); - ok(dyn_object_count == 0, "Unexpected dynamic objects\n"); - - /* one more iteration but not with every object */ - for (i = 0; i < ARRAYSIZE(sao) - 1; i++) - { - hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length); - ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08lx\n", hr); - ok(buffer != NULL, "Expected to get a non-NULL buffer\n"); - ok(buffer_length == frame_count * format.wBitsPerSample / 8, "Expected buffer length to be sample_size * frame_count = %hu but got %u\n", - frame_count * format.wBitsPerSample / 8, buffer_length); - ok(is_buffer_zeroed(buffer, buffer_length), "Expected audio object's buffer to be zeroed\n"); - } - - hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas); - ok(hr == S_OK, "Failed to end updating audio objects: 0x%08lx\n", hr); - - /* ending the stream */ - hr = ISpatialAudioObject_SetEndOfStream(sao[0], 0); - todo_wine ok(hr == SPTLAUDCLNT_E_OUT_OF_ORDER, "Expected that ending the stream at this point won't be allowed: 0x%08lx\n", hr); - - hr = WaitForSingleObject(event, 200); - ok(hr == WAIT_OBJECT_0, "Expected event to be flagged: 0x%08lx\n", hr); - - hr = ISpatialAudioObject_SetEndOfStream(sao[0], 0); - todo_wine ok(hr == SPTLAUDCLNT_E_OUT_OF_ORDER, "Expected that ending the stream at this point won't be allowed: 0x%08lx\n", hr); - - hr = ISpatialAudioObjectRenderStream_BeginUpdatingAudioObjects(sas, &dyn_object_count, &frame_count); - ok(hr == S_OK, "Failed to begin updating audio objects: 0x%08lx\n", hr); - ok(dyn_object_count == 0, "Unexpected dynamic objects\n"); - - /* expect the object that was not updated last cycle to be invalidated */ - hr = ISpatialAudioObject_GetBuffer(sao[ARRAYSIZE(sao) - 1], &buffer, &buffer_length); - todo_wine ok(hr == SPTLAUDCLNT_E_RESOURCES_INVALIDATED, "Expected audio object to be invalidated: 0x%08lx\n", hr); - - for (i = 0; i < ARRAYSIZE(sao) - 1; i++) - { - hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length); - ok(hr == S_OK, "Expected to be able to get buffers for audio object: 0x%08lx\n", hr); - - hr = ISpatialAudioObject_SetEndOfStream(sao[i], 0); - todo_wine ok(hr == S_OK, "Failed to end the stream: 0x%08lx\n", hr); - - hr = ISpatialAudioObject_GetBuffer(sao[i], &buffer, &buffer_length); - todo_wine ok(hr == SPTLAUDCLNT_E_RESOURCES_INVALIDATED, "Expected audio object to be invalidated: 0x%08lx\n", hr); - } - - hr = ISpatialAudioObjectRenderStream_EndUpdatingAudioObjects(sas); - ok(hr == S_OK, "Failed to end updating audio objects: 0x%08lx\n", hr); - - for (i = 0; i < ARRAYSIZE(sao); i++) - { - ISpatialAudioObject_Release(sao[i]); - } - - ISpatialAudioObjectRenderStream_Release(sas); -} - -START_TEST(spatialaudio) -{ - HRESULT hr; - - event = CreateEventA(NULL, FALSE, FALSE, "spatial-audio-test-prog-event"); - ok(event != NULL, "Failed to create event, last error: 0x%08lx\n", GetLastError()); - - CoInitializeEx(NULL, COINIT_MULTITHREADED); - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, (void**)&mme); - if (FAILED(hr)) - { - skip("mmdevapi not available: 0x%08lx\n", hr); - goto cleanup; - } - - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(mme, eRender, eMultimedia, &dev); - ok(hr == S_OK || hr == E_NOTFOUND, "GetDefaultAudioEndpoint failed: 0x%08lx\n", hr); - if (hr != S_OK || !dev) - { - if (hr == E_NOTFOUND) - skip("No sound card available\n"); - else - skip("GetDefaultAudioEndpoint returns 0x%08lx\n", hr); - goto cleanup; - } - - hr = IMMDevice_Activate(dev, &IID_ISpatialAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&sac); - ok(hr == S_OK || hr == E_NOINTERFACE, "ISpatialAudioClient Activation failed: 0x%08lx\n", hr); - if (hr != S_OK || !dev) - { - if (hr == E_NOINTERFACE) - skip("ISpatialAudioClient interface not found\n"); - else - skip("ISpatialAudioClient Activation returns 0x%08lx\n", hr); - goto cleanup; - } - - hr = ISpatialAudioClient_GetMaxDynamicObjectCount(sac, &max_dyn_count); - ok(hr == S_OK, "Failed to get max dynamic object count: 0x%08lx\n", hr); - - /* that's the default, after manually enabling Windows Sonic it's possible to have max_dyn_count > 0 */ - /* ok(max_dyn_count == 0, "expected max dynamic object count to be 0 got %u\n", max_dyn_count); */ - - test_formats(); - test_stream_activation(); - test_audio_object_activation(); - test_audio_object_buffers(); - - ISpatialAudioClient_Release(sac); - -cleanup: - if (dev) - IMMDevice_Release(dev); - if (mme) - IMMDeviceEnumerator_Release(mme); - CoUninitialize(); - CloseHandle(event); -} diff --git a/pkgs/osu-wine/audio-revert/mmdevapi/unixlib.h b/pkgs/osu-wine/audio-revert/mmdevapi/unixlib.h deleted file mode 100644 index ea0d2f9..0000000 --- a/pkgs/osu-wine/audio-revert/mmdevapi/unixlib.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2021 Jacek Caban for CodeWeavers - * Copyright 2021-2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "audioclient.h" -#include "mmdeviceapi.h" - -typedef UINT64 stream_handle; - -enum driver_priority -{ - Priority_Unavailable = 0, /* driver won't work */ - Priority_Low, /* driver may work, but unlikely */ - Priority_Neutral, /* driver makes no judgment */ - Priority_Preferred /* driver thinks it's correct */ -}; - -struct endpoint -{ - unsigned int name; - unsigned int device; -}; - -struct main_loop_params -{ - HANDLE event; -}; - -struct get_endpoint_ids_params -{ - EDataFlow flow; - struct endpoint *endpoints; - unsigned int size; - HRESULT result; - unsigned int num; - unsigned int default_idx; -}; - -struct create_stream_params -{ - const char *name; - const char *device; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - DWORD flags; - REFERENCE_TIME duration; - REFERENCE_TIME period; - const WAVEFORMATEX *fmt; - HRESULT result; - UINT32 *channel_count; - stream_handle *stream; -}; - -struct release_stream_params -{ - stream_handle stream; - HANDLE timer_thread; - HRESULT result; -}; - -struct start_params -{ - stream_handle stream; - HRESULT result; -}; - -struct stop_params -{ - stream_handle stream; - HRESULT result; -}; - -struct reset_params -{ - stream_handle stream; - HRESULT result; -}; - -struct timer_loop_params -{ - stream_handle stream; -}; - -struct get_render_buffer_params -{ - stream_handle stream; - UINT32 frames; - HRESULT result; - BYTE **data; -}; - -struct release_render_buffer_params -{ - stream_handle stream; - UINT32 written_frames; - UINT flags; - HRESULT result; -}; - -struct get_capture_buffer_params -{ - stream_handle stream; - HRESULT result; - BYTE **data; - UINT32 *frames; - UINT *flags; - UINT64 *devpos; - UINT64 *qpcpos; -}; - -struct release_capture_buffer_params -{ - stream_handle stream; - UINT32 done; - HRESULT result; -}; - -struct is_format_supported_params -{ - const char *device; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - const WAVEFORMATEX *fmt_in; - WAVEFORMATEXTENSIBLE *fmt_out; - HRESULT result; -}; - -struct get_mix_format_params -{ - const char *device; - EDataFlow flow; - WAVEFORMATEXTENSIBLE *fmt; - HRESULT result; -}; - -struct get_device_period_params -{ - const char *device; - EDataFlow flow; - HRESULT result; - REFERENCE_TIME *def_period; - REFERENCE_TIME *min_period; -}; - -struct get_buffer_size_params -{ - stream_handle stream; - HRESULT result; - UINT32 *frames; -}; - -struct get_latency_params -{ - stream_handle stream; - HRESULT result; - REFERENCE_TIME *latency; -}; - -struct get_current_padding_params -{ - stream_handle stream; - HRESULT result; - UINT32 *padding; -}; - -struct get_next_packet_size_params -{ - stream_handle stream; - HRESULT result; - UINT32 *frames; -}; - -struct get_frequency_params -{ - stream_handle stream; - HRESULT result; - UINT64 *freq; -}; - -struct get_position_params -{ - stream_handle stream; - BOOL device; - HRESULT result; - UINT64 *pos; - UINT64 *qpctime; -}; - -struct set_volumes_params -{ - stream_handle stream; - float master_volume; - const float *volumes; - const float *session_volumes; - int channel; -}; - -struct set_event_handle_params -{ - stream_handle stream; - HANDLE event; - HRESULT result; -}; - -struct test_connect_params -{ - const char *name; - enum driver_priority priority; -}; - -struct is_started_params -{ - stream_handle stream; - HRESULT result; -}; - -struct get_prop_value_params -{ - const char *device; - EDataFlow flow; - const GUID *guid; - const PROPERTYKEY *prop; - HRESULT result; - PROPVARIANT *value; - void *buffer; /* caller allocated buffer to hold value's strings */ - unsigned int *buffer_size; -}; - -struct midi_init_params -{ - UINT *err; -}; - -struct notify_context -{ - BOOL send_notify; - WORD dev_id; - WORD msg; - UINT_PTR param_1; - UINT_PTR param_2; - UINT_PTR callback; - UINT flags; - HANDLE device; - UINT_PTR instance; -}; - -struct midi_out_message_params -{ - UINT dev_id; - UINT msg; - UINT_PTR user; - UINT_PTR param_1; - UINT_PTR param_2; - UINT *err; - struct notify_context *notify; -}; - -struct midi_in_message_params -{ - UINT dev_id; - UINT msg; - UINT_PTR user; - UINT_PTR param_1; - UINT_PTR param_2; - UINT *err; - struct notify_context *notify; -}; - -struct midi_notify_wait_params -{ - BOOL *quit; - struct notify_context *notify; -}; - -struct aux_message_params -{ - UINT dev_id; - UINT msg; - UINT_PTR user; - UINT_PTR param_1; - UINT_PTR param_2; - UINT *err; -}; - -enum unix_funcs -{ - process_attach, - process_detach, - main_loop, - get_endpoint_ids, - create_stream, - release_stream, - start, - stop, - reset, - timer_loop, - get_render_buffer, - release_render_buffer, - get_capture_buffer, - release_capture_buffer, - is_format_supported, - get_mix_format, - get_device_period, - get_buffer_size, - get_latency, - get_current_padding, - get_next_packet_size, - get_frequency, - get_position, - set_volumes, - set_event_handle, - test_connect, - is_started, - get_prop_value, - midi_init, - midi_release, - midi_out_message, - midi_in_message, - midi_notify_wait, - aux_message, -}; diff --git a/pkgs/osu-wine/audio-revert/winealsa.drv/Makefile.in b/pkgs/osu-wine/audio-revert/winealsa.drv/Makefile.in deleted file mode 100644 index 7c84f69..0000000 --- a/pkgs/osu-wine/audio-revert/winealsa.drv/Makefile.in +++ /dev/null @@ -1,11 +0,0 @@ -MODULE = winealsa.drv -UNIXLIB = winealsa.so -IMPORTS = uuid ole32 advapi32 -DELAYIMPORTS = winmm -UNIX_LIBS = $(ALSA_LIBS) $(PTHREAD_LIBS) - -SOURCES = \ - alsa.c \ - alsamidi.c \ - midi.c \ - mmdevdrv.c diff --git a/pkgs/osu-wine/audio-revert/winealsa.drv/alsa.c b/pkgs/osu-wine/audio-revert/winealsa.drv/alsa.c deleted file mode 100644 index ddc5b37..0000000 --- a/pkgs/osu-wine/audio-revert/winealsa.drv/alsa.c +++ /dev/null @@ -1,2899 +0,0 @@ -/* - * Copyright 2010 Maarten Lankhorst for CodeWeavers - * Copyright 2011 Andrew Eikum for CodeWeavers - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#if 0 -#pragma makedep unix -#endif - -#include "config.h" - -#include -#include -#include - -#include - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winternl.h" -#include "initguid.h" -#include "mmdeviceapi.h" - -#include "wine/debug.h" -#include "wine/list.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(alsa); - -struct alsa_stream -{ - snd_pcm_t *pcm_handle; - snd_pcm_uframes_t alsa_bufsize_frames, alsa_period_frames, safe_rewind_frames; - snd_pcm_hw_params_t *hw_params; /* does not hold state between calls */ - snd_pcm_format_t alsa_format; - - LARGE_INTEGER last_period_time; - - WAVEFORMATEX *fmt; - DWORD flags; - AUDCLNT_SHAREMODE share; - EDataFlow flow; - HANDLE event; - - BOOL need_remapping; - int alsa_channels; - int alsa_channel_map[32]; - - BOOL started, please_quit; - REFERENCE_TIME mmdev_period_rt; - UINT64 written_frames, last_pos_frames; - UINT32 bufsize_frames, held_frames, tmp_buffer_frames, mmdev_period_frames; - snd_pcm_uframes_t remapping_buf_frames; - UINT32 lcl_offs_frames; /* offs into local_buffer where valid data starts */ - UINT32 wri_offs_frames; /* where to write fresh data in local_buffer */ - UINT32 hidden_frames; /* ALSA reserve to ensure continuous rendering */ - UINT32 vol_adjusted_frames; /* Frames we've already adjusted the volume of but didn't write yet */ - UINT32 data_in_alsa_frames; - - BYTE *local_buffer, *tmp_buffer, *remapping_buf, *silence_buf; - LONG32 getbuf_last; /* <0 when using tmp_buffer */ - float *vols; - - pthread_mutex_t lock; -}; - -#define EXTRA_SAFE_RT 40000 - -int GetAudioEnv(char const* env, int def) { - char* val = getenv(env); - if (val) { - return atoi(val); - } - return def; -} - -static const WCHAR drv_keyW[] = {'S','o','f','t','w','a','r','e','\\', - 'W','i','n','e','\\','D','r','i','v','e','r','s','\\', - 'w','i','n','e','a','l','s','a','.','d','r','v'}; - -static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len ) -{ - while (len--) *dst++ = (unsigned char)*src++; -} - -static HKEY reg_open_key( HKEY root, const WCHAR *name, ULONG name_len ) -{ - UNICODE_STRING nameW = { name_len, name_len, (WCHAR *)name }; - OBJECT_ATTRIBUTES attr; - HANDLE ret; - - attr.Length = sizeof(attr); - attr.RootDirectory = root; - attr.ObjectName = &nameW; - attr.Attributes = 0; - attr.SecurityDescriptor = NULL; - attr.SecurityQualityOfService = NULL; - - if (NtOpenKeyEx( &ret, MAXIMUM_ALLOWED, &attr, 0 )) return 0; - return ret; -} - -static HKEY open_hkcu(void) -{ - char buffer[256]; - WCHAR bufferW[256]; - DWORD_PTR sid_data[(sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE) / sizeof(DWORD_PTR)]; - DWORD i, len = sizeof(sid_data); - SID *sid; - - if (NtQueryInformationToken( GetCurrentThreadEffectiveToken(), TokenUser, sid_data, len, &len )) - return 0; - - sid = ((TOKEN_USER *)sid_data)->User.Sid; - len = sprintf( buffer, "\\Registry\\User\\S-%u-%u", sid->Revision, - (unsigned)MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ), - MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] ))); - for (i = 0; i < sid->SubAuthorityCount; i++) - len += sprintf( buffer + len, "-%u", (unsigned)sid->SubAuthority[i] ); - ascii_to_unicode( bufferW, buffer, len + 1 ); - - return reg_open_key( NULL, bufferW, len * sizeof(WCHAR) ); -} - -static HKEY reg_open_hkcu_key( const WCHAR *name, ULONG name_len ) -{ - HKEY hkcu = open_hkcu(), key; - - key = reg_open_key( hkcu, name, name_len ); - NtClose( hkcu ); - - return key; -} - -static ULONG reg_query_value( HKEY hkey, const WCHAR *name, - KEY_VALUE_PARTIAL_INFORMATION *info, ULONG size ) -{ - unsigned int name_size = name ? wcslen( name ) * sizeof(WCHAR) : 0; - UNICODE_STRING nameW = { name_size, name_size, (WCHAR *)name }; - - if (NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, - info, size, &size )) - return 0; - - return size - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); -} - -static snd_pcm_stream_t alsa_get_direction(EDataFlow flow) -{ - return (flow == eRender) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE; -} - -static WCHAR *strdupAtoW(const char *str) -{ - unsigned int len; - WCHAR *ret; - - if(!str) return NULL; - - len = strlen(str) + 1; - ret = malloc(len * sizeof(WCHAR)); - if(ret) ntdll_umbstowcs(str, len, ret, len); - return ret; -} - -/* copied from kernelbase */ -static int muldiv( int a, int b, int c ) -{ - LONGLONG ret; - - if (!c) return -1; - - /* We want to deal with a positive divisor to simplify the logic. */ - if (c < 0) - { - a = -a; - c = -c; - } - - /* If the result is positive, we "add" to round. else, we subtract to round. */ - if ((a < 0 && b < 0) || (a >= 0 && b >= 0)) - ret = (((LONGLONG)a * b) + (c / 2)) / c; - else - ret = (((LONGLONG)a * b) - (c / 2)) / c; - - if (ret > 2147483647 || ret < -2147483647) return -1; - return ret; -} - -static void alsa_lock(struct alsa_stream *stream) -{ - pthread_mutex_lock(&stream->lock); -} - -static void alsa_unlock(struct alsa_stream *stream) -{ - pthread_mutex_unlock(&stream->lock); -} - -static NTSTATUS alsa_unlock_result(struct alsa_stream *stream, - HRESULT *result, HRESULT value) -{ - *result = value; - alsa_unlock(stream); - return STATUS_SUCCESS; -} - -static struct alsa_stream *handle_get_stream(stream_handle h) -{ - return (struct alsa_stream *)(UINT_PTR)h; -} - -static BOOL alsa_try_open(const char *devnode, EDataFlow flow) -{ - snd_pcm_t *handle; - int err; - - TRACE("devnode: %s, flow: %d\n", devnode, flow); - - if((err = snd_pcm_open(&handle, devnode, alsa_get_direction(flow), SND_PCM_NONBLOCK)) < 0){ - WARN("The device \"%s\" failed to open: %d (%s).\n", devnode, err, snd_strerror(err)); - return FALSE; - } - - snd_pcm_close(handle); - return TRUE; -} - -static WCHAR *construct_device_id(EDataFlow flow, const WCHAR *chunk1, const WCHAR *chunk2) -{ - WCHAR *ret; - const WCHAR *prefix; - size_t len_wchars = 0, chunk1_len = 0, chunk2_len = 0, copied = 0, prefix_len; - - static const WCHAR dashW[] = {' ','-',' ',0}; - static const size_t dashW_len = ARRAY_SIZE(dashW) - 1; - static const WCHAR outW[] = {'O','u','t',':',' ',0}; - static const WCHAR inW[] = {'I','n',':',' ',0}; - - if(flow == eRender){ - prefix = outW; - prefix_len = ARRAY_SIZE(outW) - 1; - len_wchars += prefix_len; - }else{ - prefix = inW; - prefix_len = ARRAY_SIZE(inW) - 1; - len_wchars += prefix_len; - } - if(chunk1){ - chunk1_len = wcslen(chunk1); - len_wchars += chunk1_len; - } - if(chunk1 && chunk2) - len_wchars += dashW_len; - if(chunk2){ - chunk2_len = wcslen(chunk2); - len_wchars += chunk2_len; - } - len_wchars += 1; /* NULL byte */ - - ret = malloc(len_wchars * sizeof(WCHAR)); - - memcpy(ret, prefix, prefix_len * sizeof(WCHAR)); - copied += prefix_len; - if(chunk1){ - memcpy(ret + copied, chunk1, chunk1_len * sizeof(WCHAR)); - copied += chunk1_len; - } - if(chunk1 && chunk2){ - memcpy(ret + copied, dashW, dashW_len * sizeof(WCHAR)); - copied += dashW_len; - } - if(chunk2){ - memcpy(ret + copied, chunk2, chunk2_len * sizeof(WCHAR)); - copied += chunk2_len; - } - ret[copied] = 0; - - TRACE("Enumerated device: %s\n", wine_dbgstr_w(ret)); - - return ret; -} - -struct endpt -{ - WCHAR *name; - char *device; -}; - -struct endpoints_info -{ - unsigned int num, size; - struct endpt *endpoints; -}; - -static void endpoints_add(struct endpoints_info *endpoints, WCHAR *name, char *device) -{ - if(endpoints->num >= endpoints->size){ - if (!endpoints->size) endpoints->size = 16; - else endpoints->size *= 2; - endpoints->endpoints = realloc(endpoints->endpoints, endpoints->size * sizeof(*endpoints->endpoints)); - } - - endpoints->endpoints[endpoints->num].name = name; - endpoints->endpoints[endpoints->num++].device = device; -} - -static HRESULT alsa_get_card_devices(EDataFlow flow, struct endpoints_info *endpoints_info, - snd_ctl_t *ctl, int card, const WCHAR *cardname) -{ - int err, device; - snd_pcm_info_t *info; - - info = calloc(1, snd_pcm_info_sizeof()); - if(!info) - return E_OUTOFMEMORY; - - snd_pcm_info_set_subdevice(info, 0); - snd_pcm_info_set_stream(info, alsa_get_direction(flow)); - - device = -1; - for(err = snd_ctl_pcm_next_device(ctl, &device); device != -1 && err >= 0; - err = snd_ctl_pcm_next_device(ctl, &device)){ - char devnode[32]; - WCHAR *devname; - - snd_pcm_info_set_device(info, device); - - if((err = snd_ctl_pcm_info(ctl, info)) < 0){ - if(err == -ENOENT) - /* This device doesn't have the right stream direction */ - continue; - - WARN("Failed to get info for card %d, device %d: %d (%s)\n", - card, device, err, snd_strerror(err)); - continue; - } - - sprintf(devnode, "plughw:%d,%d", card, device); - if(!alsa_try_open(devnode, flow)) - continue; - - devname = strdupAtoW(snd_pcm_info_get_name(info)); - if(!devname){ - WARN("Unable to get device name for card %d, device %d\n", card, device); - continue; - } - - endpoints_add(endpoints_info, construct_device_id(flow, cardname, devname), strdup(devnode)); - free(devname); - } - - free(info); - - if(err != 0) - WARN("Got a failure during device enumeration on card %d: %d (%s)\n", - card, err, snd_strerror(err)); - - return S_OK; -} - -static void get_reg_devices(EDataFlow flow, struct endpoints_info *endpoints_info) -{ - static const WCHAR ALSAOutputDevices[] = {'A','L','S','A','O','u','t','p','u','t','D','e','v','i','c','e','s',0}; - static const WCHAR ALSAInputDevices[] = {'A','L','S','A','I','n','p','u','t','D','e','v','i','c','e','s',0}; - char buffer[4096]; - KEY_VALUE_PARTIAL_INFORMATION *key_info = (void *)buffer; - HKEY key; - DWORD size; - const WCHAR *value_name = (flow == eRender) ? ALSAOutputDevices : ALSAInputDevices; - - /* @@ Wine registry key: HKCU\Software\Wine\Drivers\winealsa.drv */ - if((key = reg_open_hkcu_key(drv_keyW, sizeof(drv_keyW)))){ - if((size = reg_query_value(key, value_name, key_info, sizeof(buffer)))){ - WCHAR *p = (WCHAR *)key_info->Data; - - if(key_info->Type != REG_MULTI_SZ){ - ERR("Registry ALSA device list value type must be REG_MULTI_SZ\n"); - NtClose(key); - return; - } - - while(*p){ - int len = wcslen(p); - char *devname = malloc(len * 3 + 1); - - ntdll_wcstoumbs(p, len + 1, devname, len * 3 + 1, FALSE); - - if(alsa_try_open(devname, flow)) - endpoints_add(endpoints_info, construct_device_id(flow, p, NULL), strdup(devname)); - - free(devname); - p += len + 1; - } - } - - NtClose(key); - } -} - -struct card_type { - struct list entry; - int first_card_number; - char string[1]; -}; - -static struct list card_types = LIST_INIT(card_types); - -static BOOL need_card_number(int card, const char *string) -{ - struct card_type *cptr; - - LIST_FOR_EACH_ENTRY(cptr, &card_types, struct card_type, entry) - { - if(!strcmp(string, cptr->string)) - return card != cptr->first_card_number; - } - - /* this is the first instance of string */ - cptr = malloc(sizeof(struct card_type) + strlen(string)); - if(!cptr) - /* Default to displaying card number if we can't track cards */ - return TRUE; - - cptr->first_card_number = card; - strcpy(cptr->string, string); - list_add_head(&card_types, &cptr->entry); - return FALSE; -} - -static WCHAR *alsa_get_card_name(int card) -{ - char *cardname; - WCHAR *ret; - int err; - - if((err = snd_card_get_name(card, &cardname)) < 0){ - /* FIXME: Should be localized */ - WARN("Unable to get card name for ALSA device %d: %d (%s)\n", card, err, snd_strerror(err)); - cardname = strdup("Unknown soundcard"); - } - - if(need_card_number(card, cardname)){ - char *cardnameN; - /* - * For identical card names, second and subsequent instances get - * card number prefix to distinguish them (like Windows). - */ - if(asprintf(&cardnameN, "%u-%s", card, cardname) > 0){ - free(cardname); - cardname = cardnameN; - } - } - - ret = strdupAtoW(cardname); - free(cardname); - - return ret; -} - -static NTSTATUS alsa_get_endpoint_ids(void *args) -{ - static const WCHAR defaultW[] = {'d','e','f','a','u','l','t',0}; - struct get_endpoint_ids_params *params = args; - struct endpoints_info endpoints_info; - unsigned int i, needed, name_len, device_len, offset; - struct endpoint *endpoint; - int err, card; - - card = -1; - - endpoints_info.num = endpoints_info.size = 0; - endpoints_info.endpoints = NULL; - - if(alsa_try_open("default", params->flow)) - endpoints_add(&endpoints_info, construct_device_id(params->flow, defaultW, NULL), strdup("default")); - - get_reg_devices(params->flow, &endpoints_info); - - for(err = snd_card_next(&card); card != -1 && err >= 0; err = snd_card_next(&card)){ - char cardpath[64]; - WCHAR *cardname; - snd_ctl_t *ctl; - - sprintf(cardpath, "hw:%u", card); - - if((err = snd_ctl_open(&ctl, cardpath, 0)) < 0){ - WARN("Unable to open ctl for ALSA device %s: %d (%s)\n", cardpath, - err, snd_strerror(err)); - continue; - } - - cardname = alsa_get_card_name(card); - alsa_get_card_devices(params->flow, &endpoints_info, ctl, card, cardname); - free(cardname); - - snd_ctl_close(ctl); - } - - if(err != 0) - WARN("Got a failure during card enumeration: %d (%s)\n", err, snd_strerror(err)); - - offset = needed = endpoints_info.num * sizeof(*params->endpoints); - endpoint = params->endpoints; - - for(i = 0; i < endpoints_info.num; i++){ - name_len = wcslen(endpoints_info.endpoints[i].name) + 1; - device_len = strlen(endpoints_info.endpoints[i].device) + 1; - needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1); - - if(needed <= params->size){ - endpoint->name = offset; - memcpy((char *)params->endpoints + offset, endpoints_info.endpoints[i].name, name_len * sizeof(WCHAR)); - offset += name_len * sizeof(WCHAR); - endpoint->device = offset; - memcpy((char *)params->endpoints + offset, endpoints_info.endpoints[i].device, device_len); - offset += (device_len + 1) & ~1; - endpoint++; - } - free(endpoints_info.endpoints[i].name); - free(endpoints_info.endpoints[i].device); - } - free(endpoints_info.endpoints); - - params->num = endpoints_info.num; - params->default_idx = 0; - - if(needed > params->size){ - params->size = needed; - params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - } else - params->result = S_OK; - - return STATUS_SUCCESS; -} - -static WAVEFORMATEXTENSIBLE *clone_format(const WAVEFORMATEX *fmt) -{ - WAVEFORMATEXTENSIBLE *ret; - size_t size; - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - size = sizeof(WAVEFORMATEXTENSIBLE); - else - size = sizeof(WAVEFORMATEX); - - ret = malloc(size); - if(!ret) - return NULL; - - memcpy(ret, fmt, size); - - ret->Format.cbSize = size - sizeof(WAVEFORMATEX); - - return ret; -} - -static HRESULT alsa_open_device(const char *alsa_name, EDataFlow flow, snd_pcm_t **pcm_handle, - snd_pcm_hw_params_t **hw_params) -{ - snd_pcm_stream_t pcm_stream; - int err; - - if(flow == eRender) - pcm_stream = SND_PCM_STREAM_PLAYBACK; - else if(flow == eCapture) - pcm_stream = SND_PCM_STREAM_CAPTURE; - else - return E_UNEXPECTED; - - err = snd_pcm_open(pcm_handle, alsa_name, pcm_stream, SND_PCM_NONBLOCK); - if(err < 0){ - WARN("Unable to open PCM \"%s\": %d (%s)\n", alsa_name, err, snd_strerror(err)); - switch(err){ - case -EBUSY: - return AUDCLNT_E_DEVICE_IN_USE; - default: - return AUDCLNT_E_ENDPOINT_CREATE_FAILED; - } - } - - *hw_params = malloc(snd_pcm_hw_params_sizeof()); - if(!*hw_params){ - snd_pcm_close(*pcm_handle); - return E_OUTOFMEMORY; - } - - return S_OK; -} - -static snd_pcm_format_t alsa_format(const WAVEFORMATEX *fmt) -{ - snd_pcm_format_t format = SND_PCM_FORMAT_UNKNOWN; - const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt; - - if(fmt->wFormatTag == WAVE_FORMAT_PCM || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){ - if(fmt->wBitsPerSample == 8) - format = SND_PCM_FORMAT_U8; - else if(fmt->wBitsPerSample == 16) - format = SND_PCM_FORMAT_S16_LE; - else if(fmt->wBitsPerSample == 24) - format = SND_PCM_FORMAT_S24_3LE; - else if(fmt->wBitsPerSample == 32) - format = SND_PCM_FORMAT_S32_LE; - else - WARN("Unsupported bit depth: %u\n", fmt->wBitsPerSample); - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - fmt->wBitsPerSample != fmtex->Samples.wValidBitsPerSample){ - if(fmtex->Samples.wValidBitsPerSample == 20 && fmt->wBitsPerSample == 24) - format = SND_PCM_FORMAT_S20_3LE; - else - WARN("Unsupported ValidBits: %u\n", fmtex->Samples.wValidBitsPerSample); - } - }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){ - if(fmt->wBitsPerSample == 32) - format = SND_PCM_FORMAT_FLOAT_LE; - else if(fmt->wBitsPerSample == 64) - format = SND_PCM_FORMAT_FLOAT64_LE; - else - WARN("Unsupported float size: %u\n", fmt->wBitsPerSample); - }else - WARN("Unknown wave format: %04x\n", fmt->wFormatTag); - return format; -} - -static int alsa_channel_index(UINT flag) -{ - switch(flag){ - case SPEAKER_FRONT_LEFT: - return 0; - case SPEAKER_FRONT_RIGHT: - return 1; - case SPEAKER_BACK_LEFT: - return 2; - case SPEAKER_BACK_RIGHT: - return 3; - case SPEAKER_FRONT_CENTER: - return 4; - case SPEAKER_LOW_FREQUENCY: - return 5; - case SPEAKER_SIDE_LEFT: - return 6; - case SPEAKER_SIDE_RIGHT: - return 7; - } - return -1; -} - -static BOOL need_remapping(const WAVEFORMATEX *fmt, int *map) -{ - unsigned int i; - for(i = 0; i < fmt->nChannels; ++i){ - if(map[i] != i) - return TRUE; - } - return FALSE; -} - -static DWORD get_channel_mask(unsigned int channels) -{ - switch(channels){ - case 0: - return 0; - case 1: - return KSAUDIO_SPEAKER_MONO; - case 2: - return KSAUDIO_SPEAKER_STEREO; - case 3: - return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY; - case 4: - return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */ - case 5: - return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY; - case 6: - return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */ - case 7: - return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER; - case 8: - return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */ - } - FIXME("Unknown speaker configuration: %u\n", channels); - return 0; -} - -static HRESULT map_channels(EDataFlow flow, const WAVEFORMATEX *fmt, int *alsa_channels, int *map) -{ - BOOL need_remap; - - if(flow != eCapture && (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE || fmt->nChannels > 2) ){ - WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt; - UINT mask, flag = SPEAKER_FRONT_LEFT; - UINT i = 0; - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - fmtex->dwChannelMask != 0) - mask = fmtex->dwChannelMask; - else - mask = get_channel_mask(fmt->nChannels); - - *alsa_channels = 0; - - while(i < fmt->nChannels && !(flag & SPEAKER_RESERVED)){ - if(mask & flag){ - map[i] = alsa_channel_index(flag); - TRACE("Mapping mmdevapi channel %u (0x%x) to ALSA channel %d\n", - i, flag, map[i]); - if(map[i] >= *alsa_channels) - *alsa_channels = map[i] + 1; - ++i; - } - flag <<= 1; - } - - while(i < fmt->nChannels){ - map[i] = *alsa_channels; - TRACE("Mapping mmdevapi channel %u to ALSA channel %d\n", - i, map[i]); - ++*alsa_channels; - ++i; - } - - for(i = 0; i < fmt->nChannels; ++i){ - if(map[i] == -1){ - map[i] = *alsa_channels; - ++*alsa_channels; - TRACE("Remapping mmdevapi channel %u to ALSA channel %d\n", - i, map[i]); - } - } - - need_remap = need_remapping(fmt, map); - }else{ - *alsa_channels = fmt->nChannels; - - need_remap = FALSE; - } - - TRACE("need_remapping: %u, alsa_channels: %d\n", need_remap, *alsa_channels); - - return need_remap ? S_OK : S_FALSE; -} - -static void silence_buffer(struct alsa_stream *stream, BYTE *buffer, UINT32 frames) -{ - WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt; - if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM || - (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) && - stream->fmt->wBitsPerSample == 8) - memset(buffer, 128, frames * stream->fmt->nBlockAlign); - else - memset(buffer, 0, frames * stream->fmt->nBlockAlign); -} - -static ULONG_PTR zero_bits(void) -{ -#ifdef _WIN64 - return !NtCurrentTeb()->WowTebOffset ? 0 : 0x7fffffff; -#else - return 0; -#endif -} - -static NTSTATUS alsa_create_stream(void *args) -{ - struct create_stream_params *params = args; - struct alsa_stream *stream; - snd_pcm_sw_params_t *sw_params = NULL; - snd_pcm_format_t format; - unsigned int rate, alsa_period_us, i; - WAVEFORMATEXTENSIBLE *fmtex; - int err; - SIZE_T size; - - stream = calloc(1, sizeof(*stream)); - if(!stream){ - params->result = E_OUTOFMEMORY; - return STATUS_SUCCESS; - } - - params->result = alsa_open_device(params->device, params->flow, &stream->pcm_handle, &stream->hw_params); - if(FAILED(params->result)){ - free(stream); - return STATUS_SUCCESS; - } - - stream->need_remapping = map_channels(params->flow, params->fmt, &stream->alsa_channels, stream->alsa_channel_map) == S_OK; - - if((err = snd_pcm_hw_params_any(stream->pcm_handle, stream->hw_params)) < 0){ - WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - if((err = snd_pcm_hw_params_set_access(stream->pcm_handle, stream->hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){ - WARN("Unable to set access: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - format = alsa_format(params->fmt); - if (format == SND_PCM_FORMAT_UNKNOWN){ - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - goto exit; - } - - if((err = snd_pcm_hw_params_set_format(stream->pcm_handle, stream->hw_params, - format)) < 0){ - WARN("Unable to set ALSA format to %u: %d (%s)\n", format, err, - snd_strerror(err)); - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - goto exit; - } - - stream->alsa_format = format; - stream->flow = params->flow; - - rate = params->fmt->nSamplesPerSec; - if((err = snd_pcm_hw_params_set_rate_near(stream->pcm_handle, stream->hw_params, - &rate, NULL)) < 0){ - WARN("Unable to set rate to %u: %d (%s)\n", rate, err, - snd_strerror(err)); - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - goto exit; - } - - if((err = snd_pcm_hw_params_set_channels(stream->pcm_handle, stream->hw_params, - stream->alsa_channels)) < 0){ - WARN("Unable to set channels to %u: %d (%s)\n", params->fmt->nChannels, err, - snd_strerror(err)); - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - goto exit; - } - - stream->mmdev_period_rt = params->period; - alsa_period_us = stream->mmdev_period_rt / 10; - if((err = snd_pcm_hw_params_set_period_time_near(stream->pcm_handle, - stream->hw_params, &alsa_period_us, NULL)) < 0) - WARN("Unable to set period time near %u: %d (%s)\n", alsa_period_us, - err, snd_strerror(err)); - /* ALSA updates the output variable alsa_period_us */ - - stream->mmdev_period_frames = muldiv(params->fmt->nSamplesPerSec, - stream->mmdev_period_rt, 10000000); - - /* Buffer 4 ALSA periods if large enough, else 4 mmdevapi periods */ - stream->alsa_bufsize_frames = stream->mmdev_period_frames * 4; - if(err < 0 || alsa_period_us < params->period / 10) - err = snd_pcm_hw_params_set_buffer_size_near(stream->pcm_handle, - stream->hw_params, &stream->alsa_bufsize_frames); - else{ - unsigned int periods = 4; - err = snd_pcm_hw_params_set_periods_near(stream->pcm_handle, stream->hw_params, &periods, NULL); - } - if(err < 0) - WARN("Unable to set buffer size: %d (%s)\n", err, snd_strerror(err)); - - if((err = snd_pcm_hw_params(stream->pcm_handle, stream->hw_params)) < 0){ - WARN("Unable to set hw params: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - if((err = snd_pcm_hw_params_get_period_size(stream->hw_params, - &stream->alsa_period_frames, NULL)) < 0){ - WARN("Unable to get period size: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - if((err = snd_pcm_hw_params_get_buffer_size(stream->hw_params, - &stream->alsa_bufsize_frames)) < 0){ - WARN("Unable to get buffer size: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - sw_params = calloc(1, snd_pcm_sw_params_sizeof()); - if(!sw_params){ - params->result = E_OUTOFMEMORY; - goto exit; - } - - if((err = snd_pcm_sw_params_current(stream->pcm_handle, sw_params)) < 0){ - WARN("Unable to get sw_params: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - if((err = snd_pcm_sw_params_set_start_threshold(stream->pcm_handle, - sw_params, 1)) < 0){ - WARN("Unable set start threshold to 1: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - if((err = snd_pcm_sw_params_set_stop_threshold(stream->pcm_handle, - sw_params, stream->alsa_bufsize_frames)) < 0){ - WARN("Unable set stop threshold to %lu: %d (%s)\n", - stream->alsa_bufsize_frames, err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - if((err = snd_pcm_sw_params(stream->pcm_handle, sw_params)) < 0){ - WARN("Unable to set sw params: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - if((err = snd_pcm_prepare(stream->pcm_handle)) < 0){ - WARN("Unable to prepare device: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_ENDPOINT_CREATE_FAILED; - goto exit; - } - - /* Bear in mind weird situations where - * ALSA period (50ms) > mmdevapi buffer (3x10ms) - * or surprising rounding as seen with 22050x8x1 with Pulse: - * ALSA period 220 vs. 221 frames in mmdevapi and - * buffer 883 vs. 2205 frames in mmdevapi! */ - stream->bufsize_frames = muldiv(params->duration, params->fmt->nSamplesPerSec, 10000000); - if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE) - stream->bufsize_frames -= stream->bufsize_frames % stream->mmdev_period_frames; - stream->hidden_frames = stream->alsa_period_frames + stream->mmdev_period_frames + - muldiv(params->fmt->nSamplesPerSec, EXTRA_SAFE_RT, 10000000); - /* leave no less than about 1.33ms or 256 bytes of data after a rewind */ - stream->safe_rewind_frames = max(256 / params->fmt->nBlockAlign, muldiv(133, params->fmt->nSamplesPerSec, 100000)); - - /* Check if the ALSA buffer is so small that it will run out before - * the next MMDevAPI period tick occurs. Allow a little wiggle room - * with 120% of the period time. */ - if(stream->alsa_bufsize_frames < 1.2 * stream->mmdev_period_frames) - FIXME("ALSA buffer time is too small. Expect underruns. (%lu < %u * 1.2)\n", - stream->alsa_bufsize_frames, stream->mmdev_period_frames); - - fmtex = clone_format(params->fmt); - if(!fmtex){ - params->result = E_OUTOFMEMORY; - goto exit; - } - stream->fmt = &fmtex->Format; - - size = stream->bufsize_frames * params->fmt->nBlockAlign; - if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, zero_bits(), &size, - MEM_COMMIT, PAGE_READWRITE)){ - params->result = E_OUTOFMEMORY; - goto exit; - } - silence_buffer(stream, stream->local_buffer, stream->bufsize_frames); - - stream->silence_buf = malloc(stream->alsa_period_frames * stream->fmt->nBlockAlign); - if(!stream->silence_buf){ - params->result = E_OUTOFMEMORY; - goto exit; - } - silence_buffer(stream, stream->silence_buf, stream->alsa_period_frames); - - stream->vols = malloc(params->fmt->nChannels * sizeof(float)); - if(!stream->vols){ - params->result = E_OUTOFMEMORY; - goto exit; - } - for(i = 0; i < params->fmt->nChannels; ++i) - stream->vols[i] = 1.f; - - stream->share = params->share; - stream->flags = params->flags; - - pthread_mutex_init(&stream->lock, NULL); - - TRACE("ALSA period: %lu frames\n", stream->alsa_period_frames); - TRACE("ALSA buffer: %lu frames\n", stream->alsa_bufsize_frames); - TRACE("MMDevice period: %u frames\n", stream->mmdev_period_frames); - TRACE("MMDevice buffer: %u frames\n", stream->bufsize_frames); - -exit: - free(sw_params); - if(FAILED(params->result)){ - snd_pcm_close(stream->pcm_handle); - if(stream->local_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE); - } - free(stream->silence_buf); - free(stream->hw_params); - free(stream->fmt); - free(stream->vols); - free(stream); - }else{ - *params->stream = (stream_handle)(UINT_PTR)stream; - } - - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_release_stream(void *args) -{ - struct release_stream_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - SIZE_T size; - - if(params->timer_thread){ - stream->please_quit = TRUE; - NtWaitForSingleObject(params->timer_thread, FALSE, NULL); - NtClose(params->timer_thread); - } - - snd_pcm_drop(stream->pcm_handle); - snd_pcm_close(stream->pcm_handle); - if(stream->local_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE); - } - if(stream->tmp_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE); - } - free(stream->remapping_buf); - free(stream->silence_buf); - free(stream->hw_params); - free(stream->fmt); - free(stream->vols); - pthread_mutex_destroy(&stream->lock); - free(stream); - - params->result = S_OK; - return STATUS_SUCCESS; -} - -static BYTE *remap_channels(struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames) -{ - snd_pcm_uframes_t i; - UINT c; - UINT bytes_per_sample = stream->fmt->wBitsPerSample / 8; - - if(!stream->need_remapping) - return buf; - - if(stream->remapping_buf_frames < frames){ - stream->remapping_buf = realloc(stream->remapping_buf, - bytes_per_sample * stream->alsa_channels * frames); - stream->remapping_buf_frames = frames; - } - - snd_pcm_format_set_silence(stream->alsa_format, stream->remapping_buf, - frames * stream->alsa_channels); - - switch(stream->fmt->wBitsPerSample){ - case 8: { - UINT8 *tgt_buf, *src_buf; - tgt_buf = stream->remapping_buf; - src_buf = buf; - for(i = 0; i < frames; ++i){ - for(c = 0; c < stream->fmt->nChannels; ++c) - tgt_buf[stream->alsa_channel_map[c]] = src_buf[c]; - tgt_buf += stream->alsa_channels; - src_buf += stream->fmt->nChannels; - } - break; - } - case 16: { - UINT16 *tgt_buf, *src_buf; - tgt_buf = (UINT16*)stream->remapping_buf; - src_buf = (UINT16*)buf; - for(i = 0; i < frames; ++i){ - for(c = 0; c < stream->fmt->nChannels; ++c) - tgt_buf[stream->alsa_channel_map[c]] = src_buf[c]; - tgt_buf += stream->alsa_channels; - src_buf += stream->fmt->nChannels; - } - } - break; - case 32: { - UINT32 *tgt_buf, *src_buf; - tgt_buf = (UINT32*)stream->remapping_buf; - src_buf = (UINT32*)buf; - for(i = 0; i < frames; ++i){ - for(c = 0; c < stream->fmt->nChannels; ++c) - tgt_buf[stream->alsa_channel_map[c]] = src_buf[c]; - tgt_buf += stream->alsa_channels; - src_buf += stream->fmt->nChannels; - } - } - break; - default: { - BYTE *tgt_buf, *src_buf; - tgt_buf = stream->remapping_buf; - src_buf = buf; - for(i = 0; i < frames; ++i){ - for(c = 0; c < stream->fmt->nChannels; ++c) - memcpy(&tgt_buf[stream->alsa_channel_map[c] * bytes_per_sample], - &src_buf[c * bytes_per_sample], bytes_per_sample); - tgt_buf += stream->alsa_channels * bytes_per_sample; - src_buf += stream->fmt->nChannels * bytes_per_sample; - } - } - break; - } - - return stream->remapping_buf; -} - -static void adjust_buffer_volume(const struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames) -{ - BOOL adjust = FALSE; - UINT32 i, channels, mute = 0; - BYTE *end; - - if (stream->vol_adjusted_frames >= frames) - return; - channels = stream->fmt->nChannels; - - /* Adjust the buffer based on the volume for each channel */ - for (i = 0; i < channels; i++) - { - adjust |= stream->vols[i] != 1.0f; - if (stream->vols[i] == 0.0f) - mute++; - } - - if (mute == channels) - { - int err = snd_pcm_format_set_silence(stream->alsa_format, buf, frames * channels); - if (err < 0) - WARN("Setting buffer to silence failed: %d (%s)\n", err, snd_strerror(err)); - return; - } - if (!adjust) return; - - /* Skip the frames we've already adjusted before */ - end = buf + frames * stream->fmt->nBlockAlign; - buf += stream->vol_adjusted_frames * stream->fmt->nBlockAlign; - - switch (stream->alsa_format) - { -#ifndef WORDS_BIGENDIAN -#define PROCESS_BUFFER(type) do \ -{ \ - type *p = (type*)buf; \ - do \ - { \ - for (i = 0; i < channels; i++) \ - p[i] = p[i] * stream->vols[i]; \ - p += i; \ - } while ((BYTE*)p != end); \ -} while (0) - case SND_PCM_FORMAT_S16_LE: - PROCESS_BUFFER(INT16); - break; - case SND_PCM_FORMAT_S32_LE: - PROCESS_BUFFER(INT32); - break; - case SND_PCM_FORMAT_FLOAT_LE: - PROCESS_BUFFER(float); - break; - case SND_PCM_FORMAT_FLOAT64_LE: - PROCESS_BUFFER(double); - break; -#undef PROCESS_BUFFER - case SND_PCM_FORMAT_S20_3LE: - case SND_PCM_FORMAT_S24_3LE: - { - /* Do it 12 bytes at a time until it is no longer possible */ - UINT32 *q = (UINT32*)buf, mask = ~0xff; - BYTE *p; - - /* After we adjust the volume, we need to mask out low bits */ - if (stream->alsa_format == SND_PCM_FORMAT_S20_3LE) - mask = ~0x0fff; - - i = 0; - while (end - (BYTE*)q >= 12) - { - UINT32 v[4], k; - v[0] = q[0] << 8; - v[1] = q[1] << 16 | (q[0] >> 16 & ~0xff); - v[2] = q[2] << 24 | (q[1] >> 8 & ~0xff); - v[3] = q[2] & ~0xff; - for (k = 0; k < 4; k++) - { - v[k] = (INT32)((INT32)v[k] * stream->vols[i]); - v[k] &= mask; - if (++i == channels) i = 0; - } - *q++ = v[0] >> 8 | v[1] << 16; - *q++ = v[1] >> 16 | v[2] << 8; - *q++ = v[2] >> 24 | v[3]; - } - p = (BYTE*)q; - while (p != end) - { - UINT32 v = (INT32)((INT32)(p[0] << 8 | p[1] << 16 | p[2] << 24) * stream->vols[i]); - v &= mask; - *p++ = v >> 8 & 0xff; - *p++ = v >> 16 & 0xff; - *p++ = v >> 24; - if (++i == channels) i = 0; - } - break; - } -#endif - case SND_PCM_FORMAT_U8: - { - UINT8 *p = (UINT8*)buf; - do - { - for (i = 0; i < channels; i++) - p[i] = (int)((p[i] - 128) * stream->vols[i]) + 128; - p += i; - } while ((BYTE*)p != end); - break; - } - default: - TRACE("Unhandled format %i, not adjusting volume.\n", stream->alsa_format); - break; - } -} - -static snd_pcm_sframes_t alsa_write_best_effort(struct alsa_stream *stream, BYTE *buf, snd_pcm_uframes_t frames) -{ - snd_pcm_sframes_t written; - - adjust_buffer_volume(stream, buf, frames); - - /* Mark the frames we've already adjusted */ - if (stream->vol_adjusted_frames < frames) - stream->vol_adjusted_frames = frames; - - buf = remap_channels(stream, buf, frames); - - written = snd_pcm_writei(stream->pcm_handle, buf, frames); - if(written < 0){ - int ret; - - if(written == -EAGAIN) - /* buffer full */ - return 0; - - WARN("writei failed, recovering: %ld (%s)\n", written, - snd_strerror(written)); - - ret = snd_pcm_recover(stream->pcm_handle, written, 0); - if(ret < 0){ - WARN("Could not recover: %d (%s)\n", ret, snd_strerror(ret)); - return ret; - } - - written = snd_pcm_writei(stream->pcm_handle, buf, frames); - } - - if (written > 0) - stream->vol_adjusted_frames -= written; - return written; -} - -static snd_pcm_sframes_t alsa_write_buffer_wrap(struct alsa_stream *stream, BYTE *buf, - snd_pcm_uframes_t buflen, snd_pcm_uframes_t offs, - snd_pcm_uframes_t to_write) -{ - snd_pcm_sframes_t ret = 0; - - while(to_write){ - snd_pcm_uframes_t chunk; - snd_pcm_sframes_t tmp; - - if(offs + to_write > buflen) - chunk = buflen - offs; - else - chunk = to_write; - - tmp = alsa_write_best_effort(stream, buf + offs * stream->fmt->nBlockAlign, chunk); - if(tmp < 0) - return ret; - if(!tmp) - break; - - ret += tmp; - to_write -= tmp; - offs += tmp; - offs %= buflen; - } - - return ret; -} - -static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize) -{ - if(left <= right) - return right - left; - return bufsize - (left - right); -} - -static UINT data_not_in_alsa(struct alsa_stream *stream) -{ - UINT32 diff; - - diff = buf_ptr_diff(stream->lcl_offs_frames, stream->wri_offs_frames, stream->bufsize_frames); - if(diff) - return diff; - - return stream->held_frames - stream->data_in_alsa_frames; -} - -/* Here's the buffer setup: - * - * vvvvvvvv sent to HW already - * vvvvvvvv in ALSA buffer but rewindable - * [dddddddddddddddd] ALSA buffer - * [dddddddddddddddd--------] mmdevapi buffer - * ^^^^^^^^ data_in_alsa_frames - * ^^^^^^^^^^^^^^^^ held_frames - * ^ lcl_offs_frames - * ^ wri_offs_frames - * - * GetCurrentPadding is held_frames - * - * During period callback, we decrement held_frames, fill ALSA buffer, and move - * lcl_offs forward - * - * During Stop, we rewind the ALSA buffer - */ -static void alsa_write_data(struct alsa_stream *stream) -{ - snd_pcm_sframes_t written; - snd_pcm_uframes_t avail, max_copy_frames, data_frames_played; - int err; - - /* this call seems to be required to get an accurate snd_pcm_state() */ - avail = snd_pcm_avail_update(stream->pcm_handle); - - if(snd_pcm_state(stream->pcm_handle) == SND_PCM_STATE_XRUN){ - TRACE("XRun state, recovering\n"); - - avail = stream->alsa_bufsize_frames; - - if((err = snd_pcm_recover(stream->pcm_handle, -EPIPE, 1)) < 0) - WARN("snd_pcm_recover failed: %d (%s)\n", err, snd_strerror(err)); - - if((err = snd_pcm_reset(stream->pcm_handle)) < 0) - WARN("snd_pcm_reset failed: %d (%s)\n", err, snd_strerror(err)); - - if((err = snd_pcm_prepare(stream->pcm_handle)) < 0) - WARN("snd_pcm_prepare failed: %d (%s)\n", err, snd_strerror(err)); - } - - TRACE("avail: %ld\n", avail); - - /* Add a lead-in when starting with too few frames to ensure - * continuous rendering. Additional benefit: Force ALSA to start. */ - if(stream->data_in_alsa_frames == 0 && stream->held_frames < stream->alsa_period_frames) - { - alsa_write_best_effort(stream, stream->silence_buf, - stream->alsa_period_frames - stream->held_frames); - stream->vol_adjusted_frames = 0; - } - - if(stream->started) - max_copy_frames = data_not_in_alsa(stream); - else - max_copy_frames = 0; - - data_frames_played = min(stream->data_in_alsa_frames, avail); - stream->data_in_alsa_frames -= data_frames_played; - - if(stream->held_frames > data_frames_played){ - if(stream->started) - stream->held_frames -= data_frames_played; - }else - stream->held_frames = 0; - - while(avail && max_copy_frames){ - snd_pcm_uframes_t to_write; - - to_write = min(avail, max_copy_frames); - - written = alsa_write_buffer_wrap(stream, stream->local_buffer, - stream->bufsize_frames, stream->lcl_offs_frames, to_write); - if(written <= 0) - break; - - avail -= written; - stream->lcl_offs_frames += written; - stream->lcl_offs_frames %= stream->bufsize_frames; - stream->data_in_alsa_frames += written; - max_copy_frames -= written; - } - - if(stream->event) - NtSetEvent(stream->event, NULL); -} - -static void alsa_read_data(struct alsa_stream *stream) -{ - snd_pcm_sframes_t nread; - UINT32 pos = stream->wri_offs_frames, limit = stream->held_frames; - unsigned int i; - - if(!stream->started) - goto exit; - - /* FIXME: Detect overrun and signal DATA_DISCONTINUITY - * How to count overrun frames and report them as position increase? */ - limit = stream->bufsize_frames - max(limit, pos); - - nread = snd_pcm_readi(stream->pcm_handle, - stream->local_buffer + pos * stream->fmt->nBlockAlign, limit); - TRACE("read %ld from %u limit %u\n", nread, pos, limit); - if(nread < 0){ - int ret; - - if(nread == -EAGAIN) /* no data yet */ - return; - - WARN("read failed, recovering: %ld (%s)\n", nread, snd_strerror(nread)); - - ret = snd_pcm_recover(stream->pcm_handle, nread, 0); - if(ret < 0){ - WARN("Recover failed: %d (%s)\n", ret, snd_strerror(ret)); - return; - } - - nread = snd_pcm_readi(stream->pcm_handle, - stream->local_buffer + pos * stream->fmt->nBlockAlign, limit); - if(nread < 0){ - WARN("read failed: %ld (%s)\n", nread, snd_strerror(nread)); - return; - } - } - - for(i = 0; i < stream->fmt->nChannels; i++) - if(stream->vols[i] != 0.0f) - break; - if(i == stream->fmt->nChannels){ /* mute */ - int err; - if((err = snd_pcm_format_set_silence(stream->alsa_format, - stream->local_buffer + pos * stream->fmt->nBlockAlign, - nread)) < 0) - WARN("Setting buffer to silence failed: %d (%s)\n", err, - snd_strerror(err)); - } - - stream->wri_offs_frames += nread; - stream->wri_offs_frames %= stream->bufsize_frames; - stream->held_frames += nread; - -exit: - if(stream->event) - NtSetEvent(stream->event, NULL); -} - -static snd_pcm_uframes_t interp_elapsed_frames(struct alsa_stream *stream) -{ - LARGE_INTEGER time_freq, current_time, time_diff; - - NtQueryPerformanceCounter(¤t_time, &time_freq); - time_diff.QuadPart = current_time.QuadPart - stream->last_period_time.QuadPart; - return muldiv(time_diff.QuadPart, stream->fmt->nSamplesPerSec, time_freq.QuadPart); -} - -static int alsa_rewind_best_effort(struct alsa_stream *stream) -{ - snd_pcm_uframes_t len, leave; - - /* we can't use snd_pcm_rewindable, some PCM devices crash. so follow - * PulseAudio's example and rewind as much data as we believe is in the - * buffer, minus 1.33ms for safety. */ - - /* amount of data to leave in ALSA buffer */ - leave = interp_elapsed_frames(stream) + stream->safe_rewind_frames; - - if(stream->held_frames < leave) - stream->held_frames = 0; - else - stream->held_frames -= leave; - - if(stream->data_in_alsa_frames < leave) - len = 0; - else - len = stream->data_in_alsa_frames - leave; - - TRACE("rewinding %lu frames, now held %u\n", len, stream->held_frames); - - if(len) - /* snd_pcm_rewind return value is often broken, assume it succeeded */ - snd_pcm_rewind(stream->pcm_handle, len); - - stream->data_in_alsa_frames = 0; - - return len; -} - -static NTSTATUS alsa_start(void *args) -{ - struct start_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_EVENTHANDLE_NOT_SET); - - if(stream->started) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_NOT_STOPPED); - - if(stream->flow == eCapture){ - /* dump any data that might be leftover in the ALSA capture buffer */ - snd_pcm_readi(stream->pcm_handle, stream->local_buffer, - stream->bufsize_frames); - }else{ - snd_pcm_sframes_t avail, written; - snd_pcm_uframes_t offs; - - avail = snd_pcm_avail_update(stream->pcm_handle); - avail = min(avail, stream->held_frames); - - if(stream->wri_offs_frames < stream->held_frames) - offs = stream->bufsize_frames - stream->held_frames + stream->wri_offs_frames; - else - offs = stream->wri_offs_frames - stream->held_frames; - - /* fill it with data */ - written = alsa_write_buffer_wrap(stream, stream->local_buffer, - stream->bufsize_frames, offs, avail); - - if(written > 0){ - stream->lcl_offs_frames = (offs + written) % stream->bufsize_frames; - stream->data_in_alsa_frames = written; - }else{ - stream->lcl_offs_frames = offs; - stream->data_in_alsa_frames = 0; - } - } - stream->started = TRUE; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_stop(void *args) -{ - struct stop_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - if(!stream->started) - return alsa_unlock_result(stream, ¶ms->result, S_FALSE); - - if(stream->flow == eRender) - alsa_rewind_best_effort(stream); - - stream->started = FALSE; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_reset(void *args) -{ - struct reset_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - if(stream->started) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_NOT_STOPPED); - - if(stream->getbuf_last) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_BUFFER_OPERATION_PENDING); - - if(snd_pcm_drop(stream->pcm_handle) < 0) - WARN("snd_pcm_drop failed\n"); - - if(snd_pcm_reset(stream->pcm_handle) < 0) - WARN("snd_pcm_reset failed\n"); - - if(snd_pcm_prepare(stream->pcm_handle) < 0) - WARN("snd_pcm_prepare failed\n"); - - if(stream->flow == eRender){ - stream->written_frames = 0; - stream->last_pos_frames = 0; - }else{ - stream->written_frames += stream->held_frames; - } - stream->held_frames = 0; - stream->lcl_offs_frames = 0; - stream->wri_offs_frames = 0; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_timer_loop(void *args) -{ - struct timer_loop_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - LARGE_INTEGER delay, next; - int adjust; - - alsa_lock(stream); - - delay.QuadPart = -stream->mmdev_period_rt; - NtQueryPerformanceCounter(&stream->last_period_time, NULL); - next.QuadPart = stream->last_period_time.QuadPart + stream->mmdev_period_rt; - - while(!stream->please_quit){ - if(stream->flow == eRender) - alsa_write_data(stream); - else if(stream->flow == eCapture) - alsa_read_data(stream); - alsa_unlock(stream); - - NtDelayExecution(FALSE, &delay); - - alsa_lock(stream); - NtQueryPerformanceCounter(&stream->last_period_time, NULL); - adjust = next.QuadPart - stream->last_period_time.QuadPart; - if(adjust > stream->mmdev_period_rt / 2) - adjust = stream->mmdev_period_rt / 2; - else if(adjust < -stream->mmdev_period_rt / 2) - adjust = -stream->mmdev_period_rt / 2; - delay.QuadPart = -(stream->mmdev_period_rt + adjust); - next.QuadPart += stream->mmdev_period_rt; - } - - alsa_unlock(stream); - - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_get_render_buffer(void *args) -{ - struct get_render_buffer_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - UINT32 write_pos, frames = params->frames; - SIZE_T size; - - alsa_lock(stream); - - if(stream->getbuf_last) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_OUT_OF_ORDER); - - if(!frames) - return alsa_unlock_result(stream, ¶ms->result, S_OK); - - /* held_frames == GetCurrentPadding_nolock(); */ - if(stream->held_frames + frames > stream->bufsize_frames) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_BUFFER_TOO_LARGE); - - write_pos = stream->wri_offs_frames; - if(write_pos + frames > stream->bufsize_frames){ - if(stream->tmp_buffer_frames < frames){ - if(stream->tmp_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE); - stream->tmp_buffer = NULL; - } - size = frames * stream->fmt->nBlockAlign; - if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(), &size, - MEM_COMMIT, PAGE_READWRITE)){ - stream->tmp_buffer_frames = 0; - return alsa_unlock_result(stream, ¶ms->result, E_OUTOFMEMORY); - } - stream->tmp_buffer_frames = frames; - } - *params->data = stream->tmp_buffer; - stream->getbuf_last = -frames; - }else{ - *params->data = stream->local_buffer + write_pos * stream->fmt->nBlockAlign; - stream->getbuf_last = frames; - } - - silence_buffer(stream, *params->data, frames); - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static void alsa_wrap_buffer(struct alsa_stream *stream, BYTE *buffer, UINT32 written_frames) -{ - snd_pcm_uframes_t write_offs_frames = stream->wri_offs_frames; - UINT32 write_offs_bytes = write_offs_frames * stream->fmt->nBlockAlign; - snd_pcm_uframes_t chunk_frames = stream->bufsize_frames - write_offs_frames; - UINT32 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign; - UINT32 written_bytes = written_frames * stream->fmt->nBlockAlign; - - if(written_bytes <= chunk_bytes){ - memcpy(stream->local_buffer + write_offs_bytes, buffer, written_bytes); - }else{ - memcpy(stream->local_buffer + write_offs_bytes, buffer, chunk_bytes); - memcpy(stream->local_buffer, buffer + chunk_bytes, - written_bytes - chunk_bytes); - } -} - -static NTSTATUS alsa_release_render_buffer(void *args) -{ - struct release_render_buffer_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - UINT32 written_frames = params->written_frames; - BYTE *buffer; - - alsa_lock(stream); - - if(!written_frames){ - stream->getbuf_last = 0; - return alsa_unlock_result(stream, ¶ms->result, S_OK); - } - - if(!stream->getbuf_last) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_OUT_OF_ORDER); - - if(written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last)) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_INVALID_SIZE); - - if(stream->getbuf_last >= 0) - buffer = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign; - else - buffer = stream->tmp_buffer; - - if(params->flags & AUDCLNT_BUFFERFLAGS_SILENT) - silence_buffer(stream, buffer, written_frames); - - if(stream->getbuf_last < 0) - alsa_wrap_buffer(stream, buffer, written_frames); - - stream->wri_offs_frames += written_frames; - stream->wri_offs_frames %= stream->bufsize_frames; - stream->held_frames += written_frames; - stream->written_frames += written_frames; - stream->getbuf_last = 0; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_get_capture_buffer(void *args) -{ - struct get_capture_buffer_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - UINT32 *frames = params->frames; - SIZE_T size; - - alsa_lock(stream); - - if(stream->getbuf_last) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_OUT_OF_ORDER); - - if(stream->held_frames < stream->mmdev_period_frames){ - *frames = 0; - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_S_BUFFER_EMPTY); - } - *frames = stream->mmdev_period_frames; - - if(stream->lcl_offs_frames + *frames > stream->bufsize_frames){ - UINT32 chunk_bytes, offs_bytes, frames_bytes; - if(stream->tmp_buffer_frames < *frames){ - if(stream->tmp_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE); - stream->tmp_buffer = NULL; - } - size = *frames * stream->fmt->nBlockAlign; - if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(), &size, - MEM_COMMIT, PAGE_READWRITE)){ - stream->tmp_buffer_frames = 0; - return alsa_unlock_result(stream, ¶ms->result, E_OUTOFMEMORY); - } - stream->tmp_buffer_frames = *frames; - } - - *params->data = stream->tmp_buffer; - chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) * - stream->fmt->nBlockAlign; - offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign; - frames_bytes = *frames * stream->fmt->nBlockAlign; - memcpy(stream->tmp_buffer, stream->local_buffer + offs_bytes, chunk_bytes); - memcpy(stream->tmp_buffer + chunk_bytes, stream->local_buffer, - frames_bytes - chunk_bytes); - }else - *params->data = stream->local_buffer + - stream->lcl_offs_frames * stream->fmt->nBlockAlign; - - stream->getbuf_last = *frames; - *params->flags = 0; - - if(params->devpos) - *params->devpos = stream->written_frames; - if(params->qpcpos){ /* fixme: qpc of recording time */ - LARGE_INTEGER stamp, freq; - NtQueryPerformanceCounter(&stamp, &freq); - *params->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart; - } - - return alsa_unlock_result(stream, ¶ms->result, *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY); -} - -static NTSTATUS alsa_release_capture_buffer(void *args) -{ - struct release_capture_buffer_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - UINT32 done = params->done; - - alsa_lock(stream); - - if(!done){ - stream->getbuf_last = 0; - return alsa_unlock_result(stream, ¶ms->result, S_OK); - } - - if(!stream->getbuf_last) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_OUT_OF_ORDER); - - if(stream->getbuf_last != done) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_INVALID_SIZE); - - stream->written_frames += done; - stream->held_frames -= done; - stream->lcl_offs_frames += done; - stream->lcl_offs_frames %= stream->bufsize_frames; - stream->getbuf_last = 0; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_is_format_supported(void *args) -{ - struct is_format_supported_params *params = args; - const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)params->fmt_in; - snd_pcm_t *pcm_handle; - snd_pcm_hw_params_t *hw_params; - snd_pcm_format_mask_t *formats = NULL; - snd_pcm_format_t format; - WAVEFORMATEXTENSIBLE *closest = NULL; - unsigned int max = 0, min = 0; - int err; - int alsa_channels, alsa_channel_map[32]; - - params->result = S_OK; - - if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out)) - params->result = E_POINTER; - else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE) - params->result = E_INVALIDARG; - else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - if(params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) - params->result = E_INVALIDARG; - else if(params->fmt_in->nAvgBytesPerSec == 0 || params->fmt_in->nBlockAlign == 0 || - (fmtex->Samples.wValidBitsPerSample > params->fmt_in->wBitsPerSample)) - params->result = E_INVALIDARG; - } - if(FAILED(params->result)) - return STATUS_SUCCESS; - - if(params->fmt_in->nChannels == 0){ - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - return STATUS_SUCCESS; - } - - params->result = alsa_open_device(params->device, params->flow, &pcm_handle, &hw_params); - if(FAILED(params->result)) - return STATUS_SUCCESS; - - if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){ - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - formats = calloc(1, snd_pcm_format_mask_sizeof()); - if(!formats){ - params->result = E_OUTOFMEMORY; - goto exit; - } - - snd_pcm_hw_params_get_format_mask(hw_params, formats); - format = alsa_format(params->fmt_in); - if (format == SND_PCM_FORMAT_UNKNOWN || - !snd_pcm_format_mask_test(formats, format)){ - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - goto exit; - } - - closest = clone_format(params->fmt_in); - if(!closest){ - params->result = E_OUTOFMEMORY; - goto exit; - } - - if((err = snd_pcm_hw_params_get_rate_min(hw_params, &min, NULL)) < 0){ - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - WARN("Unable to get min rate: %d (%s)\n", err, snd_strerror(err)); - goto exit; - } - - if((err = snd_pcm_hw_params_get_rate_max(hw_params, &max, NULL)) < 0){ - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err)); - goto exit; - } - - if(params->fmt_in->nSamplesPerSec < min || params->fmt_in->nSamplesPerSec > max){ - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - goto exit; - } - - if((err = snd_pcm_hw_params_get_channels_min(hw_params, &min)) < 0){ - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - WARN("Unable to get min channels: %d (%s)\n", err, snd_strerror(err)); - goto exit; - } - - if((err = snd_pcm_hw_params_get_channels_max(hw_params, &max)) < 0){ - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err)); - goto exit; - } - if(params->fmt_in->nChannels > max){ - params->result = S_FALSE; - closest->Format.nChannels = max; - }else if(params->fmt_in->nChannels < min){ - params->result = S_FALSE; - closest->Format.nChannels = min; - } - - map_channels(params->flow, params->fmt_in, &alsa_channels, alsa_channel_map); - - if(alsa_channels > max){ - params->result = S_FALSE; - closest->Format.nChannels = max; - } - - if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) - closest->dwChannelMask = get_channel_mask(closest->Format.nChannels); - - if(params->fmt_in->nBlockAlign != params->fmt_in->nChannels * params->fmt_in->wBitsPerSample / 8 || - params->fmt_in->nAvgBytesPerSec != params->fmt_in->nBlockAlign * params->fmt_in->nSamplesPerSec || - (params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - fmtex->Samples.wValidBitsPerSample < params->fmt_in->wBitsPerSample)) - params->result = S_FALSE; - - if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE && params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - if(fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED) - params->result = S_FALSE; - } - -exit: - if(params->result == S_FALSE && !params->fmt_out) - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - - if(params->result == S_FALSE && params->fmt_out) { - closest->Format.nBlockAlign = closest->Format.nChannels * closest->Format.wBitsPerSample / 8; - closest->Format.nAvgBytesPerSec = closest->Format.nBlockAlign * closest->Format.nSamplesPerSec; - if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) - closest->Samples.wValidBitsPerSample = closest->Format.wBitsPerSample; - memcpy(params->fmt_out, closest, closest->Format.cbSize); - } - free(closest); - free(formats); - free(hw_params); - snd_pcm_close(pcm_handle); - - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_get_mix_format(void *args) -{ - struct get_mix_format_params *params = args; - WAVEFORMATEXTENSIBLE *fmt = params->fmt; - snd_pcm_t *pcm_handle; - snd_pcm_hw_params_t *hw_params; - snd_pcm_format_mask_t *formats; - unsigned int max_rate, max_channels; - int err; - - params->result = alsa_open_device(params->device, params->flow, &pcm_handle, &hw_params); - if(FAILED(params->result)) - return STATUS_SUCCESS; - - formats = calloc(1, snd_pcm_format_mask_sizeof()); - if(!formats){ - free(hw_params); - snd_pcm_close(pcm_handle); - params->result = E_OUTOFMEMORY; - return STATUS_SUCCESS; - } - - if((err = snd_pcm_hw_params_any(pcm_handle, hw_params)) < 0){ - WARN("Unable to get hw_params: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - snd_pcm_hw_params_get_format_mask(hw_params, formats); - - fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_FLOAT_LE)){ - fmt->Format.wBitsPerSample = 32; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S16_LE)){ - fmt->Format.wBitsPerSample = 16; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_U8)){ - fmt->Format.wBitsPerSample = 8; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S32_LE)){ - fmt->Format.wBitsPerSample = 32; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else if(snd_pcm_format_mask_test(formats, SND_PCM_FORMAT_S24_3LE)){ - fmt->Format.wBitsPerSample = 24; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else{ - ERR("Didn't recognize any available ALSA formats\n"); - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - if((err = snd_pcm_hw_params_get_channels_max(hw_params, &max_channels)) < 0){ - WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - if(max_channels > 6) - fmt->Format.nChannels = 2; - else - fmt->Format.nChannels = max_channels; - - if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)){ - /* For most hardware on Windows, users must choose a configuration with an even - * number of channels (stereo, quad, 5.1, 7.1). Users can then disable - * channels, but those channels are still reported to applications from - * GetMixFormat! Some applications behave badly if given an odd number of - * channels (e.g. 2.1). */ - - if(fmt->Format.nChannels < max_channels) - fmt->Format.nChannels += 1; - else - /* We could "fake" more channels and downmix the emulated channels, - * but at that point you really ought to tweak your ALSA setup or - * just use PulseAudio. */ - WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels); - } - - fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels); - - if((err = snd_pcm_hw_params_get_rate_max(hw_params, &max_rate, NULL)) < 0){ - WARN("Unable to get max rate: %d (%s)\n", err, snd_strerror(err)); - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - if(max_rate >= 48000) - fmt->Format.nSamplesPerSec = 48000; - else if(max_rate >= 44100) - fmt->Format.nSamplesPerSec = 44100; - else if(max_rate >= 22050) - fmt->Format.nSamplesPerSec = 22050; - else if(max_rate >= 11025) - fmt->Format.nSamplesPerSec = 11025; - else if(max_rate >= 8000) - fmt->Format.nSamplesPerSec = 8000; - else{ - ERR("Unknown max rate: %u\n", max_rate); - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample * fmt->Format.nChannels) / 8; - fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec * fmt->Format.nBlockAlign; - - fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample; - fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - -exit: - free(formats); - free(hw_params); - snd_pcm_close(pcm_handle); - - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_get_buffer_size(void *args) -{ - struct get_buffer_size_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - *params->frames = stream->bufsize_frames; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_get_latency(void *args) -{ - struct get_latency_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - /* Hide some frames in the ALSA buffer. Allows us to return GetCurrentPadding=0 - * yet have enough data left to play (as if it were in native's mixer). Add: - * + mmdevapi_period such that at the end of it, ALSA still has data; - * + EXTRA_SAFE (~4ms) to allow for late callback invocation / fluctuation; - * + alsa_period such that ALSA always has at least one period to play. */ - if(stream->flow == eRender) - *params->latency = muldiv(stream->hidden_frames, 10000000, stream->fmt->nSamplesPerSec); - else - *params->latency = muldiv(stream->alsa_period_frames, 10000000, stream->fmt->nSamplesPerSec) - + stream->mmdev_period_rt; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_get_current_padding(void *args) -{ - struct get_current_padding_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - /* padding is solely updated at callback time in shared mode */ - *params->padding = stream->held_frames; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_get_next_packet_size(void *args) -{ - struct get_next_packet_size_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - *params->frames = stream->held_frames < stream->mmdev_period_frames ? 0 : stream->mmdev_period_frames; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_get_frequency(void *args) -{ - struct get_frequency_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - UINT64 *freq = params->freq; - - alsa_lock(stream); - - if(stream->share == AUDCLNT_SHAREMODE_SHARED) - *freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign; - else - *freq = stream->fmt->nSamplesPerSec; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_get_position(void *args) -{ - struct get_position_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - UINT64 position; - snd_pcm_state_t alsa_state; - - alsa_lock(stream); - - /* avail_update required to get accurate snd_pcm_state() */ - snd_pcm_avail_update(stream->pcm_handle); - alsa_state = snd_pcm_state(stream->pcm_handle); - - if(stream->flow == eRender){ - position = stream->written_frames - stream->held_frames; - - if(stream->started && alsa_state == SND_PCM_STATE_RUNNING && stream->held_frames) - /* we should be using snd_pcm_delay here, but it is broken - * especially during ALSA device underrun. instead, let's just - * interpolate between periods with the system timer. */ - position += interp_elapsed_frames(stream); - - position = min(position, stream->written_frames - stream->held_frames + stream->mmdev_period_frames); - - position = min(position, stream->written_frames); - }else - position = stream->written_frames + stream->held_frames; - - /* ensure monotic growth */ - if(position < stream->last_pos_frames) - position = stream->last_pos_frames; - else - stream->last_pos_frames = position; - - TRACE("frames written: %u, held: %u, state: 0x%x, position: %u\n", - (UINT32)(stream->written_frames%1000000000), stream->held_frames, - alsa_state, (UINT32)(position%1000000000)); - - if(stream->share == AUDCLNT_SHAREMODE_SHARED) - *params->pos = position * stream->fmt->nBlockAlign; - else - *params->pos = position; - - if(params->qpctime){ - LARGE_INTEGER stamp, freq; - NtQueryPerformanceCounter(&stamp, &freq); - *params->qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart; - } - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_set_volumes(void *args) -{ - struct set_volumes_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - unsigned int i; - - for(i = 0; i < stream->fmt->nChannels; i++) - stream->vols[i] = params->volumes[i] * params->session_volumes[i] * params->master_volume; - - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_set_event_handle(void *args) -{ - struct set_event_handle_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) - return alsa_unlock_result(stream, ¶ms->result, AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED); - - if (stream->event){ - FIXME("called twice\n"); - return alsa_unlock_result(stream, ¶ms->result, HRESULT_FROM_WIN32(ERROR_INVALID_NAME)); - } - - stream->event = params->event; - - return alsa_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS alsa_is_started(void *args) -{ - struct is_started_params *params = args; - struct alsa_stream *stream = handle_get_stream(params->stream); - - alsa_lock(stream); - - return alsa_unlock_result(stream, ¶ms->result, stream->started ? S_OK : S_FALSE); -} - -static unsigned int alsa_probe_num_speakers(char *name) -{ - snd_pcm_t *handle; - snd_pcm_hw_params_t *params; - int err; - unsigned int max_channels = 0; - - if ((err = snd_pcm_open(&handle, name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { - WARN("The device \"%s\" failed to open: %d (%s).\n", - name, err, snd_strerror(err)); - return 0; - } - - params = malloc(snd_pcm_hw_params_sizeof()); - if (!params) { - WARN("Out of memory.\n"); - snd_pcm_close(handle); - return 0; - } - - if ((err = snd_pcm_hw_params_any(handle, params)) < 0) { - WARN("snd_pcm_hw_params_any failed for \"%s\": %d (%s).\n", - name, err, snd_strerror(err)); - goto exit; - } - - if ((err = snd_pcm_hw_params_get_channels_max(params, - &max_channels)) < 0){ - WARN("Unable to get max channels: %d (%s)\n", err, snd_strerror(err)); - goto exit; - } - -exit: - free(params); - snd_pcm_close(handle); - - return max_channels; -} - -enum AudioDeviceConnectionType { - AudioDeviceConnectionType_Unknown = 0, - AudioDeviceConnectionType_PCI, - AudioDeviceConnectionType_USB -}; - -static NTSTATUS alsa_get_prop_value(void *args) -{ - struct get_prop_value_params *params = args; - const char *name = params->device; - EDataFlow flow = params->flow; - const GUID *guid = params->guid; - const PROPERTYKEY *prop = params->prop; - PROPVARIANT *out = params->value; - static const PROPERTYKEY devicepath_key = { /* undocumented? - {b3f8fa53-0004-438e-9003-51a46e139bfc},2 */ - {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2 - }; - - if(IsEqualPropertyKey(*prop, devicepath_key)) - { - enum AudioDeviceConnectionType connection = AudioDeviceConnectionType_Unknown; - USHORT vendor_id = 0, product_id = 0; - char uevent[MAX_PATH]; - FILE *fuevent = NULL; - int card, device; - UINT serial_number; - char buf[128]; - int len; - - if(sscanf(name, "plughw:%u,%u", &card, &device)){ - sprintf(uevent, "/sys/class/sound/card%u/device/uevent", card); - fuevent = fopen(uevent, "r"); - } - - if(fuevent){ - char line[256]; - - while (fgets(line, sizeof(line), fuevent)) { - char *val; - size_t val_len; - - if((val = strchr(line, '='))) { - val[0] = 0; - val++; - - val_len = strlen(val); - if(val_len > 0 && val[val_len - 1] == '\n') { val[val_len - 1] = 0; } - - if(!strcmp(line, "PCI_ID")){ - connection = AudioDeviceConnectionType_PCI; - if(sscanf(val, "%hX:%hX", &vendor_id, &product_id)<2){ - WARN("Unexpected input when reading PCI_ID in uevent file.\n"); - connection = AudioDeviceConnectionType_Unknown; - break; - } - }else if(!strcmp(line, "DEVTYPE") && !strcmp(val,"usb_interface")) - connection = AudioDeviceConnectionType_USB; - else if(!strcmp(line, "PRODUCT")) - if(sscanf(val, "%hx/%hx/", &vendor_id, &product_id)<2){ - WARN("Unexpected input when reading PRODUCT in uevent file.\n"); - connection = AudioDeviceConnectionType_Unknown; - break; - } - } - } - - fclose(fuevent); - } - - /* As hardly any audio devices have serial numbers, Windows instead - appears to use a persistent random number. We emulate this here - by instead using the last 8 hex digits of the GUID. */ - serial_number = (guid->Data4[4] << 24) | (guid->Data4[5] << 16) | (guid->Data4[6] << 8) | guid->Data4[7]; - - if(connection == AudioDeviceConnectionType_USB) - sprintf(buf, "{1}.USB\\VID_%04X&PID_%04X\\%u&%08X", - vendor_id, product_id, device, serial_number); - else if (connection == AudioDeviceConnectionType_PCI) - sprintf(buf, "{1}.HDAUDIO\\FUNC_01&VEN_%04X&DEV_%04X\\%u&%08X", - vendor_id, product_id, device, serial_number); - else - sprintf(buf, "{1}.ROOT\\MEDIA\\%04u", serial_number & 0x1FF); - - len = strlen(buf) + 1; - if(*params->buffer_size < len * sizeof(WCHAR)){ - params->result = E_NOT_SUFFICIENT_BUFFER; - *params->buffer_size = len * sizeof(WCHAR); - return STATUS_SUCCESS; - } - out->vt = VT_LPWSTR; - out->pwszVal = params->buffer; - ntdll_umbstowcs(buf, len, out->pwszVal, len); - params->result = S_OK; - return STATUS_SUCCESS; - } else if (flow != eCapture && IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers)) { - unsigned int num_speakers, card, device; - char hwname[255]; - - if (sscanf(name, "plughw:%u,%u", &card, &device)) - sprintf(hwname, "hw:%u,%u", card, device); /* must be hw rather than plughw to work */ - else - strcpy(hwname, name); - - num_speakers = alsa_probe_num_speakers(hwname); - if (num_speakers == 0){ - params->result = E_FAIL; - return STATUS_SUCCESS; - } - out->vt = VT_UI4; - - if (num_speakers > 6) - out->ulVal = KSAUDIO_SPEAKER_STEREO; - else if (num_speakers == 6) - out->ulVal = KSAUDIO_SPEAKER_5POINT1; - else if (num_speakers >= 4) - out->ulVal = KSAUDIO_SPEAKER_QUAD; - else if (num_speakers >= 2) - out->ulVal = KSAUDIO_SPEAKER_STEREO; - else if (num_speakers == 1) - out->ulVal = KSAUDIO_SPEAKER_MONO; - - params->result = S_OK; - return STATUS_SUCCESS; - } - - TRACE("Unimplemented property %s,%u\n", wine_dbgstr_guid(&prop->fmtid), (unsigned)prop->pid); - - params->result = E_NOTIMPL; - return STATUS_SUCCESS; -} - -const unixlib_entry_t __wine_unix_call_funcs[] = -{ - NULL, - NULL, - NULL, - alsa_get_endpoint_ids, - alsa_create_stream, - alsa_release_stream, - alsa_start, - alsa_stop, - alsa_reset, - alsa_timer_loop, - alsa_get_render_buffer, - alsa_release_render_buffer, - alsa_get_capture_buffer, - alsa_release_capture_buffer, - alsa_is_format_supported, - alsa_get_mix_format, - NULL, - alsa_get_buffer_size, - alsa_get_latency, - alsa_get_current_padding, - alsa_get_next_packet_size, - alsa_get_frequency, - alsa_get_position, - alsa_set_volumes, - alsa_set_event_handle, - NULL, - alsa_is_started, - alsa_get_prop_value, - NULL, - alsa_midi_release, - alsa_midi_out_message, - alsa_midi_in_message, - alsa_midi_notify_wait, - NULL, -}; - -#ifdef _WIN64 - -typedef UINT PTR32; - -static NTSTATUS alsa_wow64_get_endpoint_ids(void *args) -{ - struct - { - EDataFlow flow; - PTR32 endpoints; - unsigned int size; - HRESULT result; - unsigned int num; - unsigned int default_idx; - } *params32 = args; - struct get_endpoint_ids_params params = - { - .flow = params32->flow, - .endpoints = ULongToPtr(params32->endpoints), - .size = params32->size - }; - alsa_get_endpoint_ids(¶ms); - params32->size = params.size; - params32->result = params.result; - params32->num = params.num; - params32->default_idx = params.default_idx; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_create_stream(void *args) -{ - struct - { - PTR32 name; - PTR32 device; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - DWORD flags; - REFERENCE_TIME duration; - REFERENCE_TIME period; - PTR32 fmt; - HRESULT result; - PTR32 channel_count; - PTR32 stream; - } *params32 = args; - struct create_stream_params params = - { - .name = ULongToPtr(params32->name), - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .share = params32->share, - .flags = params32->flags, - .duration = params32->duration, - .period = params32->period, - .fmt = ULongToPtr(params32->fmt), - .channel_count = ULongToPtr(params32->channel_count), - .stream = ULongToPtr(params32->stream) - }; - alsa_create_stream(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_release_stream(void *args) -{ - struct - { - stream_handle stream; - PTR32 timer_thread; - HRESULT result; - } *params32 = args; - struct release_stream_params params = - { - .stream = params32->stream, - .timer_thread = ULongToHandle(params32->timer_thread) - }; - alsa_release_stream(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_render_buffer(void *args) -{ - struct - { - stream_handle stream; - UINT32 frames; - HRESULT result; - PTR32 data; - } *params32 = args; - BYTE *data = NULL; - struct get_render_buffer_params params = - { - .stream = params32->stream, - .frames = params32->frames, - .data = &data - }; - alsa_get_render_buffer(¶ms); - params32->result = params.result; - *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data); - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_capture_buffer(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 data; - PTR32 frames; - PTR32 flags; - PTR32 devpos; - PTR32 qpcpos; - } *params32 = args; - BYTE *data = NULL; - struct get_capture_buffer_params params = - { - .stream = params32->stream, - .data = &data, - .frames = ULongToPtr(params32->frames), - .flags = ULongToPtr(params32->flags), - .devpos = ULongToPtr(params32->devpos), - .qpcpos = ULongToPtr(params32->qpcpos) - }; - alsa_get_capture_buffer(¶ms); - params32->result = params.result; - *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data); - return STATUS_SUCCESS; -}; - -static NTSTATUS alsa_wow64_is_format_supported(void *args) -{ - struct - { - PTR32 device; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - PTR32 fmt_in; - PTR32 fmt_out; - HRESULT result; - } *params32 = args; - struct is_format_supported_params params = - { - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .share = params32->share, - .fmt_in = ULongToPtr(params32->fmt_in), - .fmt_out = ULongToPtr(params32->fmt_out) - }; - alsa_is_format_supported(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_mix_format(void *args) -{ - struct - { - PTR32 device; - EDataFlow flow; - PTR32 fmt; - HRESULT result; - } *params32 = args; - struct get_mix_format_params params = - { - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .fmt = ULongToPtr(params32->fmt) - }; - alsa_get_mix_format(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_buffer_size(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 frames; - } *params32 = args; - struct get_buffer_size_params params = - { - .stream = params32->stream, - .frames = ULongToPtr(params32->frames) - }; - alsa_get_buffer_size(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_latency(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 latency; - } *params32 = args; - struct get_latency_params params = - { - .stream = params32->stream, - .latency = ULongToPtr(params32->latency) - }; - alsa_get_latency(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_current_padding(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 padding; - } *params32 = args; - struct get_current_padding_params params = - { - .stream = params32->stream, - .padding = ULongToPtr(params32->padding) - }; - alsa_get_current_padding(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_next_packet_size(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 frames; - } *params32 = args; - struct get_next_packet_size_params params = - { - .stream = params32->stream, - .frames = ULongToPtr(params32->frames) - }; - alsa_get_next_packet_size(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_frequency(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 freq; - } *params32 = args; - struct get_frequency_params params = - { - .stream = params32->stream, - .freq = ULongToPtr(params32->freq) - }; - alsa_get_frequency(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_position(void *args) -{ - struct - { - stream_handle stream; - BOOL device; - HRESULT result; - PTR32 pos; - PTR32 qpctime; - } *params32 = args; - struct get_position_params params = - { - .stream = params32->stream, - .device = params32->device, - .pos = ULongToPtr(params32->pos), - .qpctime = ULongToPtr(params32->qpctime) - }; - alsa_get_position(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_set_volumes(void *args) -{ - struct - { - stream_handle stream; - float master_volume; - PTR32 volumes; - PTR32 session_volumes; - int channel; - } *params32 = args; - struct set_volumes_params params = - { - .stream = params32->stream, - .master_volume = params32->master_volume, - .volumes = ULongToPtr(params32->volumes), - .session_volumes = ULongToPtr(params32->session_volumes), - .channel = params32->channel - }; - return alsa_set_volumes(¶ms); -} - -static NTSTATUS alsa_wow64_set_event_handle(void *args) -{ - struct - { - stream_handle stream; - PTR32 event; - HRESULT result; - } *params32 = args; - struct set_event_handle_params params = - { - .stream = params32->stream, - .event = ULongToHandle(params32->event) - }; - - alsa_set_event_handle(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS alsa_wow64_get_prop_value(void *args) -{ - struct propvariant32 - { - WORD vt; - WORD pad1, pad2, pad3; - union - { - ULONG ulVal; - PTR32 ptr; - ULARGE_INTEGER uhVal; - }; - } *value32; - struct - { - PTR32 device; - EDataFlow flow; - PTR32 guid; - PTR32 prop; - HRESULT result; - PTR32 value; - PTR32 buffer; /* caller allocated buffer to hold value's strings */ - PTR32 buffer_size; - } *params32 = args; - PROPVARIANT value; - struct get_prop_value_params params = - { - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .guid = ULongToPtr(params32->guid), - .prop = ULongToPtr(params32->prop), - .value = &value, - .buffer = ULongToPtr(params32->buffer), - .buffer_size = ULongToPtr(params32->buffer_size) - }; - alsa_get_prop_value(¶ms); - params32->result = params.result; - if (SUCCEEDED(params.result)) - { - value32 = UlongToPtr(params32->value); - value32->vt = value.vt; - switch (value.vt) - { - case VT_UI4: - value32->ulVal = value.ulVal; - break; - case VT_LPWSTR: - value32->ptr = params32->buffer; - break; - default: - FIXME("Unhandled vt %04x\n", value.vt); - } - } - return STATUS_SUCCESS; -} - -const unixlib_entry_t __wine_unix_call_wow64_funcs[] = -{ - NULL, - NULL, - NULL, - alsa_wow64_get_endpoint_ids, - alsa_wow64_create_stream, - alsa_wow64_release_stream, - alsa_start, - alsa_stop, - alsa_reset, - alsa_timer_loop, - alsa_wow64_get_render_buffer, - alsa_release_render_buffer, - alsa_wow64_get_capture_buffer, - alsa_release_capture_buffer, - alsa_wow64_is_format_supported, - alsa_wow64_get_mix_format, - NULL, - alsa_wow64_get_buffer_size, - alsa_wow64_get_latency, - alsa_wow64_get_current_padding, - alsa_wow64_get_next_packet_size, - alsa_wow64_get_frequency, - alsa_wow64_get_position, - alsa_wow64_set_volumes, - alsa_wow64_set_event_handle, - NULL, - alsa_is_started, - alsa_wow64_get_prop_value, - NULL, - alsa_midi_release, - alsa_wow64_midi_out_message, - alsa_wow64_midi_in_message, - alsa_wow64_midi_notify_wait, - NULL, -}; - -#endif /* _WIN64 */ diff --git a/pkgs/osu-wine/audio-revert/winealsa.drv/alsamidi.c b/pkgs/osu-wine/audio-revert/winealsa.drv/alsamidi.c deleted file mode 100644 index 8b4207c..0000000 --- a/pkgs/osu-wine/audio-revert/winealsa.drv/alsamidi.c +++ /dev/null @@ -1,1877 +0,0 @@ -/* - * MIDI driver for ALSA (unixlib) - * - * Copyright 1994 Martin Ayotte - * Copyright 1998 Luiz Otavio L. Zorzella - * Copyright 1998, 1999 Eric POUECH - * Copyright 2003 Christian Costa - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#if 0 -#pragma makedep unix -#endif - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winternl.h" -#include "mmdeviceapi.h" -#include "mmddk.h" - -#include "wine/debug.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(midi); - -struct midi_dest -{ - BOOL bEnabled; - MIDIOPENDESC midiDesc; - BYTE runningStatus; - WORD wFlags; - MIDIOUTCAPSW caps; - snd_seq_t *seq; - snd_seq_addr_t addr; - int port_out; -}; - -struct midi_src -{ - int state; /* -1 disabled, 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */ - MIDIOPENDESC midiDesc; - WORD wFlags; - MIDIHDR *lpQueueHdr; - UINT startTime; - MIDIINCAPSW caps; - snd_seq_t *seq; - snd_seq_addr_t addr; - int port_in; -}; - -static pthread_mutex_t seq_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t in_buffer_mutex = PTHREAD_MUTEX_INITIALIZER; - -static unsigned int num_dests, num_srcs; -static struct midi_dest dests[MAX_MIDIOUTDRV]; -static struct midi_src srcs[MAX_MIDIINDRV]; -static snd_seq_t *midi_seq; -static unsigned int seq_refs; -static int port_in = -1; - -static unsigned int num_midi_in_started; -static int rec_cancel_pipe[2]; -static pthread_t rec_thread_id; - -static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t notify_read_cond = PTHREAD_COND_INITIALIZER; -static pthread_cond_t notify_write_cond = PTHREAD_COND_INITIALIZER; -static BOOL notify_quit; -#define NOTIFY_BUFFER_SIZE 64 + 1 /* + 1 for the sentinel */ -static struct notify_context notify_buffer[NOTIFY_BUFFER_SIZE]; -static struct notify_context *notify_read = notify_buffer, *notify_write = notify_buffer; - -static void seq_lock(void) -{ - pthread_mutex_lock(&seq_mutex); -} - -static void seq_unlock(void) -{ - pthread_mutex_unlock(&seq_mutex); -} - -static void in_buffer_lock(void) -{ - pthread_mutex_lock(&in_buffer_mutex); -} - -static void in_buffer_unlock(void) -{ - pthread_mutex_unlock(&in_buffer_mutex); -} - -static uint64_t get_time_msec(void) -{ - struct timespec now = {0, 0}; - -#ifdef CLOCK_MONOTONIC_RAW - if (!clock_gettime(CLOCK_MONOTONIC_RAW, &now)) - return (uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; -#endif - clock_gettime(CLOCK_MONOTONIC, &now); - return (uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; -} - -static void set_in_notify(struct notify_context *notify, struct midi_src *src, WORD dev_id, WORD msg, - UINT_PTR param_1, UINT_PTR param_2) -{ - notify->send_notify = TRUE; - notify->dev_id = dev_id; - notify->msg = msg; - notify->param_1 = param_1; - notify->param_2 = param_2; - notify->callback = src->midiDesc.dwCallback; - notify->flags = src->wFlags; - notify->device = src->midiDesc.hMidi; - notify->instance = src->midiDesc.dwInstance; -} - -/* - * notify buffer: The notification ring buffer is implemented so that - * there is always at least one unused sentinel before the current - * read position in order to allow detection of the full vs empty - * state. - */ -static struct notify_context *notify_buffer_next(struct notify_context *notify) -{ - if (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer)) - notify = notify_buffer; - - return notify; -} - -static BOOL notify_buffer_empty(void) -{ - return notify_read == notify_write; -} - -static BOOL notify_buffer_full(void) -{ - return notify_buffer_next(notify_write) == notify_read; -} - -static BOOL notify_buffer_add(struct notify_context *notify) -{ - if (notify_buffer_full()) return FALSE; - - *notify_write = *notify; - notify_write = notify_buffer_next(notify_write); - return TRUE; -} - -static BOOL notify_buffer_remove(struct notify_context *notify) -{ - if (notify_buffer_empty()) return FALSE; - - *notify = *notify_read; - notify_read = notify_buffer_next(notify_read); - return TRUE; -} - -static void notify_post(struct notify_context *notify) -{ - pthread_mutex_lock(¬ify_mutex); - - if (notify) - { - while (notify_buffer_full()) - pthread_cond_wait(¬ify_write_cond, ¬ify_mutex); - - notify_buffer_add(notify); - } - else notify_quit = TRUE; - pthread_cond_signal(¬ify_read_cond); - - pthread_mutex_unlock(¬ify_mutex); -} - -static snd_seq_t *seq_open(int *port_in_ret) -{ - static int midi_warn; - - seq_lock(); - if (seq_refs == 0) - { - if (snd_seq_open(&midi_seq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) - { - if (!midi_warn) - WARN("Error opening ALSA sequencer.\n"); - midi_warn = 1; - seq_unlock(); - return NULL; - } - snd_seq_set_client_name(midi_seq, "WINE midi driver"); - } - seq_refs++; - - if (port_in_ret) - { - if (port_in < 0) - { - port_in = snd_seq_create_simple_port(midi_seq, "WINE ALSA Input", - SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE, - SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); - if (port_in < 0) - TRACE("Unable to create input port\n"); - else - TRACE("Input port %d created successfully\n", port_in); - } - *port_in_ret = port_in; - } - seq_unlock(); - return midi_seq; -} - -static void seq_close(void) -{ - seq_lock(); - if (--seq_refs == 0) - { - if (port_in >= 0) - { - snd_seq_delete_simple_port(midi_seq, port_in); - port_in = -1; - } - snd_seq_close(midi_seq); - midi_seq = NULL; - } - seq_unlock(); -} - -static int alsa_to_win_device_type(unsigned int type) -{ - /* MOD_MIDIPORT output port - * MOD_SYNTH generic internal synth - * MOD_SQSYNTH square wave internal synth - * MOD_FMSYNTH FM internal synth - * MOD_MAPPER MIDI mapper - * MOD_WAVETABLE hardware wavetable internal synth - * MOD_SWSYNTH software internal synth - */ - - /* FIXME Is this really the correct equivalence from ALSA to - Windows Sound type? */ - - if (type & SND_SEQ_PORT_TYPE_SYNTH) - return MOD_FMSYNTH; - - if (type & (SND_SEQ_PORT_TYPE_DIRECT_SAMPLE|SND_SEQ_PORT_TYPE_SAMPLE)) - return MOD_SYNTH; - - if (type & (SND_SEQ_PORT_TYPE_MIDI_GENERIC|SND_SEQ_PORT_TYPE_APPLICATION)) - return MOD_MIDIPORT; - - ERR("Cannot determine the type (alsa type is %x) of this midi device. Assuming FM Synth\n", type); - return MOD_FMSYNTH; -} - -static void port_add(snd_seq_client_info_t* cinfo, snd_seq_port_info_t* pinfo, unsigned int cap, unsigned int type) -{ - char name[MAXPNAMELEN]; - unsigned int len; - struct midi_dest *dest; - struct midi_src *src; - - if (cap & SND_SEQ_PORT_CAP_WRITE) { - TRACE("OUT (%d:%s:%s:%d:%s:%x)\n",snd_seq_client_info_get_client(cinfo), - snd_seq_client_info_get_name(cinfo), - snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT ? "user" : "kernel", - snd_seq_port_info_get_port(pinfo), - snd_seq_port_info_get_name(pinfo), - type); - - if (num_dests >= MAX_MIDIOUTDRV) - return; - if (!type) - return; - - dest = dests + num_dests; - dest->addr = *snd_seq_port_info_get_addr(pinfo); - - /* Manufac ID. We do not have access to this with soundcard.h - * Does not seem to be a problem, because in mmsystem.h only - * Microsoft's ID is listed. - */ - dest->caps.wMid = 0x00FF; - dest->caps.wPid = 0x0001; /* FIXME Product ID */ - /* Product Version. We simply say "1" */ - dest->caps.vDriverVersion = 0x001; - /* The following are mandatory for MOD_MIDIPORT */ - dest->caps.wChannelMask = 0xFFFF; - dest->caps.wVoices = 0; - dest->caps.wNotes = 0; - dest->caps.dwSupport = 0; - - /* Try to use both client and port names, if this is too long take the port name only. - In the second case the port name should be explicit enough due to its big size. - */ - len = strlen(snd_seq_port_info_get_name(pinfo)); - if ( (strlen(snd_seq_client_info_get_name(cinfo)) + len + 3) < sizeof(name) ) { - sprintf(name, "%s - %s", snd_seq_client_info_get_name(cinfo), snd_seq_port_info_get_name(pinfo)); - len = strlen(name); - } else { - len = min(len, sizeof(name) - 1); - memcpy(name, snd_seq_port_info_get_name(pinfo), len); - name[len] = '\0'; - } - ntdll_umbstowcs( name, len + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname)); - - dest->caps.wTechnology = alsa_to_win_device_type(type); - - if (MOD_MIDIPORT != dest->caps.wTechnology) { - /* FIXME Do we have this information? - * Assuming the soundcards can handle - * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but - * not MIDICAPS_CACHE. - */ - dest->caps.dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME; - dest->caps.wVoices = 16; - - /* FIXME Is it possible to know the maximum - * number of simultaneous notes of a soundcard ? - * I believe we don't have this information, but - * it's probably equal or more than wVoices - */ - dest->caps.wNotes = 16; - } - dest->bEnabled = TRUE; - dest->port_out = -1; - - TRACE("MidiOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n" - "\tALSA info: midi dev-type=%x, capa=0\n", - num_dests, wine_dbgstr_w(dest->caps.szPname), - dest->caps.wTechnology, - dest->caps.wVoices, dest->caps.wNotes, - dest->caps.wChannelMask, (unsigned)dest->caps.dwSupport, - type); - - num_dests++; - } - if (cap & SND_SEQ_PORT_CAP_READ) { - TRACE("IN (%d:%s:%s:%d:%s:%x)\n",snd_seq_client_info_get_client(cinfo), - snd_seq_client_info_get_name(cinfo), - snd_seq_client_info_get_type(cinfo) == SND_SEQ_USER_CLIENT ? "user" : "kernel", - snd_seq_port_info_get_port(pinfo), - snd_seq_port_info_get_name(pinfo), - type); - - if (num_srcs >= MAX_MIDIINDRV) - return; - if (!type) - return; - - src = srcs + num_srcs; - src->addr = *snd_seq_port_info_get_addr(pinfo); - - /* Manufac ID. We do not have access to this with soundcard.h - * Does not seem to be a problem, because in mmsystem.h only - * Microsoft's ID is listed. - */ - src->caps.wMid = 0x00FF; - src->caps.wPid = 0x0001; /* FIXME Product ID */ - /* Product Version. We simply say "1" */ - src->caps.vDriverVersion = 0x001; - src->caps.dwSupport = 0; /* mandatory with MIDIINCAPS */ - - /* Try to use both client and port names, if this is too long take the port name only. - In the second case the port name should be explicit enough due to its big size. - */ - len = strlen(snd_seq_port_info_get_name(pinfo)); - if ( (strlen(snd_seq_client_info_get_name(cinfo)) + len + 3) < sizeof(name) ) { - sprintf(name, "%s - %s", snd_seq_client_info_get_name(cinfo), snd_seq_port_info_get_name(pinfo)); - len = strlen(name); - } else { - len = min(len, sizeof(name) - 1); - memcpy(name, snd_seq_port_info_get_name(pinfo), len); - name[len] = '\0'; - } - ntdll_umbstowcs( name, len + 1, src->caps.szPname, ARRAY_SIZE(src->caps.szPname)); - src->state = 0; - - TRACE("MidiIn [%d]\tname='%s' support=%d\n" - "\tALSA info: midi dev-type=%x, capa=0\n", - num_srcs, wine_dbgstr_w(src->caps.szPname), (unsigned)src->caps.dwSupport, type); - - num_srcs++; - } -} - -static UINT alsa_midi_init(void) -{ - static BOOL init_done; - snd_seq_client_info_t *cinfo; - snd_seq_port_info_t *pinfo; - snd_seq_t *seq; - - if (init_done) - return ERROR_ALREADY_INITIALIZED; - - TRACE("Initializing the MIDI variables.\n"); - init_done = TRUE; - - /* try to open device */ - if (!(seq = seq_open(NULL))) - return ERROR_OPEN_FAILED; - - cinfo = calloc( 1, snd_seq_client_info_sizeof() ); - pinfo = calloc( 1, snd_seq_port_info_sizeof() ); - - /* First, search for all internal midi devices */ - snd_seq_client_info_set_client(cinfo, -1); - while (snd_seq_query_next_client(seq, cinfo) >= 0) { - snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); - snd_seq_port_info_set_port(pinfo, -1); - while (snd_seq_query_next_port(seq, pinfo) >= 0) { - unsigned int cap = snd_seq_port_info_get_capability(pinfo); - unsigned int type = snd_seq_port_info_get_type(pinfo); - if (!(type & SND_SEQ_PORT_TYPE_PORT)) - port_add(cinfo, pinfo, cap, type); - } - } - - /* Second, search for all external ports */ - snd_seq_client_info_set_client(cinfo, -1); - while (snd_seq_query_next_client(seq, cinfo) >= 0) { - snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo)); - snd_seq_port_info_set_port(pinfo, -1); - while (snd_seq_query_next_port(seq, pinfo) >= 0) { - unsigned int cap = snd_seq_port_info_get_capability(pinfo); - unsigned int type = snd_seq_port_info_get_type(pinfo); - if (type & SND_SEQ_PORT_TYPE_PORT) - port_add(cinfo, pinfo, cap, type); - } - } - seq_close(); - free( cinfo ); - free( pinfo ); - - TRACE("End\n"); - - return NOERROR; -} - -NTSTATUS alsa_midi_release(void *args) -{ - /* stop the notify_wait thread */ - notify_post(NULL); - - return STATUS_SUCCESS; -} - -static void set_out_notify(struct notify_context *notify, struct midi_dest *dest, WORD dev_id, WORD msg, - UINT_PTR param_1, UINT_PTR param_2) -{ - notify->send_notify = TRUE; - notify->dev_id = dev_id; - notify->msg = msg; - notify->param_1 = param_1; - notify->param_2 = param_2; - notify->callback = dest->midiDesc.dwCallback; - notify->flags = dest->wFlags; - notify->device = dest->midiDesc.hMidi; - notify->instance = dest->midiDesc.dwInstance; -} - -static UINT midi_out_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, struct notify_context *notify) -{ - int ret; - int port_out; - char port_out_name[32]; - snd_seq_t *midi_seq; - struct midi_dest *dest; - - TRACE("(%04X, %p, %08X);\n", dev_id, midi_desc, flags); - - if (midi_desc == NULL) - { - WARN("Invalid Parameter !\n"); - return MMSYSERR_INVALPARAM; - } - if (dev_id >= num_dests) - { - TRACE("MAX_MIDIOUTDRV reached !\n"); - return MMSYSERR_BADDEVICEID; - } - dest = dests + dev_id; - if (dest->midiDesc.hMidi != 0) - { - WARN("device already open !\n"); - return MMSYSERR_ALLOCATED; - } - if (!dest->bEnabled) - { - WARN("device disabled !\n"); - return MIDIERR_NODEVICE; - } - if ((flags & ~CALLBACK_TYPEMASK) != 0) - { - WARN("bad dwFlags\n"); - return MMSYSERR_INVALFLAG; - } - - switch (dest->caps.wTechnology) - { - case MOD_FMSYNTH: - case MOD_MIDIPORT: - case MOD_SYNTH: - if (!(midi_seq = seq_open(NULL))) - return MMSYSERR_ALLOCATED; - break; - default: - WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology); - return MMSYSERR_NOTENABLED; - } - - dest->runningStatus = 0; - dest->wFlags = HIWORD(flags & CALLBACK_TYPEMASK); - dest->midiDesc = *midi_desc; - dest->seq = midi_seq; - - seq_lock(); - /* Create a port dedicated to a specific device */ - /* Keep the old name without a number for the first port */ - if (dev_id) - sprintf(port_out_name, "WINE ALSA Output #%d", dev_id); - - port_out = snd_seq_create_simple_port(midi_seq, dev_id ? port_out_name : "WINE ALSA Output", - SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ | SND_SEQ_PORT_CAP_SUBS_WRITE, - SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION); - - if (port_out < 0) - { - TRACE("Unable to create output port\n"); - dest->port_out = -1; - } - else - { - TRACE("Output port %d created successfully\n", port_out); - dest->port_out = port_out; - - /* Connect our app port to the device port */ - ret = snd_seq_connect_to(midi_seq, port_out, dest->addr.client, dest->addr.port); - - /* usually will happen when the port is already connected */ - /* other errors should not be fatal either */ - if (ret < 0) - WARN("Could not connect port %d to %d:%d: %s\n", dev_id, dest->addr.client, - dest->addr.port, snd_strerror(ret)); - } - seq_unlock(); - - if (port_out < 0) - return MMSYSERR_NOTENABLED; - - TRACE("Output port :%d connected %d:%d\n", port_out, dest->addr.client, dest->addr.port); - - set_out_notify(notify, dest, dev_id, MOM_OPEN, 0, 0); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_close(WORD dev_id, struct notify_context *notify) -{ - struct midi_dest *dest; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - - dest = dests + dev_id; - - if (dest->midiDesc.hMidi == 0) - { - WARN("device not opened !\n"); - return MMSYSERR_ERROR; - } - - /* FIXME: should test that no pending buffer is still in the queue for - * playing */ - - if (dest->seq == NULL) - { - WARN("can't close !\n"); - return MMSYSERR_ERROR; - } - - switch (dest->caps.wTechnology) - { - case MOD_FMSYNTH: - case MOD_MIDIPORT: - case MOD_SYNTH: - seq_lock(); - TRACE("Deleting port :%d, connected to %d:%d\n", dest->port_out, dest->addr.client, dest->addr.port); - snd_seq_delete_simple_port(dest->seq, dest->port_out); - dest->port_out = -1; - seq_unlock(); - seq_close(); - dest->seq = NULL; - break; - default: - WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology); - return MMSYSERR_NOTENABLED; - } - - set_out_notify(notify, dest, dev_id, MOM_CLOSE, 0, 0); - - dest->midiDesc.hMidi = 0; - - return MMSYSERR_NOERROR; -} - -static UINT midi_out_data(WORD dev_id, UINT data) -{ - BYTE evt = LOBYTE(LOWORD(data)), d1, d2; - struct midi_dest *dest; - - TRACE("(%04X, %08X);\n", dev_id, data); - - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - dest = dests + dev_id; - - if (!dest->bEnabled) return MIDIERR_NODEVICE; - - if (dest->seq == NULL) - { - WARN("can't play !\n"); - return MIDIERR_NODEVICE; - } - - if (evt & 0x80) - { - d1 = HIBYTE(LOWORD(data)); - d2 = LOBYTE(HIWORD(data)); - if (evt < 0xF0) - dest->runningStatus = evt; - else if (evt <= 0xF7) - dest->runningStatus = 0; - } - else if (dest->runningStatus) - { - evt = dest->runningStatus; - d1 = LOBYTE(LOWORD(data)); - d2 = HIBYTE(LOWORD(data)); - } - else - { - FIXME("ooch %x\n", data); - return MMSYSERR_NOERROR; - } - - switch (dest->caps.wTechnology) - { - case MOD_SYNTH: - case MOD_MIDIPORT: - { - int handled = 1; /* Assume event is handled */ - snd_seq_event_t event; - snd_seq_ev_clear(&event); - snd_seq_ev_set_direct(&event); - snd_seq_ev_set_source(&event, dest->port_out); - snd_seq_ev_set_subs(&event); - - switch (evt & 0xF0) - { - case MIDI_CMD_NOTE_OFF: - snd_seq_ev_set_noteoff(&event, evt & 0x0F, d1, d2); - break; - case MIDI_CMD_NOTE_ON: - snd_seq_ev_set_noteon(&event, evt & 0x0F, d1, d2); - break; - case MIDI_CMD_NOTE_PRESSURE: - snd_seq_ev_set_keypress(&event, evt & 0x0F, d1, d2); - break; - case MIDI_CMD_CONTROL: - snd_seq_ev_set_controller(&event, evt & 0x0F, d1, d2); - break; - case MIDI_CMD_BENDER: - snd_seq_ev_set_pitchbend(&event, evt & 0x0F, ((WORD)d2 << 7 | (WORD)d1) - 0x2000); - break; - case MIDI_CMD_PGM_CHANGE: - snd_seq_ev_set_pgmchange(&event, evt & 0x0F, d1); - break; - case MIDI_CMD_CHANNEL_PRESSURE: - snd_seq_ev_set_chanpress(&event, evt & 0x0F, d1); - break; - case MIDI_CMD_COMMON_SYSEX: - switch (evt & 0x0F) - { - case 0x00: /* System Exclusive, don't do it on modData, - * should require modLongData*/ - case 0x04: /* Undefined. */ - case 0x05: /* Undefined. */ - case 0x07: /* End of Exclusive. */ - case 0x09: /* Undefined. */ - case 0x0D: /* Undefined. */ - handled = 0; - break; - case 0x06: /* Tune Request */ - case 0x08: /* Timing Clock. */ - case 0x0A: /* Start. */ - case 0x0B: /* Continue */ - case 0x0C: /* Stop */ - case 0x0E: /* Active Sensing. */ - { - snd_midi_event_t *midi_event; - - snd_midi_event_new(1, &midi_event); - snd_midi_event_init(midi_event); - snd_midi_event_encode_byte(midi_event, evt, &event); - snd_midi_event_free(midi_event); - break; - } - case 0x0F: /* Reset */ - /* snd_seq_ev_set_sysex(&event, 1, &evt); - this other way may be better */ - { - BYTE reset_sysex_seq[] = {MIDI_CMD_COMMON_SYSEX, 0x7e, 0x7f, 0x09, 0x01, 0xf7}; - snd_seq_ev_set_sysex(&event, sizeof(reset_sysex_seq), reset_sysex_seq); - dest->runningStatus = 0; - break; - } - case 0x01: /* MTC Quarter frame */ - case 0x03: /* Song Select. */ - { - BYTE buf[2]; - buf[0] = evt; - buf[1] = d1; - snd_seq_ev_set_sysex(&event, sizeof(buf), buf); - break; - } - case 0x02: /* Song Position Pointer. */ - { - BYTE buf[3]; - buf[0] = evt; - buf[1] = d1; - buf[2] = d2; - snd_seq_ev_set_sysex(&event, sizeof(buf), buf); - break; - } - } - break; - } - if (handled) - { - seq_lock(); - snd_seq_event_output_direct(dest->seq, &event); - seq_unlock(); - } - break; - } - default: - WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology); - return MMSYSERR_NOTENABLED; - } - - return MMSYSERR_NOERROR; -} - -static UINT midi_out_long_data(WORD dev_id, MIDIHDR *hdr, UINT hdr_size, struct notify_context *notify) -{ - struct midi_dest *dest; - int len_add = 0; - BYTE *data, *new_data = NULL; - snd_seq_event_t event; - - TRACE("(%04X, %p, %08X);\n", dev_id, hdr, hdr_size); - - /* Note: MS doc does not say much about the dwBytesRecorded member of the MIDIHDR structure - * but it seems to be used only for midi input. - * Taking a look at the WAVEHDR structure (which is quite similar) confirms this assumption. - */ - - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - dest = dests + dev_id; - - if (!dest->bEnabled) return MIDIERR_NODEVICE; - - if (dest->seq == NULL) - { - WARN("can't play !\n"); - return MIDIERR_NODEVICE; - } - - data = (BYTE*)hdr->lpData; - - if (data == NULL) - return MIDIERR_UNPREPARED; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MIDIERR_UNPREPARED; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - hdr->dwFlags &= ~MHDR_DONE; - hdr->dwFlags |= MHDR_INQUEUE; - - /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive - * data, or can it also contain raw MIDI data, to be split up and sent to - * modShortData() ? - * If the latest is true, then the following WARNing will fire up - */ - if (data[0] != 0xF0 || data[hdr->dwBufferLength - 1] != 0xF7) - { - WARN("Alleged system exclusive buffer is not correct\n\tPlease report with MIDI file\n"); - new_data = malloc(hdr->dwBufferLength + 2); - } - - TRACE("dwBufferLength=%u !\n", (unsigned)hdr->dwBufferLength); - TRACE(" %02X %02X %02X ... %02X %02X %02X\n", - data[0], data[1], data[2], data[hdr->dwBufferLength-3], - data[hdr->dwBufferLength-2], data[hdr->dwBufferLength-1]); - - switch (dest->caps.wTechnology) - { - case MOD_FMSYNTH: - /* FIXME: I don't think there is much to do here */ - free(new_data); - break; - case MOD_MIDIPORT: - if (data[0] != 0xF0) - { - /* Send start of System Exclusive */ - len_add = 1; - new_data[0] = 0xF0; - memcpy(new_data + 1, data, hdr->dwBufferLength); - WARN("Adding missing 0xF0 marker at the beginning of system exclusive byte stream\n"); - } - if (data[hdr->dwBufferLength-1] != 0xF7) - { - /* Send end of System Exclusive */ - if (!len_add) - memcpy(new_data, data, hdr->dwBufferLength); - new_data[hdr->dwBufferLength + len_add] = 0xF7; - len_add++; - WARN("Adding missing 0xF7 marker at the end of system exclusive byte stream\n"); - } - snd_seq_ev_clear(&event); - snd_seq_ev_set_direct(&event); - snd_seq_ev_set_source(&event, dest->port_out); - snd_seq_ev_set_subs(&event); - snd_seq_ev_set_sysex(&event, hdr->dwBufferLength + len_add, new_data ? new_data : data); - seq_lock(); - snd_seq_event_output_direct(dest->seq, &event); - seq_unlock(); - free(new_data); - break; - default: - WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology); - free(new_data); - return MMSYSERR_NOTENABLED; - } - - dest->runningStatus = 0; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - set_out_notify(notify, dest, dev_id, MOM_DONE, (DWORD_PTR)hdr, 0); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -static UINT midi_out_get_devcaps(WORD dev_id, MIDIOUTCAPSW *caps, UINT size) -{ - TRACE("(%04X, %p, %08X);\n", dev_id, caps, size); - - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - if (!caps) return MMSYSERR_INVALPARAM; - - memcpy(caps, &dests[dev_id].caps, min(size, sizeof(*caps))); - - return MMSYSERR_NOERROR; -} - -static UINT midi_out_get_volume(WORD dev_id, UINT* volume) -{ - if (!volume) return MMSYSERR_INVALPARAM; - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - - *volume = 0xFFFFFFFF; - return (dests[dev_id].caps.dwSupport & MIDICAPS_VOLUME) ? 0 : MMSYSERR_NOTSUPPORTED; -} - -static UINT midi_out_reset(WORD dev_id) -{ - unsigned chn; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - if (!dests[dev_id].bEnabled) return MIDIERR_NODEVICE; - - /* stop all notes */ - for (chn = 0; chn < 16; chn++) - { - /* turn off every note */ - midi_out_data(dev_id, (MIDI_CTL_ALL_SOUNDS_OFF << 8) | MIDI_CMD_CONTROL | chn); - /* remove sustain on all channels */ - midi_out_data(dev_id, (MIDI_CTL_SUSTAIN << 8) | MIDI_CMD_CONTROL | chn); - } - dests[dev_id].runningStatus = 0; - /* FIXME: the LongData buffers must also be returned to the app */ - return MMSYSERR_NOERROR; -} - -static void handle_sysex_event(struct midi_src *src, BYTE *data, UINT len) -{ - UINT pos = 0, copy_len, current_time = get_time_msec() - src->startTime; - struct notify_context notify; - MIDIHDR *hdr; - - in_buffer_lock(); - - while (len) - { - hdr = src->lpQueueHdr; - if (!hdr) break; - - copy_len = min(len, hdr->dwBufferLength - hdr->dwBytesRecorded); - memcpy(hdr->lpData + hdr->dwBytesRecorded, data + pos, copy_len); - hdr->dwBytesRecorded += copy_len; - len -= copy_len; - pos += copy_len; - - if ((hdr->dwBytesRecorded == hdr->dwBufferLength) || - (*(BYTE*)(hdr->lpData + hdr->dwBytesRecorded - 1) == 0xF7)) - { /* buffer full or end of sysex message */ - src->lpQueueHdr = hdr->lpNext; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - set_in_notify(¬ify, src, src - srcs, MIM_LONGDATA, (DWORD_PTR)hdr, current_time); - notify_post(¬ify); - } - } - - in_buffer_unlock(); -} - -static void handle_regular_event(struct midi_src *src, snd_seq_event_t *ev) -{ - UINT data = 0, value, current_time = get_time_msec() - src->startTime; - struct notify_context notify; - - switch (ev->type) - { - case SND_SEQ_EVENT_NOTEOFF: - data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_OFF | ev->data.control.channel; - break; - case SND_SEQ_EVENT_NOTEON: - data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_ON | ev->data.control.channel; - break; - case SND_SEQ_EVENT_KEYPRESS: - data = (ev->data.note.velocity << 16) | (ev->data.note.note << 8) | MIDI_CMD_NOTE_PRESSURE | ev->data.control.channel; - break; - case SND_SEQ_EVENT_CONTROLLER: - data = (ev->data.control.value << 16) | (ev->data.control.param << 8) | MIDI_CMD_CONTROL | ev->data.control.channel; - break; - case SND_SEQ_EVENT_PITCHBEND: - value = ev->data.control.value + 0x2000; - data = (((value >> 7) & 0x7f) << 16) | ((value & 0x7f) << 8) | MIDI_CMD_BENDER | ev->data.control.channel; - break; - case SND_SEQ_EVENT_PGMCHANGE: - data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_PGM_CHANGE | ev->data.control.channel; - break; - case SND_SEQ_EVENT_CHANPRESS: - data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_CHANNEL_PRESSURE | ev->data.control.channel; - break; - case SND_SEQ_EVENT_CLOCK: - data = 0xF8; - break; - case SND_SEQ_EVENT_START: - data = 0xFA; - break; - case SND_SEQ_EVENT_CONTINUE: - data = 0xFB; - break; - case SND_SEQ_EVENT_STOP: - data = 0xFC; - break; - case SND_SEQ_EVENT_SONGPOS: - data = (((ev->data.control.value >> 7) & 0x7f) << 16) | ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_POS; - break; - case SND_SEQ_EVENT_SONGSEL: - data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_SONG_SELECT; - break; - case SND_SEQ_EVENT_RESET: - data = 0xFF; - break; - case SND_SEQ_EVENT_QFRAME: - data = ((ev->data.control.value & 0x7f) << 8) | MIDI_CMD_COMMON_MTC_QUARTER; - break; - case SND_SEQ_EVENT_SENSING: - /* Noting to do */ - break; - } - - if (data != 0) - { - set_in_notify(¬ify, src, src - srcs, MIM_DATA, data, current_time); - notify_post(¬ify); - } -} - -static void midi_handle_event(snd_seq_event_t *ev) -{ - struct midi_src *src; - - /* Find the target device */ - for (src = srcs; src < srcs + num_srcs; src++) - if ((ev->source.client == src->addr.client) && (ev->source.port == src->addr.port)) - break; - if ((src == srcs + num_srcs) || (src->state != 1)) - return; - - if (ev->type == SND_SEQ_EVENT_SYSEX) - handle_sysex_event(src, ev->data.ext.ptr, ev->data.ext.len); - else - handle_regular_event(src, ev); -} - -static void *rec_thread_proc(void *arg) -{ - snd_seq_t *midi_seq = (snd_seq_t *)arg; - int num_fds; - struct pollfd *pollfd; - int ret; - - /* Add on one for the read end of the cancel pipe */ - num_fds = snd_seq_poll_descriptors_count(midi_seq, POLLIN) + 1; - pollfd = malloc(num_fds * sizeof(struct pollfd)); - - while(1) - { - pollfd[0].fd = rec_cancel_pipe[0]; - pollfd[0].events = POLLIN; - - seq_lock(); - snd_seq_poll_descriptors(midi_seq, pollfd + 1, num_fds - 1, POLLIN); - seq_unlock(); - - /* Check if an event is present */ - if (poll(pollfd, num_fds, -1) <= 0) - continue; - - if (pollfd[0].revents & POLLIN) /* cancelled */ - break; - - do - { - snd_seq_event_t *ev; - - seq_lock(); - snd_seq_event_input(midi_seq, &ev); - seq_unlock(); - - if (ev) - { - midi_handle_event(ev); - snd_seq_free_event(ev); - } - - seq_lock(); - ret = snd_seq_event_input_pending(midi_seq, 0); - seq_unlock(); - } while(ret > 0); - } - - free(pollfd); - return 0; -} - -static UINT midi_in_open(WORD dev_id, MIDIOPENDESC *desc, UINT flags, struct notify_context *notify) -{ - struct midi_src *src; - int ret = 0, port_in; - snd_seq_t *midi_seq; - - TRACE("(%04X, %p, %08X);\n", dev_id, desc, flags); - - if (!desc) - { - WARN("Invalid Parameter !\n"); - return MMSYSERR_INVALPARAM; - } - - /* FIXME: check that contents of desc are correct */ - - if (dev_id >= num_srcs) - { - WARN("dev_id too large (%u) !\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - src = srcs + dev_id; - - if (src->state == -1) - { - WARN("device disabled\n"); - return MIDIERR_NODEVICE; - } - if (src->midiDesc.hMidi) - { - WARN("device already open !\n"); - return MMSYSERR_ALLOCATED; - } - if (flags & MIDI_IO_STATUS) - { - WARN("No support for MIDI_IO_STATUS in flags yet, ignoring it\n"); - flags &= ~MIDI_IO_STATUS; - } - if (flags & ~CALLBACK_TYPEMASK) - { - FIXME("Bad flags %08X\n", flags); - return MMSYSERR_INVALFLAG; - } - - if (!(midi_seq = seq_open(&port_in))) - return MMSYSERR_ERROR; - - src->wFlags = HIWORD(flags & CALLBACK_TYPEMASK); - - src->lpQueueHdr = NULL; - src->midiDesc = *desc; - src->state = 0; - src->startTime = 0; - src->seq = midi_seq; - src->port_in = port_in; - - /* Connect our app port to the device port */ - seq_lock(); - ret = snd_seq_connect_from(midi_seq, port_in, src->addr.client, src->addr.port); - seq_unlock(); - if (ret < 0) - return MMSYSERR_NOTENABLED; - - TRACE("Input port :%d connected %d:%d\n", port_in, src->addr.client, src->addr.port); - - if (num_midi_in_started++ == 0) - { - pipe(rec_cancel_pipe); - if (pthread_create(&rec_thread_id, NULL, rec_thread_proc, midi_seq)) - { - close(rec_cancel_pipe[0]); - close(rec_cancel_pipe[1]); - num_midi_in_started = 0; - WARN("Couldn't create thread for midi-in\n"); - seq_close(); - return MMSYSERR_ERROR; - } - } - - set_in_notify(notify, src, dev_id, MIM_OPEN, 0, 0); - return MMSYSERR_NOERROR; -} - -static UINT midi_in_close(WORD dev_id, struct notify_context *notify) -{ - struct midi_src *src; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_srcs) - { - WARN("dev_id too big (%u) !\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - src = srcs + dev_id; - if (!src->midiDesc.hMidi) - { - WARN("device not opened !\n"); - return MMSYSERR_ERROR; - } - if (src->lpQueueHdr) - return MIDIERR_STILLPLAYING; - - if (src->seq == NULL) - { - WARN("ooops !\n"); - return MMSYSERR_ERROR; - } - if (--num_midi_in_started == 0) - { - TRACE("Stopping thread for midi-in\n"); - write(rec_cancel_pipe[1], "x", 1); - pthread_join(rec_thread_id, NULL); - close(rec_cancel_pipe[0]); - close(rec_cancel_pipe[1]); - TRACE("Stopped thread for midi-in\n"); - } - - seq_lock(); - snd_seq_disconnect_from(src->seq, src->port_in, src->addr.client, src->addr.port); - seq_unlock(); - seq_close(); - - set_in_notify(notify, src, dev_id, MIM_CLOSE, 0, 0); - src->midiDesc.hMidi = 0; - src->seq = NULL; - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - struct midi_src *src; - MIDIHDR **next; - - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - src = srcs + dev_id; - if (src->state == -1) return MIDIERR_NODEVICE; - - if (!hdr || hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr->dwBufferLength) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; - if (!(hdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; - - in_buffer_lock(); - - hdr->dwFlags &= ~WHDR_DONE; - hdr->dwFlags |= MHDR_INQUEUE; - hdr->dwBytesRecorded = 0; - hdr->lpNext = NULL; - - next = &src->lpQueueHdr; - while (*next) next = &(*next)->lpNext; - *next = hdr; - - in_buffer_unlock(); - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_get_devcaps(WORD dev_id, MIDIINCAPSW *caps, UINT size) -{ - TRACE("(%04X, %p, %08X);\n", dev_id, caps, size); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - if (!caps) return MMSYSERR_INVALPARAM; - - memcpy(caps, &srcs[dev_id].caps, min(size, sizeof(*caps))); - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_start(WORD dev_id) -{ - struct midi_src *src; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - src = srcs + dev_id; - if (src->state == -1) return MIDIERR_NODEVICE; - - src->state = 1; - src->startTime = get_time_msec(); - return MMSYSERR_NOERROR; -} - -static UINT midi_in_stop(WORD dev_id) -{ - struct midi_src *src; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - src = srcs + dev_id; - if (src->state == -1) return MIDIERR_NODEVICE; - - src->state = 0; - return MMSYSERR_NOERROR; -} - -static DWORD midi_in_reset(WORD dev_id, struct notify_context *notify) -{ - UINT cur_time = get_time_msec(); - UINT err = MMSYSERR_NOERROR; - struct midi_src *src; - MIDIHDR *hdr; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - src = srcs + dev_id; - if (src->state == -1) return MIDIERR_NODEVICE; - - in_buffer_lock(); - - if (src->lpQueueHdr) - { - hdr = src->lpQueueHdr; - src->lpQueueHdr = hdr->lpNext; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - set_in_notify(notify, src, dev_id, MIM_LONGDATA, (DWORD_PTR)hdr, cur_time - src->startTime); - if (src->lpQueueHdr) err = ERROR_RETRY; /* ask the client to call again */ - } - - in_buffer_unlock(); - - return err; -} - -NTSTATUS alsa_midi_out_message(void *args) -{ - struct midi_out_message_params *params = args; - - params->notify->send_notify = FALSE; - - switch (params->msg) - { - case DRVM_INIT: - *params->err = alsa_midi_init(); - break; - case DRVM_EXIT: - case DRVM_ENABLE: - case DRVM_DISABLE: - /* FIXME: Pretend this is supported */ - *params->err = MMSYSERR_NOERROR; - break; - case MODM_OPEN: - *params->err = midi_out_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify); - break; - case MODM_CLOSE: - *params->err = midi_out_close(params->dev_id, params->notify); - break; - case MODM_DATA: - *params->err = midi_out_data(params->dev_id, params->param_1); - break; - case MODM_LONGDATA: - *params->err = midi_out_long_data(params->dev_id, (MIDIHDR *)params->param_1, params->param_2, params->notify); - break; - case MODM_PREPARE: - *params->err = midi_out_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MODM_UNPREPARE: - *params->err = midi_out_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MODM_GETDEVCAPS: - *params->err = midi_out_get_devcaps(params->dev_id, (MIDIOUTCAPSW *)params->param_1, params->param_2); - break; - case MODM_GETNUMDEVS: - *params->err = num_dests; - break; - case MODM_GETVOLUME: - *params->err = midi_out_get_volume(params->dev_id, (UINT *)params->param_1); - break; - case MODM_SETVOLUME: - *params->err = 0; - break; - case MODM_RESET: - *params->err = midi_out_reset(params->dev_id); - break; - default: - TRACE("Unsupported message\n"); - *params->err = MMSYSERR_NOTSUPPORTED; - } - - return STATUS_SUCCESS; -} - -NTSTATUS alsa_midi_in_message(void *args) -{ - struct midi_in_message_params *params = args; - - params->notify->send_notify = FALSE; - - switch (params->msg) - { - case DRVM_INIT: - *params->err = alsa_midi_init(); - break; - case DRVM_EXIT: - case DRVM_ENABLE: - case DRVM_DISABLE: - /* FIXME: Pretend this is supported */ - *params->err = MMSYSERR_NOERROR; - break; - case MIDM_OPEN: - *params->err = midi_in_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify); - break; - case MIDM_CLOSE: - *params->err = midi_in_close(params->dev_id, params->notify); - break; - case MIDM_ADDBUFFER: - *params->err = midi_in_add_buffer(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_PREPARE: - *params->err = midi_in_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_UNPREPARE: - *params->err = midi_in_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_GETDEVCAPS: - *params->err = midi_in_get_devcaps(params->dev_id, (MIDIINCAPSW *)params->param_1, params->param_2); - break; - case MIDM_GETNUMDEVS: - *params->err = num_srcs; - break; - case MIDM_START: - *params->err = midi_in_start(params->dev_id); - break; - case MIDM_STOP: - *params->err = midi_in_stop(params->dev_id); - break; - case MIDM_RESET: - *params->err = midi_in_reset(params->dev_id, params->notify); - break; - default: - TRACE("Unsupported message\n"); - *params->err = MMSYSERR_NOTSUPPORTED; - } - - return STATUS_SUCCESS; -} - -NTSTATUS alsa_midi_notify_wait(void *args) -{ - struct midi_notify_wait_params *params = args; - - pthread_mutex_lock(¬ify_mutex); - - while (!notify_quit && notify_buffer_empty()) - pthread_cond_wait(¬ify_read_cond, ¬ify_mutex); - - *params->quit = notify_quit; - if (!notify_quit) - { - notify_buffer_remove(params->notify); - pthread_cond_signal(¬ify_write_cond); - } - pthread_mutex_unlock(¬ify_mutex); - - return STATUS_SUCCESS; -} - -#ifdef _WIN64 - -typedef UINT PTR32; - -struct notify_context32 -{ - BOOL send_notify; - WORD dev_id; - WORD msg; - UINT param_1; - UINT param_2; - UINT callback; - UINT flags; - PTR32 device; - UINT instance; -}; - -static void notify_to_notify32(struct notify_context32 *notify32, - const struct notify_context *notify) -{ - notify32->send_notify = notify->send_notify; - notify32->dev_id = notify->dev_id; - notify32->msg = notify->msg; - notify32->param_1 = notify->param_1; - notify32->param_2 = notify->param_2; - notify32->callback = notify->callback; - notify32->flags = notify->flags; - notify32->device = PtrToUlong(notify->device); - notify32->instance = notify->instance; -} - -struct midi_open_desc32 -{ - PTR32 hMidi; - UINT dwCallback; - UINT dwInstance; - UINT dnDevNode; - UINT cIds; - MIDIOPENSTRMID rgIds; -}; - -struct midi_hdr32 -{ - PTR32 lpData; - UINT dwBufferLength; - UINT dwBytesRecorded; - UINT dwUser; - UINT dwFlags; - PTR32 lpNext; - UINT reserved; - UINT dwOffset; - UINT dwReserved[8]; -}; - -static UINT wow64_midi_out_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - return MMSYSERR_NOERROR; -} - -static UINT wow64_midi_out_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -NTSTATUS alsa_wow64_midi_out_message(void *args) -{ - struct - { - UINT dev_id; - UINT msg; - UINT user; - UINT param_1; - UINT param_2; - PTR32 err; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_open_desc32 *desc32; - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIOPENDESC open_desc; - MIDIHDR hdr; - struct midi_out_message_params params = - { - .dev_id = params32->dev_id, - .msg = params32->msg, - .user = params32->user, - .param_1 = params32->param_1, - .param_2 = params32->param_2, - .err = ULongToPtr(params32->err), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - switch (params32->msg) - { - case MODM_OPEN: - desc32 = ULongToPtr(params32->param_1); - - open_desc.hMidi = ULongToPtr(desc32->hMidi); - open_desc.dwCallback = desc32->dwCallback; - open_desc.dwInstance = desc32->dwInstance; - open_desc.dnDevNode = desc32->dnDevNode; - open_desc.cIds = desc32->cIds; - open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID; - open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID; - - params.param_1 = (UINT_PTR)&open_desc; - break; - - case MODM_LONGDATA: - hdr32 = ULongToPtr(params32->param_1); - - memset(&hdr, 0, sizeof(hdr)); - hdr.lpData = ULongToPtr(hdr32->lpData); - hdr.dwBufferLength = hdr32->dwBufferLength; - hdr.dwFlags = hdr32->dwFlags; - - params.param_1 = (UINT_PTR)&hdr; - params.param_2 = sizeof(hdr); - break; - - case MODM_PREPARE: /* prepare and unprepare are easier to handle explicitly */ - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_out_prepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - - case MODM_UNPREPARE: - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_out_unprepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - } - - alsa_midi_out_message(¶ms); - - switch (params32->msg) - { - case MODM_LONGDATA: - hdr32 = ULongToPtr(params32->param_1); - - hdr32->dwFlags = hdr.dwFlags; - break; - } - - if (notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MOM_DONE) - notify32->param_1 = params32->param_1; /* restore the 32-bit hdr */ - } - return STATUS_SUCCESS; -} - -static UINT wow64_midi_in_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - - return MMSYSERR_NOERROR; -} - -static UINT wow64_midi_in_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - - return MMSYSERR_NOERROR; -} - -NTSTATUS alsa_wow64_midi_in_message(void *args) -{ - struct - { - UINT dev_id; - UINT msg; - UINT user; - UINT param_1; - UINT param_2; - PTR32 err; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_open_desc32 *desc32; - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIOPENDESC open_desc; - MIDIHDR *hdr = NULL; - struct midi_in_message_params params = - { - .dev_id = params32->dev_id, - .msg = params32->msg, - .user = params32->user, - .param_1 = params32->param_1, - .param_2 = params32->param_2, - .err = ULongToPtr(params32->err), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - switch (params32->msg) - { - case MIDM_OPEN: - desc32 = ULongToPtr(params32->param_1); - - open_desc.hMidi = ULongToPtr(desc32->hMidi); - open_desc.dwCallback = desc32->dwCallback; - open_desc.dwInstance = desc32->dwInstance; - open_desc.dnDevNode = desc32->dnDevNode; - open_desc.cIds = desc32->cIds; - open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID; - open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID; - - params.param_1 = (UINT_PTR)&open_desc; - break; - - case MIDM_ADDBUFFER: - hdr32 = ULongToPtr(params32->param_1); - - hdr = calloc(1, sizeof(*hdr)); - hdr->lpData = ULongToPtr(hdr32->lpData); - hdr->dwBufferLength = hdr32->dwBufferLength; - hdr->dwFlags = hdr32->dwFlags; - hdr->dwReserved[7] = params32->param_1; /* keep hdr32 for MIM_LONGDATA notification */ - - params.param_1 = (UINT_PTR)hdr; - params.param_2 = sizeof(*hdr); - break; - - case MIDM_PREPARE: /* prepare and unprepare are easier to handle explicitly */ - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_in_prepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - - case MIDM_UNPREPARE: - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_in_unprepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - } - - alsa_midi_in_message(¶ms); - - switch (params32->msg) - { - case MIDM_ADDBUFFER: - hdr32 = ULongToPtr(params32->param_1); - - if (!*params.err) - { - hdr32->dwFlags = hdr->dwFlags; - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->lpNext = 0; - } - else - free(hdr); - break; - } - - if (notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MIM_LONGDATA) - { - hdr = (MIDIHDR *)notify.param_1; - notify32->param_1 = hdr->dwReserved[7]; - hdr32 = ULongToPtr(notify32->param_1); - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->dwFlags = hdr->dwFlags; - free(hdr); - } - } - return STATUS_SUCCESS; -} - -NTSTATUS alsa_wow64_midi_notify_wait(void *args) -{ - struct - { - PTR32 quit; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIHDR *hdr; - struct midi_notify_wait_params params = - { - .quit = ULongToPtr(params32->quit), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - alsa_midi_notify_wait(¶ms); - - if (!*params.quit && notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MIM_LONGDATA) - { - hdr = (MIDIHDR *)notify.param_1; - notify32->param_1 = hdr->dwReserved[7]; - hdr32 = ULongToPtr(notify32->param_1); - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->dwFlags = hdr->dwFlags; - free(hdr); - } - } - return STATUS_SUCCESS; -} - -#endif /* _WIN64 */ diff --git a/pkgs/osu-wine/audio-revert/winealsa.drv/midi.c b/pkgs/osu-wine/audio-revert/winealsa.drv/midi.c deleted file mode 100644 index 1c44116..0000000 --- a/pkgs/osu-wine/audio-revert/winealsa.drv/midi.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * MIDI driver for ALSA (PE-side) - * - * Copyright 1994 Martin Ayotte - * Copyright 1998 Luiz Otavio L. Zorzella - * Copyright 1998, 1999 Eric POUECH - * Copyright 2003 Christian Costa - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winternl.h" -#include "mmddk.h" -#include "mmdeviceapi.h" - -#include "wine/debug.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(midi); - -static void notify_client(struct notify_context *notify) -{ - TRACE("dev_id = %d msg = %d param1 = %04IX param2 = %04IX\n", notify->dev_id, notify->msg, notify->param_1, notify->param_2); - - DriverCallback(notify->callback, notify->flags, notify->device, notify->msg, - notify->instance, notify->param_1, notify->param_2); -} - -/*======================================================================* - * MIDI entry points * - *======================================================================*/ - -/************************************************************************** - * midMessage (WINEALSA.@) - */ -DWORD WINAPI ALSA_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - struct midi_in_message_params params; - struct notify_context notify; - UINT err; - - TRACE("(%04X, %04X, %08IX, %08IX, %08IX);\n", - wDevID, wMsg, dwUser, dwParam1, dwParam2); - - params.dev_id = wDevID; - params.msg = wMsg; - params.user = dwUser; - params.param_1 = dwParam1; - params.param_2 = dwParam2; - params.err = &err; - params.notify = ¬ify; - - do - { - ALSA_CALL(midi_in_message, ¶ms); - if ((!err || err == ERROR_RETRY) && notify.send_notify) notify_client(¬ify); - } while (err == ERROR_RETRY); - - return err; -} - -/************************************************************************** - * modMessage (WINEALSA.@) - */ -DWORD WINAPI ALSA_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - struct midi_out_message_params params; - struct notify_context notify; - UINT err; - - TRACE("(%04X, %04X, %08IX, %08IX, %08IX);\n", - wDevID, wMsg, dwUser, dwParam1, dwParam2); - - params.dev_id = wDevID; - params.msg = wMsg; - params.user = dwUser; - params.param_1 = dwParam1; - params.param_2 = dwParam2; - params.err = &err; - params.notify = ¬ify; - - ALSA_CALL(midi_out_message, ¶ms); - - if (!err && notify.send_notify) notify_client(¬ify); - - return err; -} - -static DWORD WINAPI notify_thread(void *p) -{ - struct midi_notify_wait_params params; - struct notify_context notify; - BOOL quit; - - SetThreadDescription(GetCurrentThread(), L"winealsa_midi_notify"); - - params.notify = ¬ify; - params.quit = &quit; - - while (1) - { - ALSA_CALL(midi_notify_wait, ¶ms); - if (quit) break; - if (notify.send_notify) notify_client(¬ify); - } - return 0; -} - -/************************************************************************** - * DriverProc (WINEALSA.@) - */ -LRESULT CALLBACK ALSA_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, - LPARAM dwParam1, LPARAM dwParam2) -{ - switch(wMsg) { - case DRV_LOAD: - CloseHandle(CreateThread(NULL, 0, notify_thread, NULL, 0, NULL)); - return 1; - case DRV_FREE: - ALSA_CALL(midi_release, NULL); - return 1; - case DRV_OPEN: - case DRV_CLOSE: - case DRV_ENABLE: - case DRV_DISABLE: - case DRV_QUERYCONFIGURE: - case DRV_CONFIGURE: - return 1; - case DRV_INSTALL: - case DRV_REMOVE: - return DRV_SUCCESS; - default: - return 0; - } -} diff --git a/pkgs/osu-wine/audio-revert/winealsa.drv/mmdevdrv.c b/pkgs/osu-wine/audio-revert/winealsa.drv/mmdevdrv.c deleted file mode 100644 index 8367e7e..0000000 --- a/pkgs/osu-wine/audio-revert/winealsa.drv/mmdevdrv.c +++ /dev/null @@ -1,2484 +0,0 @@ -/* - * Copyright 2010 Maarten Lankhorst for CodeWeavers - * Copyright 2011 Andrew Eikum for CodeWeavers - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS - -#include - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winternl.h" -#include "propsys.h" -#include "propkey.h" -#include "initguid.h" -#include "ole2.h" -#include "mmdeviceapi.h" -#include "devpkey.h" -#include "mmsystem.h" -#include "dsound.h" - -#include "endpointvolume.h" -#include "audioclient.h" -#include "audiopolicy.h" - -#include "wine/debug.h" -#include "wine/list.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(alsa); - -#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) - -static const REFERENCE_TIME DefaultPeriod = 100000; -static const REFERENCE_TIME MinimumPeriod = 50000; - -int GetAudioEnv(char const* env, int def) { - char* val = getenv(env); - if (val) { - return atoi(val); - } - return def; -} - -struct ACImpl; -typedef struct ACImpl ACImpl; - -typedef struct _AudioSession { - GUID guid; - struct list clients; - - IMMDevice *device; - - float master_vol; - UINT32 channel_count; - float *channel_vols; - BOOL mute; - - struct list entry; -} AudioSession; - -typedef struct _AudioSessionWrapper { - IAudioSessionControl2 IAudioSessionControl2_iface; - IChannelAudioVolume IChannelAudioVolume_iface; - ISimpleAudioVolume ISimpleAudioVolume_iface; - - LONG ref; - - ACImpl *client; - AudioSession *session; -} AudioSessionWrapper; - -struct ACImpl { - IAudioClient3 IAudioClient3_iface; - IAudioRenderClient IAudioRenderClient_iface; - IAudioCaptureClient IAudioCaptureClient_iface; - IAudioClock IAudioClock_iface; - IAudioClock2 IAudioClock2_iface; - IAudioStreamVolume IAudioStreamVolume_iface; - - LONG ref; - - IMMDevice *parent; - IUnknown *pUnkFTMarshal; - - EDataFlow dataflow; - float *vols; - UINT32 channel_count; - stream_handle stream; - - HANDLE timer_thread; - - AudioSession *session; - AudioSessionWrapper *session_wrapper; - - struct list entry; - - /* Keep at end */ - char alsa_name[1]; -}; - -typedef struct _SessionMgr { - IAudioSessionManager2 IAudioSessionManager2_iface; - - LONG ref; - - IMMDevice *device; -} SessionMgr; - -static CRITICAL_SECTION g_sessions_lock; -static CRITICAL_SECTION_DEBUG g_sessions_lock_debug = -{ - 0, 0, &g_sessions_lock, - { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") } -}; -static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 }; -static struct list g_sessions = LIST_INIT(g_sessions); - -static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\', - 'W','i','n','e','\\','D','r','i','v','e','r','s','\\', - 'w','i','n','e','a','l','s','a','.','d','r','v','\\','d','e','v','i','c','e','s',0}; -static const WCHAR guidW[] = {'g','u','i','d',0}; - -static const IAudioClient3Vtbl AudioClient3_Vtbl; -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl; -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl; -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl; -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl; -static const IAudioClockVtbl AudioClock_Vtbl; -static const IAudioClock2Vtbl AudioClock2_Vtbl; -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl; -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl; -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl; - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client); - -static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface); -} - -static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface); -} - -static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface); -} - -static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface); -} - -static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface); -} - -static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface); -} - -static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface); -} - -static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface); -} - -static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); -} - -static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface) -{ - return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface); -} - -BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) -{ - switch (reason) - { - case DLL_PROCESS_ATTACH: - if(__wine_init_unix_call()) return FALSE; - break; - - case DLL_PROCESS_DETACH: - if (reserved) break; - DeleteCriticalSection(&g_sessions_lock); - break; - } - return TRUE; -} - -int WINAPI AUDDRV_GetPriority(void) -{ - return Priority_Neutral; -} - -static HRESULT alsa_stream_release(stream_handle stream, HANDLE timer_thread) -{ - struct release_stream_params params; - - params.stream = stream; - params.timer_thread = timer_thread; - - ALSA_CALL(release_stream, ¶ms); - - return params.result; -} - -static DWORD WINAPI alsa_timer_thread(void *user) -{ - struct timer_loop_params params; - struct ACImpl *This = user; - - SetThreadDescription(GetCurrentThread(), L"winealsa_timer"); - - params.stream = This->stream; - - ALSA_CALL(timer_loop, ¶ms); - - return 0; -} - -static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name, - GUID *guid) -{ - HKEY key; - BOOL opened = FALSE; - LONG lr; - - if(!drv_key){ - lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE, - NULL, &drv_key, NULL); - if(lr != ERROR_SUCCESS){ - ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr); - return; - } - opened = TRUE; - } - - lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE, - NULL, &key, NULL); - if(lr != ERROR_SUCCESS){ - ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr); - goto exit; - } - - lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid, - sizeof(GUID)); - if(lr != ERROR_SUCCESS) - ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr); - - RegCloseKey(key); -exit: - if(opened) - RegCloseKey(drv_key); -} - -static void get_device_guid(EDataFlow flow, const char *device, GUID *guid) -{ - HKEY key = NULL, dev_key; - DWORD type, size = sizeof(*guid); - WCHAR key_name[256]; - - if(flow == eCapture) - key_name[0] = '1'; - else - key_name[0] = '0'; - key_name[1] = ','; - MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2); - - if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){ - if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){ - if(RegQueryValueExW(dev_key, guidW, 0, &type, - (BYTE*)guid, &size) == ERROR_SUCCESS){ - if(type == REG_BINARY){ - RegCloseKey(dev_key); - RegCloseKey(key); - return; - } - ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n", - wine_dbgstr_w(key_name), type); - } - RegCloseKey(dev_key); - } - } - - CoCreateGuid(guid); - - set_device_guid(flow, key, key_name, guid); - - if(key) - RegCloseKey(key); -} - -static void set_stream_volumes(ACImpl *This) -{ - struct set_volumes_params params; - - params.stream = This->stream; - params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol); - params.volumes = This->vols; - params.session_volumes = This->session->channel_vols; - params.channel = 0; - - ALSA_CALL(set_volumes, ¶ms); -} - -HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out, - UINT *num, UINT *def_index) -{ - struct get_endpoint_ids_params params; - unsigned int i; - GUID *guids = NULL; - WCHAR **ids = NULL; - - TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index); - - params.flow = flow; - params.size = 1000; - params.endpoints = NULL; - do{ - HeapFree(GetProcessHeap(), 0, params.endpoints); - params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size); - ALSA_CALL(get_endpoint_ids, ¶ms); - }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)); - - if(FAILED(params.result)) goto end; - - ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids)); - guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids)); - if(!ids || !guids){ - params.result = E_OUTOFMEMORY; - goto end; - } - - for(i = 0; i < params.num; i++){ - WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name); - char *device = (char *)params.endpoints + params.endpoints[i].device; - unsigned int size = (wcslen(name) + 1) * sizeof(WCHAR); - - ids[i] = HeapAlloc(GetProcessHeap(), 0, size); - if(!ids[i]){ - params.result = E_OUTOFMEMORY; - goto end; - } - memcpy(ids[i], name, size); - get_device_guid(flow, device, guids + i); - } - *def_index = params.default_idx; - -end: - HeapFree(GetProcessHeap(), 0, params.endpoints); - if(FAILED(params.result)){ - HeapFree(GetProcessHeap(), 0, guids); - if(ids){ - for(i = 0; i < params.num; i++) - HeapFree(GetProcessHeap(), 0, ids[i]); - HeapFree(GetProcessHeap(), 0, ids); - } - }else{ - *ids_out = ids; - *guids_out = guids; - *num = params.num; - } - - return params.result; -} - -static BOOL get_alsa_name_by_guid(GUID *guid, char *name, DWORD name_size, EDataFlow *flow) -{ - HKEY devices_key; - UINT i = 0; - WCHAR key_name[256]; - DWORD key_name_size; - - if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){ - ERR("No devices found in registry?\n"); - return FALSE; - } - - while(1){ - HKEY key; - DWORD size, type; - GUID reg_guid; - - key_name_size = ARRAY_SIZE(key_name); - if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL, - NULL, NULL, NULL) != ERROR_SUCCESS) - break; - - if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){ - WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name)); - continue; - } - - size = sizeof(reg_guid); - if(RegQueryValueExW(key, guidW, 0, &type, - (BYTE*)®_guid, &size) == ERROR_SUCCESS){ - if(IsEqualGUID(®_guid, guid)){ - RegCloseKey(key); - RegCloseKey(devices_key); - - TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name)); - - if(key_name[0] == '0') - *flow = eRender; - else if(key_name[0] == '1') - *flow = eCapture; - else{ - ERR("Unknown device type: %c\n", key_name[0]); - return FALSE; - } - - WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL); - - return TRUE; - } - } - - RegCloseKey(key); - } - - RegCloseKey(devices_key); - - WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid)); - - return FALSE; -} - -HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out) -{ - ACImpl *This; - char alsa_name[256]; - EDataFlow dataflow; - HRESULT hr; - int len; - - TRACE("%s %p %p\n", debugstr_guid(guid), dev, out); - - if(!get_alsa_name_by_guid(guid, alsa_name, sizeof(alsa_name), &dataflow)) - return AUDCLNT_E_DEVICE_INVALIDATED; - - if(dataflow != eRender && dataflow != eCapture) - return E_UNEXPECTED; - - len = strlen(alsa_name); - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, alsa_name[len + 1])); - if(!This) - return E_OUTOFMEMORY; - - This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl; - This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl; - This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl; - This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl; - This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl; - This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl; - - hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal); - if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, This); - return hr; - } - - This->dataflow = dataflow; - memcpy(This->alsa_name, alsa_name, len + 1); - - This->parent = dev; - IMMDevice_AddRef(This->parent); - - *out = (IAudioClient *)&This->IAudioClient3_iface; - IAudioClient3_AddRef(&This->IAudioClient3_iface); - - return S_OK; -} - -static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioClient) || - IsEqualIID(riid, &IID_IAudioClient2) || - IsEqualIID(riid, &IID_IAudioClient3)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - ULONG ref; - - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref){ - IAudioClient3_Stop(iface); - IMMDevice_Release(This->parent); - IUnknown_Release(This->pUnkFTMarshal); - if(This->session){ - EnterCriticalSection(&g_sessions_lock); - list_remove(&This->entry); - LeaveCriticalSection(&g_sessions_lock); - } - HeapFree(GetProcessHeap(), 0, This->vols); - if (This->stream) - alsa_stream_release(This->stream, This->timer_thread); - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static void dump_fmt(const WAVEFORMATEX *fmt) -{ - TRACE("wFormatTag: 0x%x (", fmt->wFormatTag); - switch(fmt->wFormatTag){ - case WAVE_FORMAT_PCM: - TRACE("WAVE_FORMAT_PCM"); - break; - case WAVE_FORMAT_IEEE_FLOAT: - TRACE("WAVE_FORMAT_IEEE_FLOAT"); - break; - case WAVE_FORMAT_EXTENSIBLE: - TRACE("WAVE_FORMAT_EXTENSIBLE"); - break; - default: - TRACE("Unknown"); - break; - } - TRACE(")\n"); - - TRACE("nChannels: %u\n", fmt->nChannels); - TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec); - TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec); - TRACE("nBlockAlign: %u\n", fmt->nBlockAlign); - TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample); - TRACE("cbSize: %u\n", fmt->cbSize); - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt; - TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask); - TRACE("Samples: %04x\n", fmtex->Samples.wReserved); - TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat)); - } -} - -static void session_init_vols(AudioSession *session, UINT channels) -{ - if(session->channel_count < channels){ - UINT i; - - if(session->channel_vols) - session->channel_vols = HeapReAlloc(GetProcessHeap(), 0, - session->channel_vols, sizeof(float) * channels); - else - session->channel_vols = HeapAlloc(GetProcessHeap(), 0, - sizeof(float) * channels); - if(!session->channel_vols) - return; - - for(i = session->channel_count; i < channels; ++i) - session->channel_vols[i] = 1.f; - - session->channel_count = channels; - } -} - -static AudioSession *create_session(const GUID *guid, IMMDevice *device, - UINT num_channels) -{ - AudioSession *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession)); - if(!ret) - return NULL; - - memcpy(&ret->guid, guid, sizeof(GUID)); - - ret->device = device; - - list_init(&ret->clients); - - list_add_head(&g_sessions, &ret->entry); - - session_init_vols(ret, num_channels); - - ret->master_vol = 1.f; - - return ret; -} - -/* if channels == 0, then this will return or create a session with - * matching dataflow and GUID. otherwise, channels must also match */ -static HRESULT get_audio_session(const GUID *sessionguid, - IMMDevice *device, UINT channels, AudioSession **out) -{ - AudioSession *session; - - if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){ - *out = create_session(&GUID_NULL, device, channels); - if(!*out) - return E_OUTOFMEMORY; - - return S_OK; - } - - *out = NULL; - LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){ - if(session->device == device && - IsEqualGUID(sessionguid, &session->guid)){ - session_init_vols(session, channels); - *out = session; - break; - } - } - - if(!*out){ - *out = create_session(sessionguid, device, channels); - if(!*out) - return E_OUTOFMEMORY; - } - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, - AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration, - REFERENCE_TIME period, const WAVEFORMATEX *fmt, - const GUID *sessionguid) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct create_stream_params params; - stream_handle stream; - unsigned int i; - - TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags, - wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid)); - - if(!fmt) - return E_POINTER; - - if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) - return E_INVALIDARG; - - if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS | - AUDCLNT_STREAMFLAGS_LOOPBACK | - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | - AUDCLNT_STREAMFLAGS_NOPERSIST | - AUDCLNT_STREAMFLAGS_RATEADJUST | - AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED | - AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | - AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){ - FIXME("Unknown flags: %08lx\n", flags); - return E_INVALIDARG; - } - - if(mode == AUDCLNT_SHAREMODE_SHARED){ - period = GetAudioEnv("STAGING_AUDIO_DEFAULT_PERIOD", DefaultPeriod); - duration = GetAudioEnv("STAGING_AUDIO_DURATION", 100000); - }else{ - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 || - ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED) - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - - if(!period){ - period = GetAudioEnv("STAGING_AUDIO_DEFAULT_PERIOD", DefaultPeriod); /* not minimum */ - duration = GetAudioEnv("STAGING_AUDIO_DURATION", 100000); - } - if(period < GetAudioEnv("STAGING_AUDIO_MINIMUM_PERIOD", MinimumPeriod) || period > 5000000) - return AUDCLNT_E_INVALID_DEVICE_PERIOD; - if(duration > 20000000) /* the smaller the period, the lower this limit */ - return AUDCLNT_E_BUFFER_SIZE_ERROR; - if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){ - if(duration != period) - return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; - FIXME("EXCLUSIVE mode with EVENTCALLBACK\n"); - return AUDCLNT_E_DEVICE_IN_USE; - }else{ - if( duration < 8 * period) - duration = 8 * period; /* may grow above 2s */ - } - } - - EnterCriticalSection(&g_sessions_lock); - - if(This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_ALREADY_INITIALIZED; - } - - dump_fmt(fmt); - - params.name = NULL; - params.device = This->alsa_name; - params.flow = This->dataflow; - params.share = mode; - params.flags = flags; - params.duration = duration; - params.period = period; - params.fmt = fmt; - params.channel_count = NULL; - params.stream = &stream; - - ALSA_CALL(create_stream, ¶ms); - if(FAILED(params.result)){ - LeaveCriticalSection(&g_sessions_lock); - return params.result; - } - - This->channel_count = fmt->nChannels; - This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float)); - if(!This->vols){ - params.result = E_OUTOFMEMORY; - goto exit; - } - for(i = 0; i < This->channel_count; ++i) - This->vols[i] = 1.f; - - params.result = get_audio_session(sessionguid, This->parent, This->channel_count, - &This->session); - if(FAILED(params.result)) - goto exit; - - list_add_tail(&This->session->clients, &This->entry); - -exit: - if(FAILED(params.result)){ - alsa_stream_release(stream, NULL); - HeapFree(GetProcessHeap(), 0, This->vols); - This->vols = NULL; - }else{ - This->stream = stream; - set_stream_volumes(This); - } - - LeaveCriticalSection(&g_sessions_lock); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface, - UINT32 *out) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_buffer_size_params params; - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.frames = out; - - ALSA_CALL(get_buffer_size, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface, - REFERENCE_TIME *latency) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_latency_params params; - - TRACE("(%p)->(%p)\n", This, latency); - - if(!latency) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.latency = latency; - - ALSA_CALL(get_latency, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface, - UINT32 *out) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_current_padding_params params; - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.padding = out; - - ALSA_CALL(get_current_padding, ¶ms); - - TRACE("pad: %u\n", *out); - - return params.result; -} - -static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface, - AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt, - WAVEFORMATEX **out) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct is_format_supported_params params; - - TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out); - if(fmt) dump_fmt(fmt); - - params.device = This->alsa_name; - params.flow = This->dataflow; - params.share = mode; - params.fmt_in = fmt; - params.fmt_out = NULL; - - if(out){ - *out = NULL; - if(mode == AUDCLNT_SHAREMODE_SHARED) - params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out)); - } - ALSA_CALL(is_format_supported, ¶ms); - - if(params.result == S_FALSE) - *out = ¶ms.fmt_out->Format; - else - CoTaskMemFree(params.fmt_out); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, - WAVEFORMATEX **pwfx) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_mix_format_params params; - - TRACE("(%p)->(%p)\n", This, pwfx); - - if(!pwfx) - return E_POINTER; - *pwfx = NULL; - - params.device = This->alsa_name; - params.flow = This->dataflow; - params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE)); - if(!params.fmt) - return E_OUTOFMEMORY; - - ALSA_CALL(get_mix_format, ¶ms); - - if(SUCCEEDED(params.result)){ - *pwfx = ¶ms.fmt->Format; - dump_fmt(*pwfx); - } else - CoTaskMemFree(params.fmt); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, - REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod); - - if(!defperiod && !minperiod) - return E_POINTER; - - if(defperiod) - *defperiod = GetAudioEnv("STAGING_AUDIO_DEFAULT_PERIOD", DefaultPeriod); - if(minperiod) - *minperiod = GetAudioEnv("STAGING_AUDIO_MINIMUM_PERIOD", MinimumPeriod); - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct start_params params; - - TRACE("(%p)\n", This); - - EnterCriticalSection(&g_sessions_lock); - - if(!This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_NOT_INITIALIZED; - } - - params.stream = This->stream; - - ALSA_CALL(start, ¶ms); - - if(SUCCEEDED(params.result) && !This->timer_thread){ - This->timer_thread = CreateThread(NULL, 0, alsa_timer_thread, This, 0, NULL); - SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL); - } - - LeaveCriticalSection(&g_sessions_lock); - - return params.result; -} - -static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct stop_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - - ALSA_CALL(stop, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct reset_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - - ALSA_CALL(reset, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface, - HANDLE event) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct set_event_handle_params params; - - TRACE("(%p)->(%p)\n", This, event); - - if(!event) - return E_INVALIDARG; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.event = event; - - ALSA_CALL(set_event_handle, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid, - void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - EnterCriticalSection(&g_sessions_lock); - - if(!This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_NOT_INITIALIZED; - } - - if(IsEqualIID(riid, &IID_IAudioRenderClient)){ - if(This->dataflow != eRender){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - } - IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface); - *ppv = &This->IAudioRenderClient_iface; - }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){ - if(This->dataflow != eCapture){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - } - IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface); - *ppv = &This->IAudioCaptureClient_iface; - }else if(IsEqualIID(riid, &IID_IAudioClock)){ - IAudioClock_AddRef(&This->IAudioClock_iface); - *ppv = &This->IAudioClock_iface; - }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){ - IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface); - *ppv = &This->IAudioStreamVolume_iface; - }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface); - - *ppv = &This->session_wrapper->IAudioSessionControl2_iface; - }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface); - - *ppv = &This->session_wrapper->IChannelAudioVolume_iface; - }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface); - - *ppv = &This->session_wrapper->ISimpleAudioVolume_iface; - } - - if(*ppv){ - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - - LeaveCriticalSection(&g_sessions_lock); - - FIXME("stub %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface, - AUDIO_STREAM_CATEGORY category, BOOL *offload_capable) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable); - - if(!offload_capable) - return E_INVALIDARG; - - *offload_capable = FALSE; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface, - const AudioClientProperties *prop) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop; - - TRACE("(%p)->(%p)\n", This, prop); - - if(!legacy_prop) - return E_POINTER; - - if(legacy_prop->cbSize == sizeof(AudioClientProperties)){ - TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n", - legacy_prop->bIsOffload, - legacy_prop->eCategory, - prop->Options); - }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){ - TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n", - legacy_prop->bIsOffload, - legacy_prop->eCategory); - }else{ - WARN("Unsupported Size = %d\n", legacy_prop->cbSize); - return E_INVALIDARG; - } - - - if(legacy_prop->bIsOffload) - return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface, - const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration, - REFERENCE_TIME *max_duration) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface, - const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames, - UINT32 *min_period_frames, UINT32 *max_period_frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames, - min_period_frames, max_period_frames); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface, - WAVEFORMATEX **cur_format, UINT32 *cur_period_frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface, - DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format, - const GUID *session_guid) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid)); - - return E_NOTIMPL; -} - -static const IAudioClient3Vtbl AudioClient3_Vtbl = -{ - AudioClient_QueryInterface, - AudioClient_AddRef, - AudioClient_Release, - AudioClient_Initialize, - AudioClient_GetBufferSize, - AudioClient_GetStreamLatency, - AudioClient_GetCurrentPadding, - AudioClient_IsFormatSupported, - AudioClient_GetMixFormat, - AudioClient_GetDevicePeriod, - AudioClient_Start, - AudioClient_Stop, - AudioClient_Reset, - AudioClient_SetEventHandle, - AudioClient_GetService, - AudioClient_IsOffloadCapable, - AudioClient_SetClientProperties, - AudioClient_GetBufferSizeLimits, - AudioClient_GetSharedModeEnginePeriod, - AudioClient_GetCurrentSharedModeEnginePeriod, - AudioClient_InitializeSharedAudioStream, -}; - -static HRESULT WINAPI AudioRenderClient_QueryInterface( - IAudioRenderClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioRenderClient)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface, - UINT32 frames, BYTE **data) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - struct get_render_buffer_params params; - - TRACE("(%p)->(%u, %p)\n", This, frames, data); - - if(!data) - return E_POINTER; - *data = NULL; - - params.stream = This->stream; - params.frames = frames; - params.data = data; - - ALSA_CALL(get_render_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioRenderClient_ReleaseBuffer( - IAudioRenderClient *iface, UINT32 written_frames, DWORD flags) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - struct release_render_buffer_params params; - - TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags); - - params.stream = This->stream; - params.written_frames = written_frames; - params.flags = flags; - - ALSA_CALL(release_render_buffer, ¶ms); - - return params.result; -} - -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = { - AudioRenderClient_QueryInterface, - AudioRenderClient_AddRef, - AudioRenderClient_Release, - AudioRenderClient_GetBuffer, - AudioRenderClient_ReleaseBuffer -}; - -static HRESULT WINAPI AudioCaptureClient_QueryInterface( - IAudioCaptureClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioCaptureClient)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface, - BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos, - UINT64 *qpcpos) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct get_capture_buffer_params params; - - TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags, - devpos, qpcpos); - - if(!data) - return E_POINTER; - - *data = NULL; - - if(!frames || !flags) - return E_POINTER; - - params.stream = This->stream; - params.data = data; - params.frames = frames; - params.flags = (UINT*)flags; - params.devpos = devpos; - params.qpcpos = qpcpos; - - ALSA_CALL(get_capture_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer( - IAudioCaptureClient *iface, UINT32 done) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct release_capture_buffer_params params; - - TRACE("(%p)->(%u)\n", This, done); - - params.stream = This->stream; - params.done = done; - - ALSA_CALL(release_capture_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize( - IAudioCaptureClient *iface, UINT32 *frames) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct get_next_packet_size_params params; - - TRACE("(%p)->(%p)\n", This, frames); - - if(!frames) - return E_POINTER; - - params.stream = This->stream; - params.frames = frames; - - ALSA_CALL(get_next_packet_size, ¶ms); - - return params.result; -} - -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl = -{ - AudioCaptureClient_QueryInterface, - AudioCaptureClient_AddRef, - AudioCaptureClient_Release, - AudioCaptureClient_GetBuffer, - AudioCaptureClient_ReleaseBuffer, - AudioCaptureClient_GetNextPacketSize -}; - -static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IAudioClock2)) - *ppv = &This->IAudioClock2_iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioClock_Release(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq) -{ - ACImpl *This = impl_from_IAudioClock(iface); - struct get_frequency_params params; - - TRACE("(%p)->(%p)\n", This, freq); - - params.stream = This->stream; - params.freq = freq; - - ALSA_CALL(get_frequency, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos, - UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock(iface); - struct get_position_params params; - - TRACE("(%p)->(%p, %p)\n", This, pos, qpctime); - - if(!pos) - return E_POINTER; - - params.stream = This->stream; - params.device = FALSE; - params.pos = pos; - params.qpctime = qpctime; - - ALSA_CALL(get_position, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface, - DWORD *chars) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%p)\n", This, chars); - - if(!chars) - return E_POINTER; - - *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ; - - return S_OK; -} - -static const IAudioClockVtbl AudioClock_Vtbl = -{ - AudioClock_QueryInterface, - AudioClock_AddRef, - AudioClock_Release, - AudioClock_GetFrequency, - AudioClock_GetPosition, - AudioClock_GetCharacteristics -}; - -static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv); -} - -static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface, - UINT64 *pos, UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - - FIXME("(%p)->(%p, %p)\n", This, pos, qpctime); - - return E_NOTIMPL; -} - -static const IAudioClock2Vtbl AudioClock2_Vtbl = -{ - AudioClock2_QueryInterface, - AudioClock2_AddRef, - AudioClock2_Release, - AudioClock2_GetDevicePosition -}; - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client) -{ - AudioSessionWrapper *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(AudioSessionWrapper)); - if(!ret) - return NULL; - - ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl; - ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl; - ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl; - - ret->ref = 1; - - ret->client = client; - if(client){ - ret->session = client->session; - AudioClient_AddRef(&client->IAudioClient3_iface); - } - - return ret; -} - -static HRESULT WINAPI AudioSessionControl_QueryInterface( - IAudioSessionControl2 *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionControl) || - IsEqualIID(riid, &IID_IAudioSessionControl2)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref){ - if(This->client){ - EnterCriticalSection(&g_sessions_lock); - This->client->session_wrapper = NULL; - LeaveCriticalSection(&g_sessions_lock); - AudioClient_Release(&This->client->IAudioClient3_iface); - } - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface, - AudioSessionState *state) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - struct is_started_params params; - ACImpl *client; - - TRACE("(%p)->(%p)\n", This, state); - - if(!state) - return NULL_PTR_ERR; - - EnterCriticalSection(&g_sessions_lock); - - if(list_empty(&This->session->clients)){ - *state = AudioSessionStateExpired; - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - - LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){ - params.stream = client->stream; - ALSA_CALL(is_started, ¶ms); - if(params.result == S_OK){ - *state = AudioSessionStateActive; - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - } - - LeaveCriticalSection(&g_sessions_lock); - - *state = AudioSessionStateInactive; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetDisplayName( - IAudioSessionControl2 *iface, WCHAR **name) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, name); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetDisplayName( - IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetIconPath( - IAudioSessionControl2 *iface, WCHAR **path) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, path); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetIconPath( - IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetGroupingParam( - IAudioSessionControl2 *iface, GUID *group) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, group); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetGroupingParam( - IAudioSessionControl2 *iface, const GUID *group, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group), - debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetProcessId( - IAudioSessionControl2 *iface, DWORD *pid) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%p)\n", This, pid); - - if(!pid) - return E_POINTER; - - *pid = GetCurrentProcessId(); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession( - IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)\n", This); - - return S_FALSE; -} - -static HRESULT WINAPI AudioSessionControl_SetDuckingPreference( - IAudioSessionControl2 *iface, BOOL optout) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%d)\n", This, optout); - - return S_OK; -} - -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl = -{ - AudioSessionControl_QueryInterface, - AudioSessionControl_AddRef, - AudioSessionControl_Release, - AudioSessionControl_GetState, - AudioSessionControl_GetDisplayName, - AudioSessionControl_SetDisplayName, - AudioSessionControl_GetIconPath, - AudioSessionControl_SetIconPath, - AudioSessionControl_GetGroupingParam, - AudioSessionControl_SetGroupingParam, - AudioSessionControl_RegisterAudioSessionNotification, - AudioSessionControl_UnregisterAudioSessionNotification, - AudioSessionControl_GetSessionIdentifier, - AudioSessionControl_GetSessionInstanceIdentifier, - AudioSessionControl_GetProcessId, - AudioSessionControl_IsSystemSoundsSession, - AudioSessionControl_SetDuckingPreference -}; - -static HRESULT WINAPI SimpleAudioVolume_QueryInterface( - ISimpleAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_ISimpleAudioVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume( - ISimpleAudioVolume *iface, float level, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context)); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->master_vol = level; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume( - ISimpleAudioVolume *iface, float *level) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, level); - - if(!level) - return NULL_PTR_ERR; - - *level = session->master_vol; - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface, - BOOL mute, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context)); - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->mute = mute; - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface, - BOOL *mute) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, mute); - - if(!mute) - return NULL_PTR_ERR; - - *mute = session->mute; - - return S_OK; -} - -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl = -{ - SimpleAudioVolume_QueryInterface, - SimpleAudioVolume_AddRef, - SimpleAudioVolume_Release, - SimpleAudioVolume_SetMasterVolume, - SimpleAudioVolume_GetMasterVolume, - SimpleAudioVolume_SetMute, - SimpleAudioVolume_GetMute -}; - -static HRESULT WINAPI AudioStreamVolume_QueryInterface( - IAudioStreamVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioStreamVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelCount( - IAudioStreamVolume *iface, UINT32 *out) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - *out = This->channel_count; - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_SetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%d, %f)\n", This, index, level); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(index >= This->channel_count) - return E_INVALIDARG; - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - This->vols[index] = level; - set_stream_volumes(This); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float *level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%d, %p)\n", This, index, level); - - if(!level) - return E_POINTER; - - if(index >= This->channel_count) - return E_INVALIDARG; - - *level = This->vols[index]; - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_SetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, const float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - unsigned int i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if(!levels) - return E_POINTER; - - if(count != This->channel_count) - return E_INVALIDARG; - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - This->vols[i] = levels[i]; - set_stream_volumes(This); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_GetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - unsigned int i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if(!levels) - return E_POINTER; - - if(count != This->channel_count) - return E_INVALIDARG; - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - levels[i] = This->vols[i]; - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl = -{ - AudioStreamVolume_QueryInterface, - AudioStreamVolume_AddRef, - AudioStreamVolume_Release, - AudioStreamVolume_GetChannelCount, - AudioStreamVolume_SetChannelVolume, - AudioStreamVolume_GetChannelVolume, - AudioStreamVolume_SetAllVolumes, - AudioStreamVolume_GetAllVolumes -}; - -static HRESULT WINAPI ChannelAudioVolume_QueryInterface( - IChannelAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IChannelAudioVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelCount( - IChannelAudioVolume *iface, UINT32 *out) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, out); - - if(!out) - return NULL_PTR_ERR; - - *out = session->channel_count; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float level, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%d, %f, %s)\n", session, index, level, - wine_dbgstr_guid(context)); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(index >= session->channel_count) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->channel_vols[index] = level; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float *level) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%d, %p)\n", session, index, level); - - if(!level) - return NULL_PTR_ERR; - - if(index >= session->channel_count) - return E_INVALIDARG; - - *level = session->channel_vols[index]; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, const float *levels, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - unsigned int i; - ACImpl *client; - - TRACE("(%p)->(%d, %p, %s)\n", session, count, levels, - wine_dbgstr_guid(context)); - - if(!levels) - return NULL_PTR_ERR; - - if(count != session->channel_count) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - session->channel_vols[i] = levels[i]; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, float *levels) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - unsigned int i; - - TRACE("(%p)->(%d, %p)\n", session, count, levels); - - if(!levels) - return NULL_PTR_ERR; - - if(count != session->channel_count) - return E_INVALIDARG; - - for(i = 0; i < count; ++i) - levels[i] = session->channel_vols[i]; - - return S_OK; -} - -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl = -{ - ChannelAudioVolume_QueryInterface, - ChannelAudioVolume_AddRef, - ChannelAudioVolume_Release, - ChannelAudioVolume_GetChannelCount, - ChannelAudioVolume_SetChannelVolume, - ChannelAudioVolume_GetChannelVolume, - ChannelAudioVolume_SetAllVolumes, - ChannelAudioVolume_GetAllVolumes -}; - -static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface, - REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionManager) || - IsEqualIID(riid, &IID_IAudioSessionManager2)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref) - HeapFree(GetProcessHeap(), 0, This); - return ref; -} - -static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - IAudioSessionControl **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if(FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - ISimpleAudioVolume **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if(FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = &wrapper->ISimpleAudioVolume_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator( - IAudioSessionManager2 *iface, IAudioSessionEnumerator **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, out); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification( - IAudioSessionManager2 *iface, const WCHAR *session_id, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification( - IAudioSessionManager2 *iface, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl = -{ - AudioSessionManager_QueryInterface, - AudioSessionManager_AddRef, - AudioSessionManager_Release, - AudioSessionManager_GetAudioSessionControl, - AudioSessionManager_GetSimpleAudioVolume, - AudioSessionManager_GetSessionEnumerator, - AudioSessionManager_RegisterSessionNotification, - AudioSessionManager_UnregisterSessionNotification, - AudioSessionManager_RegisterDuckNotification, - AudioSessionManager_UnregisterDuckNotification -}; - -HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device, - IAudioSessionManager2 **out) -{ - SessionMgr *This; - - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr)); - if(!This) - return E_OUTOFMEMORY; - - This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl; - This->device = device; - This->ref = 1; - - *out = &This->IAudioSessionManager2_iface; - - return S_OK; -} - -HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out) -{ - struct get_prop_value_params params; - char name[256]; - EDataFlow flow; - unsigned int size = 0; - - TRACE("%s, (%s,%lu), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out); - - if(!get_alsa_name_by_guid(guid, name, sizeof(name), &flow)) - { - WARN("Unknown interface %s\n", debugstr_guid(guid)); - return E_NOINTERFACE; - } - - params.device = name; - params.flow = flow; - params.guid = guid; - params.prop = prop; - params.value = out; - params.buffer = NULL; - params.buffer_size = &size; - - while(1) { - ALSA_CALL(get_prop_value, ¶ms); - - if(params.result != E_NOT_SUFFICIENT_BUFFER) - break; - - CoTaskMemFree(params.buffer); - params.buffer = CoTaskMemAlloc(*params.buffer_size); - if(!params.buffer) - return E_OUTOFMEMORY; - } - if(FAILED(params.result)) - CoTaskMemFree(params.buffer); - - return params.result; -} diff --git a/pkgs/osu-wine/audio-revert/winealsa.drv/mmdevdrv.c.orig b/pkgs/osu-wine/audio-revert/winealsa.drv/mmdevdrv.c.orig deleted file mode 100644 index ea48143..0000000 --- a/pkgs/osu-wine/audio-revert/winealsa.drv/mmdevdrv.c.orig +++ /dev/null @@ -1,2475 +0,0 @@ -/* - * Copyright 2010 Maarten Lankhorst for CodeWeavers - * Copyright 2011 Andrew Eikum for CodeWeavers - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS - -#include - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winternl.h" -#include "propsys.h" -#include "propkey.h" -#include "initguid.h" -#include "ole2.h" -#include "mmdeviceapi.h" -#include "devpkey.h" -#include "mmsystem.h" -#include "dsound.h" - -#include "endpointvolume.h" -#include "audioclient.h" -#include "audiopolicy.h" - -#include "wine/debug.h" -#include "wine/list.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(alsa); - -#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) - -static const REFERENCE_TIME DefaultPeriod = 100000; -static const REFERENCE_TIME MinimumPeriod = 50000; - -struct ACImpl; -typedef struct ACImpl ACImpl; - -typedef struct _AudioSession { - GUID guid; - struct list clients; - - IMMDevice *device; - - float master_vol; - UINT32 channel_count; - float *channel_vols; - BOOL mute; - - struct list entry; -} AudioSession; - -typedef struct _AudioSessionWrapper { - IAudioSessionControl2 IAudioSessionControl2_iface; - IChannelAudioVolume IChannelAudioVolume_iface; - ISimpleAudioVolume ISimpleAudioVolume_iface; - - LONG ref; - - ACImpl *client; - AudioSession *session; -} AudioSessionWrapper; - -struct ACImpl { - IAudioClient3 IAudioClient3_iface; - IAudioRenderClient IAudioRenderClient_iface; - IAudioCaptureClient IAudioCaptureClient_iface; - IAudioClock IAudioClock_iface; - IAudioClock2 IAudioClock2_iface; - IAudioStreamVolume IAudioStreamVolume_iface; - - LONG ref; - - IMMDevice *parent; - IUnknown *pUnkFTMarshal; - - EDataFlow dataflow; - float *vols; - UINT32 channel_count; - stream_handle stream; - - HANDLE timer_thread; - - AudioSession *session; - AudioSessionWrapper *session_wrapper; - - struct list entry; - - /* Keep at end */ - char alsa_name[1]; -}; - -typedef struct _SessionMgr { - IAudioSessionManager2 IAudioSessionManager2_iface; - - LONG ref; - - IMMDevice *device; -} SessionMgr; - -static CRITICAL_SECTION g_sessions_lock; -static CRITICAL_SECTION_DEBUG g_sessions_lock_debug = -{ - 0, 0, &g_sessions_lock, - { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") } -}; -static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 }; -static struct list g_sessions = LIST_INIT(g_sessions); - -static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\', - 'W','i','n','e','\\','D','r','i','v','e','r','s','\\', - 'w','i','n','e','a','l','s','a','.','d','r','v','\\','d','e','v','i','c','e','s',0}; -static const WCHAR guidW[] = {'g','u','i','d',0}; - -static const IAudioClient3Vtbl AudioClient3_Vtbl; -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl; -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl; -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl; -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl; -static const IAudioClockVtbl AudioClock_Vtbl; -static const IAudioClock2Vtbl AudioClock2_Vtbl; -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl; -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl; -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl; - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client); - -static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface); -} - -static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface); -} - -static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface); -} - -static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface); -} - -static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface); -} - -static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface); -} - -static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface); -} - -static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface); -} - -static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); -} - -static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface) -{ - return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface); -} - -BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) -{ - switch (reason) - { - case DLL_PROCESS_ATTACH: - if(__wine_init_unix_call()) return FALSE; - break; - - case DLL_PROCESS_DETACH: - if (reserved) break; - DeleteCriticalSection(&g_sessions_lock); - break; - } - return TRUE; -} - -int WINAPI AUDDRV_GetPriority(void) -{ - return Priority_Neutral; -} - -static HRESULT alsa_stream_release(stream_handle stream, HANDLE timer_thread) -{ - struct release_stream_params params; - - params.stream = stream; - params.timer_thread = timer_thread; - - ALSA_CALL(release_stream, ¶ms); - - return params.result; -} - -static DWORD WINAPI alsa_timer_thread(void *user) -{ - struct timer_loop_params params; - struct ACImpl *This = user; - - SetThreadDescription(GetCurrentThread(), L"winealsa_timer"); - - params.stream = This->stream; - - ALSA_CALL(timer_loop, ¶ms); - - return 0; -} - -static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name, - GUID *guid) -{ - HKEY key; - BOOL opened = FALSE; - LONG lr; - - if(!drv_key){ - lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE, - NULL, &drv_key, NULL); - if(lr != ERROR_SUCCESS){ - ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr); - return; - } - opened = TRUE; - } - - lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE, - NULL, &key, NULL); - if(lr != ERROR_SUCCESS){ - ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr); - goto exit; - } - - lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid, - sizeof(GUID)); - if(lr != ERROR_SUCCESS) - ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr); - - RegCloseKey(key); -exit: - if(opened) - RegCloseKey(drv_key); -} - -static void get_device_guid(EDataFlow flow, const char *device, GUID *guid) -{ - HKEY key = NULL, dev_key; - DWORD type, size = sizeof(*guid); - WCHAR key_name[256]; - - if(flow == eCapture) - key_name[0] = '1'; - else - key_name[0] = '0'; - key_name[1] = ','; - MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2); - - if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){ - if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){ - if(RegQueryValueExW(dev_key, guidW, 0, &type, - (BYTE*)guid, &size) == ERROR_SUCCESS){ - if(type == REG_BINARY){ - RegCloseKey(dev_key); - RegCloseKey(key); - return; - } - ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n", - wine_dbgstr_w(key_name), type); - } - RegCloseKey(dev_key); - } - } - - CoCreateGuid(guid); - - set_device_guid(flow, key, key_name, guid); - - if(key) - RegCloseKey(key); -} - -static void set_stream_volumes(ACImpl *This) -{ - struct set_volumes_params params; - - params.stream = This->stream; - params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol); - params.volumes = This->vols; - params.session_volumes = This->session->channel_vols; - params.channel = 0; - - ALSA_CALL(set_volumes, ¶ms); -} - -HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out, - UINT *num, UINT *def_index) -{ - struct get_endpoint_ids_params params; - unsigned int i; - GUID *guids = NULL; - WCHAR **ids = NULL; - - TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index); - - params.flow = flow; - params.size = 1000; - params.endpoints = NULL; - do{ - HeapFree(GetProcessHeap(), 0, params.endpoints); - params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size); - ALSA_CALL(get_endpoint_ids, ¶ms); - }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)); - - if(FAILED(params.result)) goto end; - - ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids)); - guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids)); - if(!ids || !guids){ - params.result = E_OUTOFMEMORY; - goto end; - } - - for(i = 0; i < params.num; i++){ - WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name); - char *device = (char *)params.endpoints + params.endpoints[i].device; - unsigned int size = (wcslen(name) + 1) * sizeof(WCHAR); - - ids[i] = HeapAlloc(GetProcessHeap(), 0, size); - if(!ids[i]){ - params.result = E_OUTOFMEMORY; - goto end; - } - memcpy(ids[i], name, size); - get_device_guid(flow, device, guids + i); - } - *def_index = params.default_idx; - -end: - HeapFree(GetProcessHeap(), 0, params.endpoints); - if(FAILED(params.result)){ - HeapFree(GetProcessHeap(), 0, guids); - if(ids){ - for(i = 0; i < params.num; i++) - HeapFree(GetProcessHeap(), 0, ids[i]); - HeapFree(GetProcessHeap(), 0, ids); - } - }else{ - *ids_out = ids; - *guids_out = guids; - *num = params.num; - } - - return params.result; -} - -static BOOL get_alsa_name_by_guid(GUID *guid, char *name, DWORD name_size, EDataFlow *flow) -{ - HKEY devices_key; - UINT i = 0; - WCHAR key_name[256]; - DWORD key_name_size; - - if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){ - ERR("No devices found in registry?\n"); - return FALSE; - } - - while(1){ - HKEY key; - DWORD size, type; - GUID reg_guid; - - key_name_size = ARRAY_SIZE(key_name); - if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL, - NULL, NULL, NULL) != ERROR_SUCCESS) - break; - - if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){ - WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name)); - continue; - } - - size = sizeof(reg_guid); - if(RegQueryValueExW(key, guidW, 0, &type, - (BYTE*)®_guid, &size) == ERROR_SUCCESS){ - if(IsEqualGUID(®_guid, guid)){ - RegCloseKey(key); - RegCloseKey(devices_key); - - TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name)); - - if(key_name[0] == '0') - *flow = eRender; - else if(key_name[0] == '1') - *flow = eCapture; - else{ - ERR("Unknown device type: %c\n", key_name[0]); - return FALSE; - } - - WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL); - - return TRUE; - } - } - - RegCloseKey(key); - } - - RegCloseKey(devices_key); - - WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid)); - - return FALSE; -} - -HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out) -{ - ACImpl *This; - char alsa_name[256]; - EDataFlow dataflow; - HRESULT hr; - int len; - - TRACE("%s %p %p\n", debugstr_guid(guid), dev, out); - - if(!get_alsa_name_by_guid(guid, alsa_name, sizeof(alsa_name), &dataflow)) - return AUDCLNT_E_DEVICE_INVALIDATED; - - if(dataflow != eRender && dataflow != eCapture) - return E_UNEXPECTED; - - len = strlen(alsa_name); - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, alsa_name[len + 1])); - if(!This) - return E_OUTOFMEMORY; - - This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl; - This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl; - This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl; - This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl; - This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl; - This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl; - - hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal); - if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, This); - return hr; - } - - This->dataflow = dataflow; - memcpy(This->alsa_name, alsa_name, len + 1); - - This->parent = dev; - IMMDevice_AddRef(This->parent); - - *out = (IAudioClient *)&This->IAudioClient3_iface; - IAudioClient3_AddRef(&This->IAudioClient3_iface); - - return S_OK; -} - -static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioClient) || - IsEqualIID(riid, &IID_IAudioClient2) || - IsEqualIID(riid, &IID_IAudioClient3)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - ULONG ref; - - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref){ - IAudioClient3_Stop(iface); - IMMDevice_Release(This->parent); - IUnknown_Release(This->pUnkFTMarshal); - if(This->session){ - EnterCriticalSection(&g_sessions_lock); - list_remove(&This->entry); - LeaveCriticalSection(&g_sessions_lock); - } - HeapFree(GetProcessHeap(), 0, This->vols); - if (This->stream) - alsa_stream_release(This->stream, This->timer_thread); - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static void dump_fmt(const WAVEFORMATEX *fmt) -{ - TRACE("wFormatTag: 0x%x (", fmt->wFormatTag); - switch(fmt->wFormatTag){ - case WAVE_FORMAT_PCM: - TRACE("WAVE_FORMAT_PCM"); - break; - case WAVE_FORMAT_IEEE_FLOAT: - TRACE("WAVE_FORMAT_IEEE_FLOAT"); - break; - case WAVE_FORMAT_EXTENSIBLE: - TRACE("WAVE_FORMAT_EXTENSIBLE"); - break; - default: - TRACE("Unknown"); - break; - } - TRACE(")\n"); - - TRACE("nChannels: %u\n", fmt->nChannels); - TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec); - TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec); - TRACE("nBlockAlign: %u\n", fmt->nBlockAlign); - TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample); - TRACE("cbSize: %u\n", fmt->cbSize); - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt; - TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask); - TRACE("Samples: %04x\n", fmtex->Samples.wReserved); - TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat)); - } -} - -static void session_init_vols(AudioSession *session, UINT channels) -{ - if(session->channel_count < channels){ - UINT i; - - if(session->channel_vols) - session->channel_vols = HeapReAlloc(GetProcessHeap(), 0, - session->channel_vols, sizeof(float) * channels); - else - session->channel_vols = HeapAlloc(GetProcessHeap(), 0, - sizeof(float) * channels); - if(!session->channel_vols) - return; - - for(i = session->channel_count; i < channels; ++i) - session->channel_vols[i] = 1.f; - - session->channel_count = channels; - } -} - -static AudioSession *create_session(const GUID *guid, IMMDevice *device, - UINT num_channels) -{ - AudioSession *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession)); - if(!ret) - return NULL; - - memcpy(&ret->guid, guid, sizeof(GUID)); - - ret->device = device; - - list_init(&ret->clients); - - list_add_head(&g_sessions, &ret->entry); - - session_init_vols(ret, num_channels); - - ret->master_vol = 1.f; - - return ret; -} - -/* if channels == 0, then this will return or create a session with - * matching dataflow and GUID. otherwise, channels must also match */ -static HRESULT get_audio_session(const GUID *sessionguid, - IMMDevice *device, UINT channels, AudioSession **out) -{ - AudioSession *session; - - if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){ - *out = create_session(&GUID_NULL, device, channels); - if(!*out) - return E_OUTOFMEMORY; - - return S_OK; - } - - *out = NULL; - LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){ - if(session->device == device && - IsEqualGUID(sessionguid, &session->guid)){ - session_init_vols(session, channels); - *out = session; - break; - } - } - - if(!*out){ - *out = create_session(sessionguid, device, channels); - if(!*out) - return E_OUTOFMEMORY; - } - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, - AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration, - REFERENCE_TIME period, const WAVEFORMATEX *fmt, - const GUID *sessionguid) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct create_stream_params params; - stream_handle stream; - unsigned int i; - - TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags, - wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid)); - - if(!fmt) - return E_POINTER; - - if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) - return E_INVALIDARG; - - if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS | - AUDCLNT_STREAMFLAGS_LOOPBACK | - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | - AUDCLNT_STREAMFLAGS_NOPERSIST | - AUDCLNT_STREAMFLAGS_RATEADJUST | - AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED | - AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | - AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){ - FIXME("Unknown flags: %08lx\n", flags); - return E_INVALIDARG; - } - - if(mode == AUDCLNT_SHAREMODE_SHARED){ - period = DefaultPeriod; - if( duration < 3 * period) - duration = 3 * period; - }else{ - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 || - ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED) - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - - if(!period) - period = DefaultPeriod; /* not minimum */ - if(period < MinimumPeriod || period > 5000000) - return AUDCLNT_E_INVALID_DEVICE_PERIOD; - if(duration > 20000000) /* the smaller the period, the lower this limit */ - return AUDCLNT_E_BUFFER_SIZE_ERROR; - if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){ - if(duration != period) - return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; - FIXME("EXCLUSIVE mode with EVENTCALLBACK\n"); - return AUDCLNT_E_DEVICE_IN_USE; - }else{ - if( duration < 8 * period) - duration = 8 * period; /* may grow above 2s */ - } - } - - EnterCriticalSection(&g_sessions_lock); - - if(This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_ALREADY_INITIALIZED; - } - - dump_fmt(fmt); - - params.name = NULL; - params.device = This->alsa_name; - params.flow = This->dataflow; - params.share = mode; - params.flags = flags; - params.duration = duration; - params.period = period; - params.fmt = fmt; - params.channel_count = NULL; - params.stream = &stream; - - ALSA_CALL(create_stream, ¶ms); - if(FAILED(params.result)){ - LeaveCriticalSection(&g_sessions_lock); - return params.result; - } - - This->channel_count = fmt->nChannels; - This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float)); - if(!This->vols){ - params.result = E_OUTOFMEMORY; - goto exit; - } - for(i = 0; i < This->channel_count; ++i) - This->vols[i] = 1.f; - - params.result = get_audio_session(sessionguid, This->parent, This->channel_count, - &This->session); - if(FAILED(params.result)) - goto exit; - - list_add_tail(&This->session->clients, &This->entry); - -exit: - if(FAILED(params.result)){ - alsa_stream_release(stream, NULL); - HeapFree(GetProcessHeap(), 0, This->vols); - This->vols = NULL; - }else{ - This->stream = stream; - set_stream_volumes(This); - } - - LeaveCriticalSection(&g_sessions_lock); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface, - UINT32 *out) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_buffer_size_params params; - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.frames = out; - - ALSA_CALL(get_buffer_size, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface, - REFERENCE_TIME *latency) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_latency_params params; - - TRACE("(%p)->(%p)\n", This, latency); - - if(!latency) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.latency = latency; - - ALSA_CALL(get_latency, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface, - UINT32 *out) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_current_padding_params params; - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.padding = out; - - ALSA_CALL(get_current_padding, ¶ms); - - TRACE("pad: %u\n", *out); - - return params.result; -} - -static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface, - AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt, - WAVEFORMATEX **out) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct is_format_supported_params params; - - TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out); - if(fmt) dump_fmt(fmt); - - params.device = This->alsa_name; - params.flow = This->dataflow; - params.share = mode; - params.fmt_in = fmt; - params.fmt_out = NULL; - - if(out){ - *out = NULL; - if(mode == AUDCLNT_SHAREMODE_SHARED) - params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out)); - } - ALSA_CALL(is_format_supported, ¶ms); - - if(params.result == S_FALSE) - *out = ¶ms.fmt_out->Format; - else - CoTaskMemFree(params.fmt_out); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, - WAVEFORMATEX **pwfx) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_mix_format_params params; - - TRACE("(%p)->(%p)\n", This, pwfx); - - if(!pwfx) - return E_POINTER; - *pwfx = NULL; - - params.device = This->alsa_name; - params.flow = This->dataflow; - params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE)); - if(!params.fmt) - return E_OUTOFMEMORY; - - ALSA_CALL(get_mix_format, ¶ms); - - if(SUCCEEDED(params.result)){ - *pwfx = ¶ms.fmt->Format; - dump_fmt(*pwfx); - } else - CoTaskMemFree(params.fmt); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, - REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod); - - if(!defperiod && !minperiod) - return E_POINTER; - - if(defperiod) - *defperiod = DefaultPeriod; - if(minperiod) - *minperiod = DefaultPeriod; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct start_params params; - - TRACE("(%p)\n", This); - - EnterCriticalSection(&g_sessions_lock); - - if(!This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_NOT_INITIALIZED; - } - - params.stream = This->stream; - - ALSA_CALL(start, ¶ms); - - if(SUCCEEDED(params.result) && !This->timer_thread){ - This->timer_thread = CreateThread(NULL, 0, alsa_timer_thread, This, 0, NULL); - SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL); - } - - LeaveCriticalSection(&g_sessions_lock); - - return params.result; -} - -static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct stop_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - - ALSA_CALL(stop, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct reset_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - - ALSA_CALL(reset, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface, - HANDLE event) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct set_event_handle_params params; - - TRACE("(%p)->(%p)\n", This, event); - - if(!event) - return E_INVALIDARG; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.event = event; - - ALSA_CALL(set_event_handle, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid, - void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - EnterCriticalSection(&g_sessions_lock); - - if(!This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_NOT_INITIALIZED; - } - - if(IsEqualIID(riid, &IID_IAudioRenderClient)){ - if(This->dataflow != eRender){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - } - IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface); - *ppv = &This->IAudioRenderClient_iface; - }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){ - if(This->dataflow != eCapture){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - } - IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface); - *ppv = &This->IAudioCaptureClient_iface; - }else if(IsEqualIID(riid, &IID_IAudioClock)){ - IAudioClock_AddRef(&This->IAudioClock_iface); - *ppv = &This->IAudioClock_iface; - }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){ - IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface); - *ppv = &This->IAudioStreamVolume_iface; - }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface); - - *ppv = &This->session_wrapper->IAudioSessionControl2_iface; - }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface); - - *ppv = &This->session_wrapper->IChannelAudioVolume_iface; - }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface); - - *ppv = &This->session_wrapper->ISimpleAudioVolume_iface; - } - - if(*ppv){ - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - - LeaveCriticalSection(&g_sessions_lock); - - FIXME("stub %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface, - AUDIO_STREAM_CATEGORY category, BOOL *offload_capable) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable); - - if(!offload_capable) - return E_INVALIDARG; - - *offload_capable = FALSE; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface, - const AudioClientProperties *prop) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop; - - TRACE("(%p)->(%p)\n", This, prop); - - if(!legacy_prop) - return E_POINTER; - - if(legacy_prop->cbSize == sizeof(AudioClientProperties)){ - TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n", - legacy_prop->bIsOffload, - legacy_prop->eCategory, - prop->Options); - }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){ - TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n", - legacy_prop->bIsOffload, - legacy_prop->eCategory); - }else{ - WARN("Unsupported Size = %d\n", legacy_prop->cbSize); - return E_INVALIDARG; - } - - - if(legacy_prop->bIsOffload) - return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface, - const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration, - REFERENCE_TIME *max_duration) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface, - const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames, - UINT32 *min_period_frames, UINT32 *max_period_frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames, - min_period_frames, max_period_frames); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface, - WAVEFORMATEX **cur_format, UINT32 *cur_period_frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface, - DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format, - const GUID *session_guid) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid)); - - return E_NOTIMPL; -} - -static const IAudioClient3Vtbl AudioClient3_Vtbl = -{ - AudioClient_QueryInterface, - AudioClient_AddRef, - AudioClient_Release, - AudioClient_Initialize, - AudioClient_GetBufferSize, - AudioClient_GetStreamLatency, - AudioClient_GetCurrentPadding, - AudioClient_IsFormatSupported, - AudioClient_GetMixFormat, - AudioClient_GetDevicePeriod, - AudioClient_Start, - AudioClient_Stop, - AudioClient_Reset, - AudioClient_SetEventHandle, - AudioClient_GetService, - AudioClient_IsOffloadCapable, - AudioClient_SetClientProperties, - AudioClient_GetBufferSizeLimits, - AudioClient_GetSharedModeEnginePeriod, - AudioClient_GetCurrentSharedModeEnginePeriod, - AudioClient_InitializeSharedAudioStream, -}; - -static HRESULT WINAPI AudioRenderClient_QueryInterface( - IAudioRenderClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioRenderClient)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface, - UINT32 frames, BYTE **data) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - struct get_render_buffer_params params; - - TRACE("(%p)->(%u, %p)\n", This, frames, data); - - if(!data) - return E_POINTER; - *data = NULL; - - params.stream = This->stream; - params.frames = frames; - params.data = data; - - ALSA_CALL(get_render_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioRenderClient_ReleaseBuffer( - IAudioRenderClient *iface, UINT32 written_frames, DWORD flags) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - struct release_render_buffer_params params; - - TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags); - - params.stream = This->stream; - params.written_frames = written_frames; - params.flags = flags; - - ALSA_CALL(release_render_buffer, ¶ms); - - return params.result; -} - -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = { - AudioRenderClient_QueryInterface, - AudioRenderClient_AddRef, - AudioRenderClient_Release, - AudioRenderClient_GetBuffer, - AudioRenderClient_ReleaseBuffer -}; - -static HRESULT WINAPI AudioCaptureClient_QueryInterface( - IAudioCaptureClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioCaptureClient)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface, - BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos, - UINT64 *qpcpos) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct get_capture_buffer_params params; - - TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags, - devpos, qpcpos); - - if(!data) - return E_POINTER; - - *data = NULL; - - if(!frames || !flags) - return E_POINTER; - - params.stream = This->stream; - params.data = data; - params.frames = frames; - params.flags = (UINT*)flags; - params.devpos = devpos; - params.qpcpos = qpcpos; - - ALSA_CALL(get_capture_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer( - IAudioCaptureClient *iface, UINT32 done) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct release_capture_buffer_params params; - - TRACE("(%p)->(%u)\n", This, done); - - params.stream = This->stream; - params.done = done; - - ALSA_CALL(release_capture_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize( - IAudioCaptureClient *iface, UINT32 *frames) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct get_next_packet_size_params params; - - TRACE("(%p)->(%p)\n", This, frames); - - if(!frames) - return E_POINTER; - - params.stream = This->stream; - params.frames = frames; - - ALSA_CALL(get_next_packet_size, ¶ms); - - return params.result; -} - -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl = -{ - AudioCaptureClient_QueryInterface, - AudioCaptureClient_AddRef, - AudioCaptureClient_Release, - AudioCaptureClient_GetBuffer, - AudioCaptureClient_ReleaseBuffer, - AudioCaptureClient_GetNextPacketSize -}; - -static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IAudioClock2)) - *ppv = &This->IAudioClock2_iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioClock_Release(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq) -{ - ACImpl *This = impl_from_IAudioClock(iface); - struct get_frequency_params params; - - TRACE("(%p)->(%p)\n", This, freq); - - params.stream = This->stream; - params.freq = freq; - - ALSA_CALL(get_frequency, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos, - UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock(iface); - struct get_position_params params; - - TRACE("(%p)->(%p, %p)\n", This, pos, qpctime); - - if(!pos) - return E_POINTER; - - params.stream = This->stream; - params.device = FALSE; - params.pos = pos; - params.qpctime = qpctime; - - ALSA_CALL(get_position, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface, - DWORD *chars) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%p)\n", This, chars); - - if(!chars) - return E_POINTER; - - *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ; - - return S_OK; -} - -static const IAudioClockVtbl AudioClock_Vtbl = -{ - AudioClock_QueryInterface, - AudioClock_AddRef, - AudioClock_Release, - AudioClock_GetFrequency, - AudioClock_GetPosition, - AudioClock_GetCharacteristics -}; - -static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv); -} - -static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface, - UINT64 *pos, UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - - FIXME("(%p)->(%p, %p)\n", This, pos, qpctime); - - return E_NOTIMPL; -} - -static const IAudioClock2Vtbl AudioClock2_Vtbl = -{ - AudioClock2_QueryInterface, - AudioClock2_AddRef, - AudioClock2_Release, - AudioClock2_GetDevicePosition -}; - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client) -{ - AudioSessionWrapper *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(AudioSessionWrapper)); - if(!ret) - return NULL; - - ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl; - ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl; - ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl; - - ret->ref = 1; - - ret->client = client; - if(client){ - ret->session = client->session; - AudioClient_AddRef(&client->IAudioClient3_iface); - } - - return ret; -} - -static HRESULT WINAPI AudioSessionControl_QueryInterface( - IAudioSessionControl2 *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionControl) || - IsEqualIID(riid, &IID_IAudioSessionControl2)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref){ - if(This->client){ - EnterCriticalSection(&g_sessions_lock); - This->client->session_wrapper = NULL; - LeaveCriticalSection(&g_sessions_lock); - AudioClient_Release(&This->client->IAudioClient3_iface); - } - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface, - AudioSessionState *state) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - struct is_started_params params; - ACImpl *client; - - TRACE("(%p)->(%p)\n", This, state); - - if(!state) - return NULL_PTR_ERR; - - EnterCriticalSection(&g_sessions_lock); - - if(list_empty(&This->session->clients)){ - *state = AudioSessionStateExpired; - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - - LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){ - params.stream = client->stream; - ALSA_CALL(is_started, ¶ms); - if(params.result == S_OK){ - *state = AudioSessionStateActive; - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - } - - LeaveCriticalSection(&g_sessions_lock); - - *state = AudioSessionStateInactive; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetDisplayName( - IAudioSessionControl2 *iface, WCHAR **name) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, name); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetDisplayName( - IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetIconPath( - IAudioSessionControl2 *iface, WCHAR **path) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, path); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetIconPath( - IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetGroupingParam( - IAudioSessionControl2 *iface, GUID *group) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, group); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetGroupingParam( - IAudioSessionControl2 *iface, const GUID *group, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group), - debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetProcessId( - IAudioSessionControl2 *iface, DWORD *pid) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%p)\n", This, pid); - - if(!pid) - return E_POINTER; - - *pid = GetCurrentProcessId(); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession( - IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)\n", This); - - return S_FALSE; -} - -static HRESULT WINAPI AudioSessionControl_SetDuckingPreference( - IAudioSessionControl2 *iface, BOOL optout) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%d)\n", This, optout); - - return S_OK; -} - -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl = -{ - AudioSessionControl_QueryInterface, - AudioSessionControl_AddRef, - AudioSessionControl_Release, - AudioSessionControl_GetState, - AudioSessionControl_GetDisplayName, - AudioSessionControl_SetDisplayName, - AudioSessionControl_GetIconPath, - AudioSessionControl_SetIconPath, - AudioSessionControl_GetGroupingParam, - AudioSessionControl_SetGroupingParam, - AudioSessionControl_RegisterAudioSessionNotification, - AudioSessionControl_UnregisterAudioSessionNotification, - AudioSessionControl_GetSessionIdentifier, - AudioSessionControl_GetSessionInstanceIdentifier, - AudioSessionControl_GetProcessId, - AudioSessionControl_IsSystemSoundsSession, - AudioSessionControl_SetDuckingPreference -}; - -static HRESULT WINAPI SimpleAudioVolume_QueryInterface( - ISimpleAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_ISimpleAudioVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume( - ISimpleAudioVolume *iface, float level, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context)); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->master_vol = level; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume( - ISimpleAudioVolume *iface, float *level) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, level); - - if(!level) - return NULL_PTR_ERR; - - *level = session->master_vol; - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface, - BOOL mute, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context)); - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->mute = mute; - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface, - BOOL *mute) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, mute); - - if(!mute) - return NULL_PTR_ERR; - - *mute = session->mute; - - return S_OK; -} - -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl = -{ - SimpleAudioVolume_QueryInterface, - SimpleAudioVolume_AddRef, - SimpleAudioVolume_Release, - SimpleAudioVolume_SetMasterVolume, - SimpleAudioVolume_GetMasterVolume, - SimpleAudioVolume_SetMute, - SimpleAudioVolume_GetMute -}; - -static HRESULT WINAPI AudioStreamVolume_QueryInterface( - IAudioStreamVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioStreamVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelCount( - IAudioStreamVolume *iface, UINT32 *out) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - *out = This->channel_count; - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_SetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%d, %f)\n", This, index, level); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(index >= This->channel_count) - return E_INVALIDARG; - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - This->vols[index] = level; - set_stream_volumes(This); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float *level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%d, %p)\n", This, index, level); - - if(!level) - return E_POINTER; - - if(index >= This->channel_count) - return E_INVALIDARG; - - *level = This->vols[index]; - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_SetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, const float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - unsigned int i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if(!levels) - return E_POINTER; - - if(count != This->channel_count) - return E_INVALIDARG; - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - This->vols[i] = levels[i]; - set_stream_volumes(This); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_GetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - unsigned int i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if(!levels) - return E_POINTER; - - if(count != This->channel_count) - return E_INVALIDARG; - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - levels[i] = This->vols[i]; - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl = -{ - AudioStreamVolume_QueryInterface, - AudioStreamVolume_AddRef, - AudioStreamVolume_Release, - AudioStreamVolume_GetChannelCount, - AudioStreamVolume_SetChannelVolume, - AudioStreamVolume_GetChannelVolume, - AudioStreamVolume_SetAllVolumes, - AudioStreamVolume_GetAllVolumes -}; - -static HRESULT WINAPI ChannelAudioVolume_QueryInterface( - IChannelAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IChannelAudioVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelCount( - IChannelAudioVolume *iface, UINT32 *out) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, out); - - if(!out) - return NULL_PTR_ERR; - - *out = session->channel_count; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float level, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%d, %f, %s)\n", session, index, level, - wine_dbgstr_guid(context)); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(index >= session->channel_count) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->channel_vols[index] = level; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float *level) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%d, %p)\n", session, index, level); - - if(!level) - return NULL_PTR_ERR; - - if(index >= session->channel_count) - return E_INVALIDARG; - - *level = session->channel_vols[index]; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, const float *levels, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - unsigned int i; - ACImpl *client; - - TRACE("(%p)->(%d, %p, %s)\n", session, count, levels, - wine_dbgstr_guid(context)); - - if(!levels) - return NULL_PTR_ERR; - - if(count != session->channel_count) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - TRACE("ALSA does not support volume control\n"); - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - session->channel_vols[i] = levels[i]; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, float *levels) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - unsigned int i; - - TRACE("(%p)->(%d, %p)\n", session, count, levels); - - if(!levels) - return NULL_PTR_ERR; - - if(count != session->channel_count) - return E_INVALIDARG; - - for(i = 0; i < count; ++i) - levels[i] = session->channel_vols[i]; - - return S_OK; -} - -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl = -{ - ChannelAudioVolume_QueryInterface, - ChannelAudioVolume_AddRef, - ChannelAudioVolume_Release, - ChannelAudioVolume_GetChannelCount, - ChannelAudioVolume_SetChannelVolume, - ChannelAudioVolume_GetChannelVolume, - ChannelAudioVolume_SetAllVolumes, - ChannelAudioVolume_GetAllVolumes -}; - -static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface, - REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionManager) || - IsEqualIID(riid, &IID_IAudioSessionManager2)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref) - HeapFree(GetProcessHeap(), 0, This); - return ref; -} - -static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - IAudioSessionControl **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if(FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - ISimpleAudioVolume **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if(FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = &wrapper->ISimpleAudioVolume_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator( - IAudioSessionManager2 *iface, IAudioSessionEnumerator **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, out); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification( - IAudioSessionManager2 *iface, const WCHAR *session_id, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification( - IAudioSessionManager2 *iface, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl = -{ - AudioSessionManager_QueryInterface, - AudioSessionManager_AddRef, - AudioSessionManager_Release, - AudioSessionManager_GetAudioSessionControl, - AudioSessionManager_GetSimpleAudioVolume, - AudioSessionManager_GetSessionEnumerator, - AudioSessionManager_RegisterSessionNotification, - AudioSessionManager_UnregisterSessionNotification, - AudioSessionManager_RegisterDuckNotification, - AudioSessionManager_UnregisterDuckNotification -}; - -HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device, - IAudioSessionManager2 **out) -{ - SessionMgr *This; - - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr)); - if(!This) - return E_OUTOFMEMORY; - - This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl; - This->device = device; - This->ref = 1; - - *out = &This->IAudioSessionManager2_iface; - - return S_OK; -} - -HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out) -{ - struct get_prop_value_params params; - char name[256]; - EDataFlow flow; - unsigned int size = 0; - - TRACE("%s, (%s,%lu), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out); - - if(!get_alsa_name_by_guid(guid, name, sizeof(name), &flow)) - { - WARN("Unknown interface %s\n", debugstr_guid(guid)); - return E_NOINTERFACE; - } - - params.device = name; - params.flow = flow; - params.guid = guid; - params.prop = prop; - params.value = out; - params.buffer = NULL; - params.buffer_size = &size; - - while(1) { - ALSA_CALL(get_prop_value, ¶ms); - - if(params.result != E_NOT_SUFFICIENT_BUFFER) - break; - - CoTaskMemFree(params.buffer); - params.buffer = CoTaskMemAlloc(*params.buffer_size); - if(!params.buffer) - return E_OUTOFMEMORY; - } - if(FAILED(params.result)) - CoTaskMemFree(params.buffer); - - return params.result; -} diff --git a/pkgs/osu-wine/audio-revert/winealsa.drv/unixlib.h b/pkgs/osu-wine/audio-revert/winealsa.drv/unixlib.h deleted file mode 100644 index 5784d5f..0000000 --- a/pkgs/osu-wine/audio-revert/winealsa.drv/unixlib.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "../mmdevapi/unixlib.h" - -NTSTATUS alsa_midi_release(void *args); -NTSTATUS alsa_midi_out_message(void *args); -NTSTATUS alsa_midi_in_message(void *args); -NTSTATUS alsa_midi_notify_wait(void *args); - -#ifdef _WIN64 -NTSTATUS alsa_wow64_midi_out_message(void *args); -NTSTATUS alsa_wow64_midi_in_message(void *args); -NTSTATUS alsa_wow64_midi_notify_wait(void *args); -#endif - -#define ALSA_CALL(func, params) WINE_UNIX_CALL(func, params) diff --git a/pkgs/osu-wine/audio-revert/winealsa.drv/winealsa.drv.spec b/pkgs/osu-wine/audio-revert/winealsa.drv/winealsa.drv.spec deleted file mode 100644 index bd83ea2..0000000 --- a/pkgs/osu-wine/audio-revert/winealsa.drv/winealsa.drv.spec +++ /dev/null @@ -1,11 +0,0 @@ -# WinMM driver functions -@ stdcall -private DriverProc(long long long long long) ALSA_DriverProc -@ stdcall -private midMessage(long long long long long) ALSA_midMessage -@ stdcall -private modMessage(long long long long long) ALSA_modMessage - -# MMDevAPI driver functions -@ stdcall -private GetPriority() AUDDRV_GetPriority -@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs -@ stdcall -private GetAudioEndpoint(ptr ptr ptr) AUDDRV_GetAudioEndpoint -@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager -@ stdcall -private GetPropValue(ptr ptr ptr) AUDDRV_GetPropValue diff --git a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/Makefile.in b/pkgs/osu-wine/audio-revert/winecoreaudio.drv/Makefile.in deleted file mode 100644 index 1bcc58d..0000000 --- a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/Makefile.in +++ /dev/null @@ -1,11 +0,0 @@ -MODULE = winecoreaudio.drv -UNIXLIB = winecoreaudio.so -IMPORTS = uuid ole32 user32 advapi32 -DELAYIMPORTS = winmm -UNIX_LIBS = $(COREAUDIO_LIBS) - -SOURCES = \ - coreaudio.c \ - coremidi.c \ - midi.c \ - mmdevdrv.c diff --git a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coreaudio.c b/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coreaudio.c deleted file mode 100644 index b48a0c7..0000000 --- a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coreaudio.c +++ /dev/null @@ -1,2030 +0,0 @@ -/* - * Unixlib for winecoreaudio driver. - * - * Copyright 2011 Andrew Eikum for CodeWeavers - * Copyright 2021 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#if 0 -#pragma makedep unix -#endif - -#include "config.h" - -#define LoadResource __carbon_LoadResource -#define CompareString __carbon_CompareString -#define GetCurrentThread __carbon_GetCurrentThread -#define GetCurrentProcess __carbon_GetCurrentProcess - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#undef LoadResource -#undef CompareString -#undef GetCurrentThread -#undef GetCurrentProcess -#undef _CDECL - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winternl.h" -#include "mmdeviceapi.h" -#include "initguid.h" -#include "audioclient.h" -#include "wine/debug.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(coreaudio); - -#define MAX_DEV_NAME_LEN 10 /* Max 32 bit digits */ - -struct coreaudio_stream -{ - OSSpinLock lock; - AudioComponentInstance unit; - AudioConverterRef converter; - AudioStreamBasicDescription dev_desc; /* audio unit format, not necessarily the same as fmt */ - AudioDeviceID dev_id; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - - BOOL playing; - UINT32 period_ms, period_frames; - UINT32 bufsize_frames, resamp_bufsize_frames; - UINT32 lcl_offs_frames, held_frames, wri_offs_frames, tmp_buffer_frames; - UINT32 cap_bufsize_frames, cap_offs_frames, cap_held_frames; - UINT32 wrap_bufsize_frames; - UINT64 written_frames; - INT32 getbuf_last; - WAVEFORMATEX *fmt; - BYTE *local_buffer, *cap_buffer, *wrap_buffer, *resamp_buffer, *tmp_buffer; -}; - -static HRESULT osstatus_to_hresult(OSStatus sc) -{ - switch(sc){ - case kAudioFormatUnsupportedDataFormatError: - case kAudioFormatUnknownFormatError: - case kAudioDeviceUnsupportedFormatError: - return AUDCLNT_E_UNSUPPORTED_FORMAT; - case kAudioHardwareBadDeviceError: - return AUDCLNT_E_DEVICE_INVALIDATED; - } - return E_FAIL; -} - -static struct coreaudio_stream *handle_get_stream(stream_handle h) -{ - return (struct coreaudio_stream *)(UINT_PTR)h; -} - -/* copied from kernelbase */ -static int muldiv( int a, int b, int c ) -{ - LONGLONG ret; - - if (!c) return -1; - - /* We want to deal with a positive divisor to simplify the logic. */ - if (c < 0) - { - a = -a; - c = -c; - } - - /* If the result is positive, we "add" to round. else, we subtract to round. */ - if ((a < 0 && b < 0) || (a >= 0 && b >= 0)) - ret = (((LONGLONG)a * b) + (c / 2)) / c; - else - ret = (((LONGLONG)a * b) - (c / 2)) / c; - - if (ret > 2147483647 || ret < -2147483647) return -1; - return ret; -} - -static AudioObjectPropertyScope get_scope(EDataFlow flow) -{ - return (flow == eRender) ? kAudioDevicePropertyScopeOutput : kAudioDevicePropertyScopeInput; -} - -static BOOL device_has_channels(AudioDeviceID device, EDataFlow flow) -{ - AudioObjectPropertyAddress addr; - AudioBufferList *buffers; - BOOL ret = FALSE; - OSStatus sc; - UInt32 size; - int i; - - addr.mSelector = kAudioDevicePropertyStreamConfiguration; - addr.mScope = get_scope(flow); - addr.mElement = 0; - - sc = AudioObjectGetPropertyDataSize(device, &addr, 0, NULL, &size); - if(sc != noErr){ - WARN("Unable to get _StreamConfiguration property size for device %u: %x\n", - (unsigned int)device, (int)sc); - return FALSE; - } - - buffers = malloc(size); - if(!buffers) return FALSE; - - sc = AudioObjectGetPropertyData(device, &addr, 0, NULL, &size, buffers); - if(sc != noErr){ - WARN("Unable to get _StreamConfiguration property for device %u: %x\n", - (unsigned int)device, (int)sc); - free(buffers); - return FALSE; - } - - for(i = 0; i < buffers->mNumberBuffers; i++){ - if(buffers->mBuffers[i].mNumberChannels > 0){ - ret = TRUE; - break; - } - } - free(buffers); - return ret; -} - -static NTSTATUS unix_get_endpoint_ids(void *args) -{ - struct get_endpoint_ids_params *params = args; - unsigned int num_devices, i, needed, offset; - AudioDeviceID *devices, default_id; - AudioObjectPropertyAddress addr; - struct endpoint *endpoint; - UInt32 devsize, size; - struct endpoint_info - { - CFStringRef name; - AudioDeviceID id; - } *info; - OSStatus sc; - UniChar *ptr; - - params->num = 0; - params->default_idx = 0; - - addr.mScope = kAudioObjectPropertyScopeGlobal; - addr.mElement = kAudioObjectPropertyElementMaster; - if(params->flow == eRender) addr.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - else if(params->flow == eCapture) addr.mSelector = kAudioHardwarePropertyDefaultInputDevice; - else{ - params->result = E_INVALIDARG; - return STATUS_SUCCESS; - } - - size = sizeof(default_id); - sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &size, &default_id); - if(sc != noErr){ - WARN("Getting _DefaultInputDevice property failed: %x\n", (int)sc); - default_id = -1; - } - - addr.mSelector = kAudioHardwarePropertyDevices; - sc = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, NULL, &devsize); - if(sc != noErr){ - WARN("Getting _Devices property size failed: %x\n", (int)sc); - params->result = osstatus_to_hresult(sc); - return STATUS_SUCCESS; - } - - num_devices = devsize / sizeof(AudioDeviceID); - devices = malloc(devsize); - info = malloc(num_devices * sizeof(*info)); - if(!devices || !info){ - free(info); - free(devices); - params->result = E_OUTOFMEMORY; - return STATUS_SUCCESS; - } - - sc = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, NULL, &devsize, devices); - if(sc != noErr){ - WARN("Getting _Devices property failed: %x\n", (int)sc); - free(info); - free(devices); - params->result = osstatus_to_hresult(sc); - return STATUS_SUCCESS; - } - - addr.mSelector = kAudioObjectPropertyName; - addr.mScope = get_scope(params->flow); - addr.mElement = 0; - - for(i = 0; i < num_devices; i++){ - if(!device_has_channels(devices[i], params->flow)) continue; - - size = sizeof(CFStringRef); - sc = AudioObjectGetPropertyData(devices[i], &addr, 0, NULL, &size, &info[params->num].name); - if(sc != noErr){ - WARN("Unable to get _Name property for device %u: %x\n", - (unsigned int)devices[i], (int)sc); - continue; - } - info[params->num++].id = devices[i]; - } - free(devices); - - offset = needed = sizeof(*endpoint) * params->num; - endpoint = params->endpoints; - - for(i = 0; i < params->num; i++){ - const SIZE_T name_len = CFStringGetLength(info[i].name) + 1; - const SIZE_T device_len = MAX_DEV_NAME_LEN + 1; - needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1); - - if(needed <= params->size){ - endpoint->name = offset; - ptr = (UniChar *)((char *)params->endpoints + offset); - CFStringGetCharacters(info[i].name, CFRangeMake(0, name_len - 1), ptr); - ptr[name_len - 1] = 0; - offset += name_len * sizeof(WCHAR); - endpoint->device = offset; - sprintf((char *)params->endpoints + offset, "%u", (unsigned int)info[i].id); - offset += (device_len + 1) & ~1; - endpoint++; - } - CFRelease(info[i].name); - if(info[i].id == default_id) params->default_idx = i; - } - free(info); - - if(needed > params->size){ - params->size = needed; - params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - } - else params->result = S_OK; - - return STATUS_SUCCESS; -} - -static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt) -{ - WAVEFORMATEX *ret; - size_t size; - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - size = sizeof(WAVEFORMATEXTENSIBLE); - else - size = sizeof(WAVEFORMATEX); - - ret = malloc(size); - if(!ret) - return NULL; - - memcpy(ret, fmt, size); - - ret->cbSize = size - sizeof(WAVEFORMATEX); - - return ret; -} - -static void silence_buffer(struct coreaudio_stream *stream, BYTE *buffer, UINT32 frames) -{ - WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt; - if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM || - (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) && - stream->fmt->wBitsPerSample == 8) - memset(buffer, 128, frames * stream->fmt->nBlockAlign); - else - memset(buffer, 0, frames * stream->fmt->nBlockAlign); -} - -/* CA is pulling data from us */ -static OSStatus ca_render_cb(void *user, AudioUnitRenderActionFlags *flags, - const AudioTimeStamp *ts, UInt32 bus, UInt32 nframes, - AudioBufferList *data) -{ - struct coreaudio_stream *stream = user; - UINT32 to_copy_bytes, to_copy_frames, chunk_bytes, lcl_offs_bytes; - - OSSpinLockLock(&stream->lock); - - if(stream->playing){ - lcl_offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign; - to_copy_frames = min(nframes, stream->held_frames); - to_copy_bytes = to_copy_frames * stream->fmt->nBlockAlign; - - chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) * stream->fmt->nBlockAlign; - - if(to_copy_bytes > chunk_bytes){ - memcpy(data->mBuffers[0].mData, stream->local_buffer + lcl_offs_bytes, chunk_bytes); - memcpy(((BYTE *)data->mBuffers[0].mData) + chunk_bytes, stream->local_buffer, to_copy_bytes - chunk_bytes); - }else - memcpy(data->mBuffers[0].mData, stream->local_buffer + lcl_offs_bytes, to_copy_bytes); - - stream->lcl_offs_frames += to_copy_frames; - stream->lcl_offs_frames %= stream->bufsize_frames; - stream->held_frames -= to_copy_frames; - }else - to_copy_bytes = to_copy_frames = 0; - - if(nframes > to_copy_frames) - silence_buffer(stream, ((BYTE *)data->mBuffers[0].mData) + to_copy_bytes, nframes - to_copy_frames); - - OSSpinLockUnlock(&stream->lock); - - return noErr; -} - -static void ca_wrap_buffer(BYTE *dst, UINT32 dst_offs, UINT32 dst_bytes, - BYTE *src, UINT32 src_bytes) -{ - UINT32 chunk_bytes = dst_bytes - dst_offs; - - if(chunk_bytes < src_bytes){ - memcpy(dst + dst_offs, src, chunk_bytes); - memcpy(dst, src + chunk_bytes, src_bytes - chunk_bytes); - }else - memcpy(dst + dst_offs, src, src_bytes); -} - -/* we need to trigger CA to pull data from the device and give it to us - * - * raw data from CA is stored in cap_buffer, possibly via wrap_buffer - * - * raw data is resampled from cap_buffer into resamp_buffer in period-size - * chunks and copied to local_buffer - */ -static OSStatus ca_capture_cb(void *user, AudioUnitRenderActionFlags *flags, - const AudioTimeStamp *ts, UInt32 bus, UInt32 nframes, - AudioBufferList *data) -{ - struct coreaudio_stream *stream = user; - AudioBufferList list; - OSStatus sc; - UINT32 cap_wri_offs_frames; - - OSSpinLockLock(&stream->lock); - - cap_wri_offs_frames = (stream->cap_offs_frames + stream->cap_held_frames) % stream->cap_bufsize_frames; - - list.mNumberBuffers = 1; - list.mBuffers[0].mNumberChannels = stream->fmt->nChannels; - list.mBuffers[0].mDataByteSize = nframes * stream->fmt->nBlockAlign; - - if(!stream->playing || cap_wri_offs_frames + nframes > stream->cap_bufsize_frames){ - if(stream->wrap_bufsize_frames < nframes){ - free(stream->wrap_buffer); - stream->wrap_buffer = malloc(list.mBuffers[0].mDataByteSize); - stream->wrap_bufsize_frames = nframes; - } - - list.mBuffers[0].mData = stream->wrap_buffer; - }else - list.mBuffers[0].mData = stream->cap_buffer + cap_wri_offs_frames * stream->fmt->nBlockAlign; - - sc = AudioUnitRender(stream->unit, flags, ts, bus, nframes, &list); - if(sc != noErr){ - OSSpinLockUnlock(&stream->lock); - return sc; - } - - if(stream->playing){ - if(list.mBuffers[0].mData == stream->wrap_buffer){ - ca_wrap_buffer(stream->cap_buffer, - cap_wri_offs_frames * stream->fmt->nBlockAlign, - stream->cap_bufsize_frames * stream->fmt->nBlockAlign, - stream->wrap_buffer, list.mBuffers[0].mDataByteSize); - } - - stream->cap_held_frames += list.mBuffers[0].mDataByteSize / stream->fmt->nBlockAlign; - if(stream->cap_held_frames > stream->cap_bufsize_frames){ - stream->cap_offs_frames += stream->cap_held_frames % stream->cap_bufsize_frames; - stream->cap_offs_frames %= stream->cap_bufsize_frames; - stream->cap_held_frames = stream->cap_bufsize_frames; - } - } - - OSSpinLockUnlock(&stream->lock); - return noErr; -} - -static AudioComponentInstance get_audiounit(EDataFlow dataflow, AudioDeviceID adevid) -{ - AudioComponentInstance unit; - AudioComponent comp; - AudioComponentDescription desc; - OSStatus sc; - - memset(&desc, 0, sizeof(desc)); - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_HALOutput; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - - if(!(comp = AudioComponentFindNext(NULL, &desc))){ - WARN("AudioComponentFindNext failed\n"); - return NULL; - } - - sc = AudioComponentInstanceNew(comp, &unit); - if(sc != noErr){ - WARN("AudioComponentInstanceNew failed: %x\n", (int)sc); - return NULL; - } - - if(dataflow == eCapture){ - UInt32 enableio; - - enableio = 1; - sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, 1, &enableio, sizeof(enableio)); - if(sc != noErr){ - WARN("Couldn't enable I/O on input element: %x\n", (int)sc); - AudioComponentInstanceDispose(unit); - return NULL; - } - - enableio = 0; - sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, 0, &enableio, sizeof(enableio)); - if(sc != noErr){ - WARN("Couldn't disable I/O on output element: %x\n", (int)sc); - AudioComponentInstanceDispose(unit); - return NULL; - } - } - - sc = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, &adevid, sizeof(adevid)); - if(sc != noErr){ - WARN("Couldn't set audio unit device\n"); - AudioComponentInstanceDispose(unit); - return NULL; - } - - return unit; -} - -static void dump_adesc(const char *aux, AudioStreamBasicDescription *desc) -{ - TRACE("%s: mSampleRate: %f\n", aux, desc->mSampleRate); - TRACE("%s: mBytesPerPacket: %u\n", aux, (unsigned int)desc->mBytesPerPacket); - TRACE("%s: mFramesPerPacket: %u\n", aux, (unsigned int)desc->mFramesPerPacket); - TRACE("%s: mBytesPerFrame: %u\n", aux, (unsigned int)desc->mBytesPerFrame); - TRACE("%s: mChannelsPerFrame: %u\n", aux, (unsigned int)desc->mChannelsPerFrame); - TRACE("%s: mBitsPerChannel: %u\n", aux, (unsigned int)desc->mBitsPerChannel); -} - -static HRESULT ca_get_audiodesc(AudioStreamBasicDescription *desc, - const WAVEFORMATEX *fmt) -{ - const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt; - - desc->mFormatFlags = 0; - - if(fmt->wFormatTag == WAVE_FORMAT_PCM || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){ - desc->mFormatID = kAudioFormatLinearPCM; - if(fmt->wBitsPerSample > 8) - desc->mFormatFlags = kAudioFormatFlagIsSignedInteger; - }else if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){ - desc->mFormatID = kAudioFormatLinearPCM; - desc->mFormatFlags = kAudioFormatFlagIsFloat; - }else if(fmt->wFormatTag == WAVE_FORMAT_MULAW || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_MULAW))){ - desc->mFormatID = kAudioFormatULaw; - }else if(fmt->wFormatTag == WAVE_FORMAT_ALAW || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_ALAW))){ - desc->mFormatID = kAudioFormatALaw; - }else - return AUDCLNT_E_UNSUPPORTED_FORMAT; - - desc->mSampleRate = fmt->nSamplesPerSec; - desc->mBytesPerPacket = fmt->nBlockAlign; - desc->mFramesPerPacket = 1; - desc->mBytesPerFrame = fmt->nBlockAlign; - desc->mChannelsPerFrame = fmt->nChannels; - desc->mBitsPerChannel = fmt->wBitsPerSample; - desc->mReserved = 0; - - return S_OK; -} - -static HRESULT ca_setup_audiounit(EDataFlow dataflow, AudioComponentInstance unit, - const WAVEFORMATEX *fmt, AudioStreamBasicDescription *dev_desc, - AudioConverterRef *converter) -{ - OSStatus sc; - HRESULT hr; - - if(dataflow == eCapture){ - AudioStreamBasicDescription desc; - UInt32 size; - Float64 rate; - fenv_t fenv; - BOOL fenv_stored = TRUE; - - hr = ca_get_audiodesc(&desc, fmt); - if(FAILED(hr)) - return hr; - dump_adesc("requested", &desc); - - /* input-only units can't perform sample rate conversion, so we have to - * set up our own AudioConverter to support arbitrary sample rates. */ - size = sizeof(*dev_desc); - sc = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 1, dev_desc, &size); - if(sc != noErr){ - WARN("Couldn't get unit format: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - dump_adesc("hardware", dev_desc); - - rate = dev_desc->mSampleRate; - *dev_desc = desc; - dev_desc->mSampleRate = rate; - - dump_adesc("final", dev_desc); - sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, dev_desc, sizeof(*dev_desc)); - if(sc != noErr){ - WARN("Couldn't set unit format: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - - /* AudioConverterNew requires divide-by-zero SSE exceptions to be masked */ - if(feholdexcept(&fenv)){ - WARN("Failed to store fenv state\n"); - fenv_stored = FALSE; - } - - sc = AudioConverterNew(dev_desc, &desc, converter); - - if(fenv_stored && fesetenv(&fenv)) - WARN("Failed to restore fenv state\n"); - - if(sc != noErr){ - WARN("Couldn't create audio converter: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - }else{ - hr = ca_get_audiodesc(dev_desc, fmt); - if(FAILED(hr)) - return hr; - - dump_adesc("final", dev_desc); - sc = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, dev_desc, sizeof(*dev_desc)); - if(sc != noErr){ - WARN("Couldn't set format: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - } - - return S_OK; -} - -static ULONG_PTR zero_bits(void) -{ -#ifdef _WIN64 - return !NtCurrentTeb()->WowTebOffset ? 0 : 0x7fffffff; -#else - return 0; -#endif -} - -static AudioDeviceID dev_id_from_device(const char *device) -{ - return strtoul(device, NULL, 10); -} - -static NTSTATUS unix_create_stream(void *args) -{ - struct create_stream_params *params = args; - struct coreaudio_stream *stream = calloc(1, sizeof(*stream)); - AURenderCallbackStruct input; - OSStatus sc; - SIZE_T size; - - if(!stream){ - params->result = E_OUTOFMEMORY; - return STATUS_SUCCESS; - } - - stream->fmt = clone_format(params->fmt); - if(!stream->fmt){ - params->result = E_OUTOFMEMORY; - goto end; - } - - stream->period_ms = params->period / 10000; - stream->period_frames = muldiv(params->period, stream->fmt->nSamplesPerSec, 10000000); - stream->dev_id = dev_id_from_device(params->device); - stream->flow = params->flow; - stream->share = params->share; - - stream->bufsize_frames = muldiv(params->duration, stream->fmt->nSamplesPerSec, 10000000); - if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE) - stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames; - - if(!(stream->unit = get_audiounit(stream->flow, stream->dev_id))){ - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - goto end; - } - - params->result = ca_setup_audiounit(stream->flow, stream->unit, stream->fmt, &stream->dev_desc, &stream->converter); - if(FAILED(params->result)) goto end; - - input.inputProcRefCon = stream; - if(stream->flow == eCapture){ - input.inputProc = ca_capture_cb; - sc = AudioUnitSetProperty(stream->unit, kAudioOutputUnitProperty_SetInputCallback, - kAudioUnitScope_Output, 1, &input, sizeof(input)); - }else{ - input.inputProc = ca_render_cb; - sc = AudioUnitSetProperty(stream->unit, kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, &input, sizeof(input)); - } - if(sc != noErr){ - WARN("Couldn't set callback: %x\n", (int)sc); - params->result = osstatus_to_hresult(sc); - goto end; - } - - sc = AudioUnitInitialize(stream->unit); - if(sc != noErr){ - WARN("Couldn't initialize: %x\n", (int)sc); - params->result = osstatus_to_hresult(sc); - goto end; - } - - /* we play audio continuously because AudioOutputUnitStart sometimes takes - * a while to return */ - sc = AudioOutputUnitStart(stream->unit); - if(sc != noErr){ - WARN("Unit failed to start: %x\n", (int)sc); - params->result = osstatus_to_hresult(sc); - goto end; - } - - size = stream->bufsize_frames * stream->fmt->nBlockAlign; - if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, zero_bits(), - &size, MEM_COMMIT, PAGE_READWRITE)){ - params->result = E_OUTOFMEMORY; - goto end; - } - silence_buffer(stream, stream->local_buffer, stream->bufsize_frames); - - if(stream->flow == eCapture){ - stream->cap_bufsize_frames = muldiv(params->duration, stream->dev_desc.mSampleRate, 10000000); - stream->cap_buffer = malloc(stream->cap_bufsize_frames * stream->fmt->nBlockAlign); - } - params->result = S_OK; - -end: - if(FAILED(params->result)){ - if(stream->converter) AudioConverterDispose(stream->converter); - if(stream->unit) AudioComponentInstanceDispose(stream->unit); - free(stream->fmt); - free(stream); - } else - *params->stream = (stream_handle)(UINT_PTR)stream; - - return STATUS_SUCCESS; -} - -static NTSTATUS unix_release_stream( void *args ) -{ - struct release_stream_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - SIZE_T size; - - if(stream->unit){ - AudioOutputUnitStop(stream->unit); - AudioComponentInstanceDispose(stream->unit); - } - - if(stream->converter) AudioConverterDispose(stream->converter); - free(stream->resamp_buffer); - free(stream->wrap_buffer); - free(stream->cap_buffer); - if(stream->local_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, - &size, MEM_RELEASE); - } - if(stream->tmp_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, - &size, MEM_RELEASE); - } - free(stream->fmt); - free(stream); - params->result = S_OK; - return STATUS_SUCCESS; -} - -static UINT ca_channel_layout_to_channel_mask(const AudioChannelLayout *layout) -{ - int i; - UINT mask = 0; - - for (i = 0; i < layout->mNumberChannelDescriptions; ++i) { - switch (layout->mChannelDescriptions[i].mChannelLabel) { - default: FIXME("Unhandled channel 0x%x\n", - (unsigned int)layout->mChannelDescriptions[i].mChannelLabel); break; - case kAudioChannelLabel_Left: mask |= SPEAKER_FRONT_LEFT; break; - case kAudioChannelLabel_Mono: - case kAudioChannelLabel_Center: mask |= SPEAKER_FRONT_CENTER; break; - case kAudioChannelLabel_Right: mask |= SPEAKER_FRONT_RIGHT; break; - case kAudioChannelLabel_LeftSurround: mask |= SPEAKER_BACK_LEFT; break; - case kAudioChannelLabel_CenterSurround: mask |= SPEAKER_BACK_CENTER; break; - case kAudioChannelLabel_RightSurround: mask |= SPEAKER_BACK_RIGHT; break; - case kAudioChannelLabel_LFEScreen: mask |= SPEAKER_LOW_FREQUENCY; break; - case kAudioChannelLabel_LeftSurroundDirect: mask |= SPEAKER_SIDE_LEFT; break; - case kAudioChannelLabel_RightSurroundDirect: mask |= SPEAKER_SIDE_RIGHT; break; - case kAudioChannelLabel_TopCenterSurround: mask |= SPEAKER_TOP_CENTER; break; - case kAudioChannelLabel_VerticalHeightLeft: mask |= SPEAKER_TOP_FRONT_LEFT; break; - case kAudioChannelLabel_VerticalHeightCenter: mask |= SPEAKER_TOP_FRONT_CENTER; break; - case kAudioChannelLabel_VerticalHeightRight: mask |= SPEAKER_TOP_FRONT_RIGHT; break; - case kAudioChannelLabel_TopBackLeft: mask |= SPEAKER_TOP_BACK_LEFT; break; - case kAudioChannelLabel_TopBackCenter: mask |= SPEAKER_TOP_BACK_CENTER; break; - case kAudioChannelLabel_TopBackRight: mask |= SPEAKER_TOP_BACK_RIGHT; break; - case kAudioChannelLabel_LeftCenter: mask |= SPEAKER_FRONT_LEFT_OF_CENTER; break; - case kAudioChannelLabel_RightCenter: mask |= SPEAKER_FRONT_RIGHT_OF_CENTER; break; - } - } - - return mask; -} - -/* For most hardware on Windows, users must choose a configuration with an even - * number of channels (stereo, quad, 5.1, 7.1). Users can then disable - * channels, but those channels are still reported to applications from - * GetMixFormat! Some applications behave badly if given an odd number of - * channels (e.g. 2.1). Here, we find the nearest configuration that Windows - * would report for a given channel layout. */ -static void convert_channel_layout(const AudioChannelLayout *ca_layout, WAVEFORMATEXTENSIBLE *fmt) -{ - UINT ca_mask = ca_channel_layout_to_channel_mask(ca_layout); - - TRACE("Got channel mask for CA: 0x%x\n", ca_mask); - - if (ca_layout->mNumberChannelDescriptions == 1) - { - fmt->Format.nChannels = 1; - fmt->dwChannelMask = ca_mask; - return; - } - - /* compare against known configurations and find smallest configuration - * which is a superset of the given speakers */ - - if (ca_layout->mNumberChannelDescriptions <= 2 && - (ca_mask & ~KSAUDIO_SPEAKER_STEREO) == 0) - { - fmt->Format.nChannels = 2; - fmt->dwChannelMask = KSAUDIO_SPEAKER_STEREO; - return; - } - - if (ca_layout->mNumberChannelDescriptions <= 4 && - (ca_mask & ~KSAUDIO_SPEAKER_QUAD) == 0) - { - fmt->Format.nChannels = 4; - fmt->dwChannelMask = KSAUDIO_SPEAKER_QUAD; - return; - } - - if (ca_layout->mNumberChannelDescriptions <= 4 && - (ca_mask & ~KSAUDIO_SPEAKER_SURROUND) == 0) - { - fmt->Format.nChannels = 4; - fmt->dwChannelMask = KSAUDIO_SPEAKER_SURROUND; - return; - } - - if (ca_layout->mNumberChannelDescriptions <= 6 && - (ca_mask & ~KSAUDIO_SPEAKER_5POINT1) == 0) - { - fmt->Format.nChannels = 6; - fmt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; - return; - } - - if (ca_layout->mNumberChannelDescriptions <= 6 && - (ca_mask & ~KSAUDIO_SPEAKER_5POINT1_SURROUND) == 0) - { - fmt->Format.nChannels = 6; - fmt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND; - return; - } - - if (ca_layout->mNumberChannelDescriptions <= 8 && - (ca_mask & ~KSAUDIO_SPEAKER_7POINT1) == 0) - { - fmt->Format.nChannels = 8; - fmt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; - return; - } - - if (ca_layout->mNumberChannelDescriptions <= 8 && - (ca_mask & ~KSAUDIO_SPEAKER_7POINT1_SURROUND) == 0) - { - fmt->Format.nChannels = 8; - fmt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND; - return; - } - - /* oddball format, report truthfully */ - fmt->Format.nChannels = ca_layout->mNumberChannelDescriptions; - fmt->dwChannelMask = ca_mask; -} - -static DWORD get_channel_mask(unsigned int channels) -{ - switch(channels){ - case 0: - return 0; - case 1: - return KSAUDIO_SPEAKER_MONO; - case 2: - return KSAUDIO_SPEAKER_STEREO; - case 3: - return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY; - case 4: - return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */ - case 5: - return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY; - case 6: - return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */ - case 7: - return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER; - case 8: - return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */ - } - FIXME("Unknown speaker configuration: %u\n", channels); - return 0; -} - -static NTSTATUS unix_get_mix_format(void *args) -{ - struct get_mix_format_params *params = args; - AudioObjectPropertyAddress addr; - AudioChannelLayout *layout; - AudioBufferList *buffers; - Float64 rate; - UInt32 size; - OSStatus sc; - int i; - const AudioDeviceID dev_id = dev_id_from_device(params->device); - - params->fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - - addr.mScope = get_scope(params->flow); - addr.mElement = 0; - addr.mSelector = kAudioDevicePropertyPreferredChannelLayout; - - sc = AudioObjectGetPropertyDataSize(dev_id, &addr, 0, NULL, &size); - if(sc == noErr){ - layout = malloc(size); - sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, layout); - if(sc == noErr){ - TRACE("Got channel layout: {tag: 0x%x, bitmap: 0x%x, num_descs: %u}\n", - (unsigned int)layout->mChannelLayoutTag, (unsigned int)layout->mChannelBitmap, - (unsigned int)layout->mNumberChannelDescriptions); - - if(layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions){ - convert_channel_layout(layout, params->fmt); - }else{ - WARN("Haven't implemented support for this layout tag: 0x%x, guessing at layout\n", - (unsigned int)layout->mChannelLayoutTag); - params->fmt->Format.nChannels = 0; - } - }else{ - TRACE("Unable to get _PreferredChannelLayout property: %x, guessing at layout\n", (int)sc); - params->fmt->Format.nChannels = 0; - } - - free(layout); - }else{ - TRACE("Unable to get size for _PreferredChannelLayout property: %x, guessing at layout\n", (int)sc); - params->fmt->Format.nChannels = 0; - } - - if(params->fmt->Format.nChannels == 0){ - addr.mScope = get_scope(params->flow); - addr.mElement = 0; - addr.mSelector = kAudioDevicePropertyStreamConfiguration; - - sc = AudioObjectGetPropertyDataSize(dev_id, &addr, 0, NULL, &size); - if(sc != noErr){ - WARN("Unable to get size for _StreamConfiguration property: %x\n", (int)sc); - params->result = osstatus_to_hresult(sc); - return STATUS_SUCCESS; - } - - buffers = malloc(size); - if(!buffers){ - params->result = E_OUTOFMEMORY; - return STATUS_SUCCESS; - } - - sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, buffers); - if(sc != noErr){ - free(buffers); - WARN("Unable to get _StreamConfiguration property: %x\n", (int)sc); - params->result = osstatus_to_hresult(sc); - return STATUS_SUCCESS; - } - - for(i = 0; i < buffers->mNumberBuffers; ++i) - params->fmt->Format.nChannels += buffers->mBuffers[i].mNumberChannels; - - free(buffers); - - params->fmt->dwChannelMask = get_channel_mask(params->fmt->Format.nChannels); - } - - addr.mSelector = kAudioDevicePropertyNominalSampleRate; - size = sizeof(Float64); - sc = AudioObjectGetPropertyData(dev_id, &addr, 0, NULL, &size, &rate); - if(sc != noErr){ - WARN("Unable to get _NominalSampleRate property: %x\n", (int)sc); - params->result = osstatus_to_hresult(sc); - return STATUS_SUCCESS; - } - params->fmt->Format.nSamplesPerSec = rate; - - params->fmt->Format.wBitsPerSample = 32; - params->fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - - params->fmt->Format.nBlockAlign = (params->fmt->Format.wBitsPerSample * - params->fmt->Format.nChannels) / 8; - params->fmt->Format.nAvgBytesPerSec = params->fmt->Format.nSamplesPerSec * - params->fmt->Format.nBlockAlign; - - params->fmt->Samples.wValidBitsPerSample = params->fmt->Format.wBitsPerSample; - params->fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - params->result = S_OK; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_is_format_supported(void *args) -{ - struct is_format_supported_params *params = args; - const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)params->fmt_in; - AudioStreamBasicDescription dev_desc; - AudioConverterRef converter; - AudioComponentInstance unit; - const AudioDeviceID dev_id = dev_id_from_device(params->device); - - params->result = S_OK; - - if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out)) - params->result = E_POINTER; - else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE) - params->result = E_INVALIDARG; - else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - if(params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) - params->result = E_INVALIDARG; - else if(params->fmt_in->nAvgBytesPerSec == 0 || params->fmt_in->nBlockAlign == 0 || - fmtex->Samples.wValidBitsPerSample > params->fmt_in->wBitsPerSample) - params->result = E_INVALIDARG; - else if(fmtex->Samples.wValidBitsPerSample < params->fmt_in->wBitsPerSample) - goto unsupported; - else if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE && - (fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED)) - goto unsupported; - } - if(FAILED(params->result)) return STATUS_SUCCESS; - - if(params->fmt_in->nBlockAlign != params->fmt_in->nChannels * params->fmt_in->wBitsPerSample / 8 || - params->fmt_in->nAvgBytesPerSec != params->fmt_in->nBlockAlign * params->fmt_in->nSamplesPerSec) - goto unsupported; - - if(params->fmt_in->nChannels == 0){ - params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - return STATUS_SUCCESS; - } - unit = get_audiounit(params->flow, dev_id); - - converter = NULL; - params->result = ca_setup_audiounit(params->flow, unit, params->fmt_in, &dev_desc, &converter); - AudioComponentInstanceDispose(unit); - if(FAILED(params->result)) goto unsupported; - if(converter) AudioConverterDispose(converter); - - params->result = S_OK; - return STATUS_SUCCESS; - -unsupported: - if(params->fmt_out){ - struct get_mix_format_params get_mix_params = - { - .device = params->device, - .flow = params->flow, - .fmt = params->fmt_out, - }; - - unix_get_mix_format(&get_mix_params); - params->result = get_mix_params.result; - if(SUCCEEDED(params->result)) params->result = S_FALSE; - } - else params->result = AUDCLNT_E_UNSUPPORTED_FORMAT; - return STATUS_SUCCESS; -} - -static UINT buf_ptr_diff(UINT left, UINT right, UINT bufsize) -{ - if(left <= right) - return right - left; - return bufsize - (left - right); -} - -/* place data from cap_buffer into provided AudioBufferList */ -static OSStatus feed_cb(AudioConverterRef converter, UInt32 *nframes, AudioBufferList *data, - AudioStreamPacketDescription **packets, void *user) -{ - struct coreaudio_stream *stream = user; - - *nframes = min(*nframes, stream->cap_held_frames); - if(!*nframes){ - data->mBuffers[0].mData = NULL; - data->mBuffers[0].mDataByteSize = 0; - data->mBuffers[0].mNumberChannels = stream->fmt->nChannels; - return noErr; - } - - data->mBuffers[0].mDataByteSize = *nframes * stream->fmt->nBlockAlign; - data->mBuffers[0].mNumberChannels = stream->fmt->nChannels; - - if(stream->cap_offs_frames + *nframes > stream->cap_bufsize_frames){ - UINT32 chunk_frames = stream->cap_bufsize_frames - stream->cap_offs_frames; - - if(stream->wrap_bufsize_frames < *nframes){ - free(stream->wrap_buffer); - stream->wrap_buffer = malloc(data->mBuffers[0].mDataByteSize); - stream->wrap_bufsize_frames = *nframes; - } - - memcpy(stream->wrap_buffer, stream->cap_buffer + stream->cap_offs_frames * stream->fmt->nBlockAlign, - chunk_frames * stream->fmt->nBlockAlign); - memcpy(stream->wrap_buffer + chunk_frames * stream->fmt->nBlockAlign, stream->cap_buffer, - (*nframes - chunk_frames) * stream->fmt->nBlockAlign); - - data->mBuffers[0].mData = stream->wrap_buffer; - }else - data->mBuffers[0].mData = stream->cap_buffer + stream->cap_offs_frames * stream->fmt->nBlockAlign; - - stream->cap_offs_frames += *nframes; - stream->cap_offs_frames %= stream->cap_bufsize_frames; - stream->cap_held_frames -= *nframes; - - if(packets) - *packets = NULL; - - return noErr; -} - -static void capture_resample(struct coreaudio_stream *stream) -{ - UINT32 resamp_period_frames = muldiv(stream->period_frames, stream->dev_desc.mSampleRate, - stream->fmt->nSamplesPerSec); - OSStatus sc; - - /* the resampling process often needs more source frames than we'd - * guess from a straight conversion using the sample rate ratio. so - * only convert if we have extra source data. */ - while(stream->cap_held_frames > resamp_period_frames * 2){ - AudioBufferList converted_list; - UInt32 wanted_frames = stream->period_frames; - - converted_list.mNumberBuffers = 1; - converted_list.mBuffers[0].mNumberChannels = stream->fmt->nChannels; - converted_list.mBuffers[0].mDataByteSize = wanted_frames * stream->fmt->nBlockAlign; - - if(stream->resamp_bufsize_frames < wanted_frames){ - free(stream->resamp_buffer); - stream->resamp_buffer = malloc(converted_list.mBuffers[0].mDataByteSize); - stream->resamp_bufsize_frames = wanted_frames; - } - - converted_list.mBuffers[0].mData = stream->resamp_buffer; - - sc = AudioConverterFillComplexBuffer(stream->converter, feed_cb, - stream, &wanted_frames, &converted_list, NULL); - if(sc != noErr){ - WARN("AudioConverterFillComplexBuffer failed: %x\n", (int)sc); - break; - } - - ca_wrap_buffer(stream->local_buffer, - stream->wri_offs_frames * stream->fmt->nBlockAlign, - stream->bufsize_frames * stream->fmt->nBlockAlign, - stream->resamp_buffer, wanted_frames * stream->fmt->nBlockAlign); - - stream->wri_offs_frames += wanted_frames; - stream->wri_offs_frames %= stream->bufsize_frames; - if(stream->held_frames + wanted_frames > stream->bufsize_frames){ - stream->lcl_offs_frames += buf_ptr_diff(stream->lcl_offs_frames, stream->wri_offs_frames, - stream->bufsize_frames); - stream->held_frames = stream->bufsize_frames; - }else - stream->held_frames += wanted_frames; - } -} - -static NTSTATUS unix_get_buffer_size(void *args) -{ - struct get_buffer_size_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - OSSpinLockLock(&stream->lock); - *params->frames = stream->bufsize_frames; - OSSpinLockUnlock(&stream->lock); - params->result = S_OK; - return STATUS_SUCCESS; -} - -static HRESULT ca_get_max_stream_latency(struct coreaudio_stream *stream, UInt32 *max) -{ - AudioObjectPropertyAddress addr; - AudioStreamID *ids; - UInt32 size; - OSStatus sc; - int nstreams, i; - - addr.mScope = get_scope(stream->flow); - addr.mElement = 0; - addr.mSelector = kAudioDevicePropertyStreams; - - sc = AudioObjectGetPropertyDataSize(stream->dev_id, &addr, 0, NULL, &size); - if(sc != noErr){ - WARN("Unable to get size for _Streams property: %x\n", (int)sc); - return osstatus_to_hresult(sc); - } - - ids = malloc(size); - if(!ids) - return E_OUTOFMEMORY; - - sc = AudioObjectGetPropertyData(stream->dev_id, &addr, 0, NULL, &size, ids); - if(sc != noErr){ - WARN("Unable to get _Streams property: %x\n", (int)sc); - free(ids); - return osstatus_to_hresult(sc); - } - - nstreams = size / sizeof(AudioStreamID); - *max = 0; - - addr.mSelector = kAudioStreamPropertyLatency; - for(i = 0; i < nstreams; ++i){ - UInt32 latency; - - size = sizeof(latency); - sc = AudioObjectGetPropertyData(ids[i], &addr, 0, NULL, &size, &latency); - if(sc != noErr){ - WARN("Unable to get _Latency property: %x\n", (int)sc); - continue; - } - - if(latency > *max) - *max = latency; - } - - free(ids); - - return S_OK; -} - -static NTSTATUS unix_get_latency(void *args) -{ - struct get_latency_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - UInt32 latency, stream_latency, size; - AudioObjectPropertyAddress addr; - OSStatus sc; - - OSSpinLockLock(&stream->lock); - - addr.mScope = get_scope(stream->flow); - addr.mSelector = kAudioDevicePropertyLatency; - addr.mElement = 0; - - size = sizeof(latency); - sc = AudioObjectGetPropertyData(stream->dev_id, &addr, 0, NULL, &size, &latency); - if(sc != noErr){ - WARN("Couldn't get _Latency property: %x\n", (int)sc); - OSSpinLockUnlock(&stream->lock); - params->result = osstatus_to_hresult(sc); - return STATUS_SUCCESS; - } - - params->result = ca_get_max_stream_latency(stream, &stream_latency); - if(FAILED(params->result)){ - OSSpinLockUnlock(&stream->lock); - return STATUS_SUCCESS; - } - - latency += stream_latency; - /* pretend we process audio in Period chunks, so max latency includes - * the period time */ - *params->latency = muldiv(latency, 10000000, stream->fmt->nSamplesPerSec) - + stream->period_ms * 10000; - - OSSpinLockUnlock(&stream->lock); - params->result = S_OK; - return STATUS_SUCCESS; -} - -static UINT32 get_current_padding_nolock(struct coreaudio_stream *stream) -{ - if(stream->flow == eCapture) capture_resample(stream); - return stream->held_frames; -} - -static NTSTATUS unix_get_current_padding(void *args) -{ - struct get_current_padding_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - OSSpinLockLock(&stream->lock); - *params->padding = get_current_padding_nolock(stream); - OSSpinLockUnlock(&stream->lock); - params->result = S_OK; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_start(void *args) -{ - struct start_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - OSSpinLockLock(&stream->lock); - - if(stream->playing) - params->result = AUDCLNT_E_NOT_STOPPED; - else{ - stream->playing = TRUE; - params->result = S_OK; - } - - OSSpinLockUnlock(&stream->lock); - - return STATUS_SUCCESS; -} - -static NTSTATUS unix_stop(void *args) -{ - struct stop_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - OSSpinLockLock(&stream->lock); - - if(!stream->playing) - params->result = S_FALSE; - else{ - stream->playing = FALSE; - params->result = S_OK; - } - - OSSpinLockUnlock(&stream->lock); - - return STATUS_SUCCESS; -} - -static NTSTATUS unix_reset(void *args) -{ - struct reset_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - OSSpinLockLock(&stream->lock); - - if(stream->playing) - params->result = AUDCLNT_E_NOT_STOPPED; - else if(stream->getbuf_last) - params->result = AUDCLNT_E_BUFFER_OPERATION_PENDING; - else{ - if(stream->flow == eRender) - stream->written_frames = 0; - else - stream->written_frames += stream->held_frames; - stream->held_frames = 0; - stream->lcl_offs_frames = 0; - stream->wri_offs_frames = 0; - stream->cap_offs_frames = 0; - stream->cap_held_frames = 0; - params->result = S_OK; - } - - OSSpinLockUnlock(&stream->lock); - return STATUS_SUCCESS; -} - -static NTSTATUS unix_get_render_buffer(void *args) -{ - struct get_render_buffer_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - SIZE_T size; - UINT32 pad; - - OSSpinLockLock(&stream->lock); - - pad = get_current_padding_nolock(stream); - - if(stream->getbuf_last){ - params->result = AUDCLNT_E_OUT_OF_ORDER; - goto end; - } - if(!params->frames){ - params->result = S_OK; - goto end; - } - if(pad + params->frames > stream->bufsize_frames){ - params->result = AUDCLNT_E_BUFFER_TOO_LARGE; - goto end; - } - - if(stream->wri_offs_frames + params->frames > stream->bufsize_frames){ - if(stream->tmp_buffer_frames < params->frames){ - if(stream->tmp_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, - &size, MEM_RELEASE); - stream->tmp_buffer = NULL; - } - size = params->frames * stream->fmt->nBlockAlign; - if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(), - &size, MEM_COMMIT, PAGE_READWRITE)){ - stream->tmp_buffer_frames = 0; - params->result = E_OUTOFMEMORY; - goto end; - } - stream->tmp_buffer_frames = params->frames; - } - *params->data = stream->tmp_buffer; - stream->getbuf_last = -params->frames; - }else{ - *params->data = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign; - stream->getbuf_last = params->frames; - } - - silence_buffer(stream, *params->data, params->frames); - params->result = S_OK; - -end: - OSSpinLockUnlock(&stream->lock); - - return STATUS_SUCCESS; -} - -static NTSTATUS unix_release_render_buffer(void *args) -{ - struct release_render_buffer_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - BYTE *buffer; - - OSSpinLockLock(&stream->lock); - - if(!params->written_frames){ - stream->getbuf_last = 0; - params->result = S_OK; - }else if(!stream->getbuf_last) - params->result = AUDCLNT_E_OUT_OF_ORDER; - else if(params->written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last)) - params->result = AUDCLNT_E_INVALID_SIZE; - else{ - if(stream->getbuf_last >= 0) - buffer = stream->local_buffer + stream->wri_offs_frames * stream->fmt->nBlockAlign; - else - buffer = stream->tmp_buffer; - - if(params->flags & AUDCLNT_BUFFERFLAGS_SILENT) - silence_buffer(stream, buffer, params->written_frames); - - if(stream->getbuf_last < 0) - ca_wrap_buffer(stream->local_buffer, - stream->wri_offs_frames * stream->fmt->nBlockAlign, - stream->bufsize_frames * stream->fmt->nBlockAlign, - buffer, params->written_frames * stream->fmt->nBlockAlign); - - stream->wri_offs_frames += params->written_frames; - stream->wri_offs_frames %= stream->bufsize_frames; - stream->held_frames += params->written_frames; - stream->written_frames += params->written_frames; - stream->getbuf_last = 0; - - params->result = S_OK; - } - - OSSpinLockUnlock(&stream->lock); - - return STATUS_SUCCESS; -} - -static NTSTATUS unix_get_capture_buffer(void *args) -{ - struct get_capture_buffer_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - UINT32 chunk_bytes, chunk_frames; - LARGE_INTEGER stamp, freq; - SIZE_T size; - - OSSpinLockLock(&stream->lock); - - if(stream->getbuf_last){ - params->result = AUDCLNT_E_OUT_OF_ORDER; - goto end; - } - - capture_resample(stream); - - *params->frames = 0; - - if(stream->held_frames < stream->period_frames){ - params->result = AUDCLNT_S_BUFFER_EMPTY; - goto end; - } - - *params->flags = 0; - chunk_frames = stream->bufsize_frames - stream->lcl_offs_frames; - if(chunk_frames < stream->period_frames){ - chunk_bytes = chunk_frames * stream->fmt->nBlockAlign; - if(!stream->tmp_buffer){ - size = stream->period_frames * stream->fmt->nBlockAlign; - NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(), - &size, MEM_COMMIT, PAGE_READWRITE); - } - *params->data = stream->tmp_buffer; - memcpy(*params->data, stream->local_buffer + stream->lcl_offs_frames * stream->fmt->nBlockAlign, - chunk_bytes); - memcpy(*params->data + chunk_bytes, stream->local_buffer, - stream->period_frames * stream->fmt->nBlockAlign - chunk_bytes); - }else - *params->data = stream->local_buffer + stream->lcl_offs_frames * stream->fmt->nBlockAlign; - - stream->getbuf_last = *params->frames = stream->period_frames; - - if(params->devpos) - *params->devpos = stream->written_frames; - if(params->qpcpos){ /* fixme: qpc of recording time */ - NtQueryPerformanceCounter(&stamp, &freq); - *params->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart; - } - params->result = S_OK; - -end: - OSSpinLockUnlock(&stream->lock); - return STATUS_SUCCESS; -} - -static NTSTATUS unix_release_capture_buffer(void *args) -{ - struct release_capture_buffer_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - OSSpinLockLock(&stream->lock); - - if(!params->done){ - stream->getbuf_last = 0; - params->result = S_OK; - }else if(!stream->getbuf_last) - params->result = AUDCLNT_E_OUT_OF_ORDER; - else if(stream->getbuf_last != params->done) - params->result = AUDCLNT_E_INVALID_SIZE; - else{ - stream->written_frames += params->done; - stream->held_frames -= params->done; - stream->lcl_offs_frames += params->done; - stream->lcl_offs_frames %= stream->bufsize_frames; - stream->getbuf_last = 0; - params->result = S_OK; - } - - OSSpinLockUnlock(&stream->lock); - - return STATUS_SUCCESS; -} - -static NTSTATUS unix_get_next_packet_size(void *args) -{ - struct get_next_packet_size_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - OSSpinLockLock(&stream->lock); - - capture_resample(stream); - - if(stream->held_frames >= stream->period_frames) - *params->frames = stream->period_frames; - else - *params->frames = 0; - - OSSpinLockUnlock(&stream->lock); - - params->result = S_OK; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_get_position(void *args) -{ - struct get_position_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - LARGE_INTEGER stamp, freq; - - OSSpinLockLock(&stream->lock); - - *params->pos = stream->written_frames - stream->held_frames; - - if(stream->share == AUDCLNT_SHAREMODE_SHARED) - *params->pos *= stream->fmt->nBlockAlign; - - if(params->qpctime){ - NtQueryPerformanceCounter(&stamp, &freq); - *params->qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart; - } - - OSSpinLockUnlock(&stream->lock); - - params->result = S_OK; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_get_frequency(void *args) -{ - struct get_frequency_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - if(stream->share == AUDCLNT_SHAREMODE_SHARED) - *params->freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign; - else - *params->freq = stream->fmt->nSamplesPerSec; - - params->result = S_OK; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_is_started(void *args) -{ - struct is_started_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - - if(stream->playing) - params->result = S_OK; - else - params->result = S_FALSE; - - return STATUS_SUCCESS; -} - -static NTSTATUS unix_set_volumes(void *args) -{ - struct set_volumes_params *params = args; - struct coreaudio_stream *stream = handle_get_stream(params->stream); - Float32 level = 1.0, tmp; - OSStatus sc; - UINT32 i; - - if(params->channel >= stream->fmt->nChannels || params->channel < -1){ - ERR("Incorrect channel %d\n", params->channel); - return STATUS_SUCCESS; - } - - if(params->channel == -1){ - for(i = 0; i < stream->fmt->nChannels; ++i){ - tmp = params->master_volume * params->volumes[i] * params->session_volumes[i]; - level = tmp < level ? tmp : level; - } - }else - level = params->master_volume * params->volumes[params->channel] * - params->session_volumes[params->channel]; - - sc = AudioUnitSetParameter(stream->unit, kHALOutputParam_Volume, - kAudioUnitScope_Global, 0, level, 0); - if(sc != noErr) - WARN("Couldn't set volume: %x\n", (int)sc); - - return STATUS_SUCCESS; -} - -unixlib_entry_t __wine_unix_call_funcs[] = -{ - NULL, - NULL, - NULL, - unix_get_endpoint_ids, - unix_create_stream, - unix_release_stream, - unix_start, - unix_stop, - unix_reset, - NULL, - unix_get_render_buffer, - unix_release_render_buffer, - unix_get_capture_buffer, - unix_release_capture_buffer, - unix_is_format_supported, - unix_get_mix_format, - NULL, - unix_get_buffer_size, - unix_get_latency, - unix_get_current_padding, - unix_get_next_packet_size, - unix_get_frequency, - unix_get_position, - unix_set_volumes, - NULL, - NULL, - unix_is_started, - NULL, - unix_midi_init, - unix_midi_release, - unix_midi_out_message, - unix_midi_in_message, - unix_midi_notify_wait, - NULL, -}; - -#ifdef _WIN64 - -typedef UINT PTR32; - -static NTSTATUS unix_wow64_get_endpoint_ids(void *args) -{ - struct - { - EDataFlow flow; - PTR32 endpoints; - unsigned int size; - HRESULT result; - unsigned int num; - unsigned int default_idx; - } *params32 = args; - struct get_endpoint_ids_params params = - { - .flow = params32->flow, - .endpoints = ULongToPtr(params32->endpoints), - .size = params32->size - }; - unix_get_endpoint_ids(¶ms); - params32->size = params.size; - params32->result = params.result; - params32->num = params.num; - params32->default_idx = params.default_idx; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_create_stream(void *args) -{ - struct - { - PTR32 name; - PTR32 device; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - DWORD flags; - REFERENCE_TIME duration; - REFERENCE_TIME period; - PTR32 fmt; - HRESULT result; - PTR32 channel_count; - PTR32 stream; - } *params32 = args; - struct create_stream_params params = - { - .name = ULongToPtr(params32->name), - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .share = params32->share, - .flags = params32->flags, - .duration = params32->duration, - .period = params32->period, - .fmt = ULongToPtr(params32->fmt), - .channel_count = ULongToPtr(params32->channel_count), - .stream = ULongToPtr(params32->stream) - }; - unix_create_stream(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_release_stream(void *args) -{ - struct - { - stream_handle stream; - PTR32 timer_thread; - HRESULT result; - } *params32 = args; - struct release_stream_params params = - { - .stream = params32->stream, - .timer_thread = ULongToHandle(params32->timer_thread) - }; - unix_release_stream(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_render_buffer(void *args) -{ - struct - { - stream_handle stream; - UINT32 frames; - HRESULT result; - PTR32 data; - } *params32 = args; - BYTE *data = NULL; - struct get_render_buffer_params params = - { - .stream = params32->stream, - .frames = params32->frames, - .data = &data - }; - unix_get_render_buffer(¶ms); - params32->result = params.result; - *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data); - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_capture_buffer(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 data; - PTR32 frames; - PTR32 flags; - PTR32 devpos; - PTR32 qpcpos; - } *params32 = args; - BYTE *data = NULL; - struct get_capture_buffer_params params = - { - .stream = params32->stream, - .data = &data, - .frames = ULongToPtr(params32->frames), - .flags = ULongToPtr(params32->flags), - .devpos = ULongToPtr(params32->devpos), - .qpcpos = ULongToPtr(params32->qpcpos) - }; - unix_get_capture_buffer(¶ms); - params32->result = params.result; - *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data); - return STATUS_SUCCESS; -}; - -static NTSTATUS unix_wow64_is_format_supported(void *args) -{ - struct - { - PTR32 device; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - PTR32 fmt_in; - PTR32 fmt_out; - HRESULT result; - } *params32 = args; - struct is_format_supported_params params = - { - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .share = params32->share, - .fmt_in = ULongToPtr(params32->fmt_in), - .fmt_out = ULongToPtr(params32->fmt_out) - }; - unix_is_format_supported(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_mix_format(void *args) -{ - struct - { - PTR32 device; - EDataFlow flow; - PTR32 fmt; - HRESULT result; - } *params32 = args; - struct get_mix_format_params params = - { - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .fmt = ULongToPtr(params32->fmt) - }; - unix_get_mix_format(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_buffer_size(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 frames; - } *params32 = args; - struct get_buffer_size_params params = - { - .stream = params32->stream, - .frames = ULongToPtr(params32->frames) - }; - unix_get_buffer_size(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_latency(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 latency; - } *params32 = args; - struct get_latency_params params = - { - .stream = params32->stream, - .latency = ULongToPtr(params32->latency) - }; - unix_get_latency(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_current_padding(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 padding; - } *params32 = args; - struct get_current_padding_params params = - { - .stream = params32->stream, - .padding = ULongToPtr(params32->padding) - }; - unix_get_current_padding(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_next_packet_size(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 frames; - } *params32 = args; - struct get_next_packet_size_params params = - { - .stream = params32->stream, - .frames = ULongToPtr(params32->frames) - }; - unix_get_next_packet_size(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_position(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 pos; - PTR32 qpctime; - } *params32 = args; - struct get_position_params params = - { - .stream = params32->stream, - .pos = ULongToPtr(params32->pos), - .qpctime = ULongToPtr(params32->qpctime) - }; - unix_get_position(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_get_frequency(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 freq; - } *params32 = args; - struct get_frequency_params params = - { - .stream = params32->stream, - .freq = ULongToPtr(params32->freq) - }; - unix_get_frequency(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS unix_wow64_set_volumes(void *args) -{ - struct - { - stream_handle stream; - float master_volume; - PTR32 volumes; - PTR32 session_volumes; - int channel; - } *params32 = args; - struct set_volumes_params params = - { - .stream = params32->stream, - .master_volume = params32->master_volume, - .volumes = ULongToPtr(params32->volumes), - .session_volumes = ULongToPtr(params32->session_volumes), - .channel = params32->channel - }; - return unix_set_volumes(¶ms); -} - -unixlib_entry_t __wine_unix_call_wow64_funcs[] = -{ - NULL, - NULL, - NULL, - unix_wow64_get_endpoint_ids, - unix_wow64_create_stream, - unix_wow64_release_stream, - unix_start, - unix_stop, - unix_reset, - NULL, - unix_wow64_get_render_buffer, - unix_release_render_buffer, - unix_wow64_get_capture_buffer, - unix_release_capture_buffer, - unix_wow64_is_format_supported, - unix_wow64_get_mix_format, - NULL, - unix_wow64_get_buffer_size, - unix_wow64_get_latency, - unix_wow64_get_current_padding, - unix_wow64_get_next_packet_size, - unix_wow64_get_frequency, - unix_wow64_get_position, - unix_wow64_set_volumes, - NULL, - NULL, - unix_is_started, - NULL, - unix_wow64_midi_init, - unix_midi_release, - unix_wow64_midi_out_message, - unix_wow64_midi_in_message, - unix_wow64_midi_notify_wait, - NULL, -}; - -#endif /* _WIN64 */ diff --git a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coreaudio.h b/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coreaudio.h deleted file mode 100644 index e04043c..0000000 --- a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coreaudio.h +++ /dev/null @@ -1,36 +0,0 @@ -/* Definition for CoreAudio drivers : wine multimedia system - * - * Copyright 2005-2007 Emmanuel Maillard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef __WINE_COREAUDIO_H -#define __WINE_COREAUDIO_H - -#include "wine/debug.h" - -/* fourcc is in native order, where MSB is the first character. */ -static inline const char* wine_dbgstr_fourcc(INT32 fourcc) -{ - char buf[4] = { (char) (fourcc >> 24), (char) (fourcc >> 16), - (char) (fourcc >> 8), (char) fourcc }; - /* OSStatus is a signed decimal except in parts of CoreAudio */ - if ((buf[0] < 32) || (buf[1] < 32) || (buf[2] < 32) || (buf[3] < 32)) - return wine_dbg_sprintf("%d", fourcc); - return wine_dbgstr_an(buf, sizeof(buf)); -} - -#endif /* __WINE_COREAUDIO_H */ diff --git a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coremidi.c b/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coremidi.c deleted file mode 100644 index c9b377f..0000000 --- a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/coremidi.c +++ /dev/null @@ -1,1614 +0,0 @@ -/* - * MIDI driver for macOS (unixlib) - * - * Copyright 1994 Martin Ayotte - * Copyright 1998 Luiz Otavio L. Zorzella - * Copyright 1998, 1999 Eric POUECH - * Copyright 2005, 2006 Emmanuel Maillard - * Copyright 2021 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#if 0 -#pragma makedep unix -#endif - -#include "config.h" - -#define ULONG __carbon_ULONG -#define E_INVALIDARG __carbon_E_INVALIDARG -#define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY -#define E_HANDLE __carbon_E_HANDLE -#define E_ACCESSDENIED __carbon_E_ACCESSDENIED -#define E_UNEXPECTED __carbon_E_UNEXPECTED -#define E_FAIL __carbon_E_FAIL -#define E_ABORT __carbon_E_ABORT -#define E_POINTER __carbon_E_POINTER -#define E_NOINTERFACE __carbon_E_NOINTERFACE -#define E_NOTIMPL __carbon_E_NOTIMPL -#define S_FALSE __carbon_S_FALSE -#define S_OK __carbon_S_OK -#define HRESULT_FACILITY __carbon_HRESULT_FACILITY -#define IS_ERROR __carbon_IS_ERROR -#define FAILED __carbon_FAILED -#define SUCCEEDED __carbon_SUCCEEDED -#define MAKE_HRESULT __carbon_MAKE_HRESULT -#define HRESULT __carbon_HRESULT -#define STDMETHODCALLTYPE __carbon_STDMETHODCALLT -#include -#include -#include -#include -#undef ULONG -#undef E_INVALIDARG -#undef E_OUTOFMEMORY -#undef E_HANDLE -#undef E_ACCESSDENIED -#undef E_UNEXPECTED -#undef E_FAIL -#undef E_ABORT -#undef E_POINTER -#undef E_NOINTERFACE -#undef E_NOTIMPL -#undef S_FALSE -#undef S_OK -#undef HRESULT_FACILITY -#undef IS_ERROR -#undef FAILED -#undef SUCCEEDED -#undef MAKE_HRESULT -#undef HRESULT -#undef STDMETHODCALLTYPE - -#include - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "winternl.h" -#include "mmsystem.h" -#include "mmddk.h" -#include "mmdeviceapi.h" -#include "audioclient.h" -#include "wine/debug.h" -#include "wine/unixlib.h" - -#include "coreaudio.h" -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(midi); - -struct midi_dest -{ - /* graph and synth are only used for MIDI Synth */ - AUGraph graph; - AudioUnit synth; - - MIDIEndpointRef dest; - - MIDIOUTCAPSW caps; - MIDIOPENDESC midiDesc; - BYTE runningStatus; - WORD wFlags; -}; - -struct midi_src -{ - MIDIEndpointRef source; - - WORD wDevID; - int state; /* 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */ - MIDIINCAPSW caps; - MIDIOPENDESC midiDesc; - LPMIDIHDR lpQueueHdr; - WORD wFlags; - UINT startTime; -}; - -static MIDIClientRef midi_client; -static MIDIPortRef midi_out_port, midi_in_port; -static UINT num_dests, num_srcs; -static struct midi_dest *dests; -static struct midi_src *srcs; - -static pthread_mutex_t midi_in_mutex = PTHREAD_MUTEX_INITIALIZER; - -#define NOTIFY_BUFFER_SIZE 64 + 1 /* + 1 for the sentinel */ -static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t notify_cond = PTHREAD_COND_INITIALIZER; -static BOOL notify_quit; -static struct notify_context notify_buffer[NOTIFY_BUFFER_SIZE]; -static struct notify_context *notify_read, *notify_write; - -#define MAX_MIDI_SYNTHS 1 - -static void midi_in_lock(BOOL lock) -{ - if (lock) pthread_mutex_lock(&midi_in_mutex); - else pthread_mutex_unlock(&midi_in_mutex); -} - -static void set_in_notify(struct notify_context *notify, struct midi_src *src, WORD dev_id, WORD msg, - UINT_PTR param_1, UINT_PTR param_2) -{ - notify->send_notify = TRUE; - notify->dev_id = dev_id; - notify->msg = msg; - notify->param_1 = param_1; - notify->param_2 = param_2; - notify->callback = src->midiDesc.dwCallback; - notify->flags = src->wFlags; - notify->device = src->midiDesc.hMidi; - notify->instance = src->midiDesc.dwInstance; -} - -/* - * notify buffer: The notification ring buffer is implemented so that - * there is always at least one unused sentinel before the current - * read position in order to allow detection of the full vs empty - * state. - */ -static struct notify_context *notify_buffer_next(struct notify_context *notify) -{ - if (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer)) - notify = notify_buffer; - - return notify; -} - -static void notify_buffer_add(struct notify_context *notify) -{ - struct notify_context *next = notify_buffer_next(notify_write); - - if (next == notify_read) /* buffer is full - we can't issue a WARN() in a non-Win32 thread */ - notify_read = notify_buffer_next(notify_read); /* drop the oldest notification */ - *notify_write = *notify; - notify_write = next; -} - -static BOOL notify_buffer_empty(void) -{ - return notify_read == notify_write; -} - -static BOOL notify_buffer_remove(struct notify_context *notify) -{ - if (notify_buffer_empty()) return FALSE; - - *notify = *notify_read; - notify_read = notify_buffer_next(notify_read); - return TRUE; -} - -static void notify_post(struct notify_context *notify) -{ - pthread_mutex_lock(¬ify_mutex); - - if (notify) notify_buffer_add(notify); - else notify_quit = TRUE; - pthread_cond_signal(¬ify_cond); - - pthread_mutex_unlock(¬ify_mutex); -} - -/* - * CoreMIDI IO threaded callback, - * we can't call Wine debug channels, critical section or anything using NtCurrentTeb here. - */ -static uint64_t get_time_ms(void) -{ - static mach_timebase_info_data_t timebase; - - if (!timebase.denom) mach_timebase_info(&timebase); - return mach_absolute_time() / 1000000 * timebase.numer / timebase.denom; -} - -static void process_sysex_packet(struct midi_src *src, MIDIPacket *packet) -{ - unsigned int pos = 0, len = packet->length, copy_len; - UINT current_time = get_time_ms() - src->startTime; - struct notify_context notify; - - src->state |= 2; - - midi_in_lock(TRUE); - - while (len) - { - MIDIHDR *hdr = src->lpQueueHdr; - if (!hdr) break; - - copy_len = min(len, hdr->dwBufferLength - hdr->dwBytesRecorded); - memcpy(hdr->lpData + hdr->dwBytesRecorded, packet->data + pos, copy_len); - hdr->dwBytesRecorded += copy_len; - len -= copy_len; - pos += copy_len; - - if ((hdr->dwBytesRecorded == hdr->dwBufferLength) || - (*(BYTE*)(hdr->lpData + hdr->dwBytesRecorded - 1) == 0xf7)) - { /* buffer full or end of sysex message */ - src->lpQueueHdr = hdr->lpNext; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - set_in_notify(¬ify, src, src->wDevID, MIM_LONGDATA, (UINT_PTR)hdr, current_time); - notify_post(¬ify); - src->state &= ~2; - } - } - - midi_in_lock(FALSE); -} - -static void process_small_packet(struct midi_src *src, MIDIPacket *packet) -{ - UINT current_time = get_time_ms() - src->startTime, data; - struct notify_context notify; - unsigned int pos = 0; - - while (pos < packet->length) - { - data = 0; - switch (packet->data[pos] & 0xf0) - { - case 0xf0: - data = packet->data[pos]; - pos++; - break; - case 0xc0: - case 0xd0: - data = (packet->data[pos + 1] << 8) | packet->data[pos]; - pos += 2; - break; - default: - data = (packet->data[pos + 2] << 16) | (packet->data[pos + 1] << 8) | - packet->data[pos]; - pos += 3; - break; - } - set_in_notify(¬ify, src, src->wDevID, MIM_DATA, data, current_time); - notify_post(¬ify); - } -} - -static void midi_in_read_proc(const MIDIPacketList *pktlist, void *refCon, void *connRefCon) -{ - MIDIPacket *packet = (MIDIPacket *)pktlist->packet; - WORD dev_id = *(WORD *)connRefCon; - struct midi_src *src; - unsigned int i; - - if (dev_id >= num_srcs) return; - src = srcs + dev_id; - if (src->state < 1) /* input not started */ - return; - - for (i = 0; i < pktlist->numPackets; ++i) - { - if (packet->data[0] == 0xf0 || src->state & 2) - process_sysex_packet(src, packet); - else - process_small_packet(src, packet); - - packet = MIDIPacketNext(packet); - } -} - -NTSTATUS unix_midi_init(void *args) -{ - CFStringRef name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("wineMIDIClient.%d"), getpid()); - struct midi_init_params *params = args; - OSStatus sc; - UINT i; - - pthread_mutex_lock(¬ify_mutex); - notify_quit = FALSE; - notify_read = notify_write = notify_buffer; - pthread_mutex_unlock(¬ify_mutex); - - sc = MIDIClientCreate(name, NULL /* FIXME use notify proc */, NULL, &midi_client); - CFRelease(name); - if (sc) - { - ERR("can't create MIDI Client\n"); - *params->err = DRV_FAILURE; - return STATUS_SUCCESS; - } - - num_dests = MAX_MIDI_SYNTHS + MIDIGetNumberOfDestinations(); - num_srcs = MIDIGetNumberOfSources(); - - TRACE("num_dests %d num_srcs %d\n", num_dests, num_srcs); - - dests = calloc(num_dests, sizeof(*dests)); - srcs = calloc(num_srcs, sizeof(*srcs)); - - if (num_srcs > 0) - { - name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineInputPort.%u"), getpid()); - MIDIInputPortCreate(midi_client, name, midi_in_read_proc, NULL, &midi_in_port); - CFRelease(name); - } - - if (num_dests > MAX_MIDI_SYNTHS) - { - name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("WineOutputPort.%u"), getpid()); - MIDIOutputPortCreate(midi_client, name, &midi_out_port); - CFRelease(name); - } - - /* initialize sources */ - for (i = 0; i < num_srcs; i++) - { - srcs[i].wDevID = i; - srcs[i].source = MIDIGetSource(i); - - sc = MIDIObjectGetStringProperty(srcs[i].source, kMIDIPropertyName, &name); - if (!sc) - { - int len = min(CFStringGetLength(name), ARRAY_SIZE(srcs[i].caps.szPname) - 1); - CFStringGetCharacters(name, CFRangeMake(0, len), srcs[i].caps.szPname); - srcs[i].caps.szPname[len] = '\0'; - } - MIDIPortConnectSource(midi_in_port, srcs[i].source, &srcs[i].wDevID); - - srcs[i].state = 0; - /* FIXME */ - srcs[i].caps.wMid = 0x00FF; /* Manufac ID */ - srcs[i].caps.wPid = 0x0001; /* Product ID */ - srcs[i].caps.vDriverVersion = 0x0001; - srcs[i].caps.dwSupport = 0; - } - - /* initialise MIDI synths */ - for (i = 0; i < MAX_MIDI_SYNTHS; i++) - { - static const WCHAR synth_name[] = {'C','o','r','e','A','u','d','i','o',' ','M','I','D','I',' ','S','y','n','t','h',' '}; - - C_ASSERT(MAX_MIDI_SYNTHS < 10); - memcpy(dests[i].caps.szPname, synth_name, sizeof(synth_name)); - dests[i].caps.szPname[ARRAY_SIZE(synth_name)] = '1' + i; - dests[i].caps.szPname[ARRAY_SIZE(synth_name) + 1] = '\0'; - - dests[i].caps.wTechnology = MOD_SYNTH; - dests[i].caps.wChannelMask = 0xFFFF; - - dests[i].caps.wMid = 0x00FF; /* Manufac ID */ - dests[i].caps.wPid = 0x0001; /* Product ID */ - dests[i].caps.vDriverVersion = 0x0001; - dests[i].caps.dwSupport = MIDICAPS_VOLUME; - dests[i].caps.wVoices = 16; - dests[i].caps.wNotes = 16; - } - /* initialise available destinations */ - for (i = MAX_MIDI_SYNTHS; i < num_dests; i++) - { - dests[i].dest = MIDIGetDestination(i - MAX_MIDI_SYNTHS); - - sc = MIDIObjectGetStringProperty(dests[i].dest, kMIDIPropertyName, &name); - if (!sc) - { - int len = min(CFStringGetLength(name), ARRAY_SIZE(dests[i].caps.szPname) - 1); - CFStringGetCharacters(name, CFRangeMake(0, len), dests[i].caps.szPname); - dests[i].caps.szPname[len] = '\0'; - } - - dests[i].caps.wTechnology = MOD_MIDIPORT; - dests[i].caps.wChannelMask = 0xFFFF; - - dests[i].caps.wMid = 0x00FF; /* Manufac ID */ - dests[i].caps.wPid = 0x0001; - dests[i].caps.vDriverVersion = 0x0001; - dests[i].caps.dwSupport = 0; - dests[i].caps.wVoices = 0; - dests[i].caps.wNotes = 0; - } - - *params->err = DRV_SUCCESS; - return STATUS_SUCCESS; -} - -NTSTATUS unix_midi_release(void *args) -{ - /* stop the notify_wait thread */ - notify_post(NULL); - - if (midi_client) MIDIClientDispose(midi_client); /* MIDIClientDispose will close all ports */ - - free(srcs); - free(dests); - - return STATUS_SUCCESS; -} - -/* - * MIDI Synth Unit - */ -static BOOL synth_unit_create_default(AUGraph *graph, AudioUnit *synth) -{ - AudioComponentDescription desc; - AUNode synth_node; - AUNode out_node; - OSStatus sc; - - sc = NewAUGraph(graph); - if (sc != noErr) - { - ERR("NewAUGraph return %s\n", wine_dbgstr_fourcc(sc)); - return FALSE; - } - - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - - /* create synth node */ - desc.componentType = kAudioUnitType_MusicDevice; - desc.componentSubType = kAudioUnitSubType_DLSSynth; - - sc = AUGraphAddNode(*graph, &desc, &synth_node); - if (sc != noErr) - { - ERR("AUGraphAddNode cannot create synthNode : %s\n", wine_dbgstr_fourcc(sc)); - return FALSE; - } - - /* create out node */ - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_DefaultOutput; - - sc = AUGraphAddNode(*graph, &desc, &out_node); - if (sc != noErr) - { - ERR("AUGraphAddNode cannot create outNode %s\n", wine_dbgstr_fourcc(sc)); - return FALSE; - } - - sc = AUGraphOpen(*graph); - if (sc != noErr) - { - ERR("AUGraphOpen returns %s\n", wine_dbgstr_fourcc(sc)); - return FALSE; - } - - /* connecting the nodes */ - sc = AUGraphConnectNodeInput(*graph, synth_node, 0, out_node, 0); - if (sc != noErr) - { - ERR("AUGraphConnectNodeInput cannot connect synthNode to outNode : %s\n", - wine_dbgstr_fourcc(sc)); - return FALSE; - } - - /* Get the synth unit */ - sc = AUGraphNodeInfo(*graph, synth_node, 0, synth); - if (sc != noErr) - { - ERR("AUGraphNodeInfo return %s\n", wine_dbgstr_fourcc(sc)); - return FALSE; - } - - return TRUE; -} - -static BOOL synth_unit_init(AudioUnit synth, AUGraph graph) -{ - OSStatus sc; - - sc = AUGraphInitialize(graph); - if (sc != noErr) - { - ERR("AUGraphInitialize(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc)); - return FALSE; - } - - sc = AUGraphStart(graph); - if (sc != noErr) - { - ERR("AUGraphStart(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc)); - return FALSE; - } - - return TRUE; -} - -static BOOL synth_unit_close(AUGraph graph) -{ - OSStatus sc; - - sc = AUGraphStop(graph); - if (sc != noErr) - { - ERR("AUGraphStop(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc)); - return FALSE; - } - - sc = DisposeAUGraph(graph); - if (sc != noErr) - { - ERR("DisposeAUGraph(%p) returns %s\n", graph, wine_dbgstr_fourcc(sc)); - return FALSE; - } - - return TRUE; -} - -static void set_out_notify(struct notify_context *notify, struct midi_dest *dest, WORD dev_id, WORD msg, - UINT_PTR param_1, UINT_PTR param_2) -{ - notify->send_notify = TRUE; - notify->dev_id = dev_id; - notify->msg = msg; - notify->param_1 = param_1; - notify->param_2 = param_2; - notify->callback = dest->midiDesc.dwCallback; - notify->flags = dest->wFlags; - notify->device = dest->midiDesc.hMidi; - notify->instance = dest->midiDesc.dwInstance; -} - -static UINT midi_out_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, struct notify_context *notify) -{ - struct midi_dest *dest; - - TRACE("dev_id = %d desc = %p flags = %08x\n", dev_id, midi_desc, flags); - - if (!midi_desc) return MMSYSERR_INVALPARAM; - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - if (dests[dev_id].midiDesc.hMidi != 0) - { - WARN("device already open!\n"); - return MMSYSERR_ALLOCATED; - } - if ((flags & ~CALLBACK_TYPEMASK) != 0) - { - WARN("bad flags\n"); - return MMSYSERR_INVALFLAG; - } - - dest = dests + dev_id; - if (dest->caps.wTechnology == MOD_SYNTH) - { - if (!synth_unit_create_default(&dest->graph, &dest->synth)) - { - ERR("SynthUnit_CreateDefaultSynthUnit dest=%p failed\n", dest); - return MMSYSERR_ERROR; - } - if (!synth_unit_init(dest->synth, dest->graph)) - { - ERR("SynthUnit_Initialise dest=%p failed\n", dest); - return MMSYSERR_ERROR; - } - } - dest->runningStatus = 0; - dest->wFlags = HIWORD(flags & CALLBACK_TYPEMASK); - dest->midiDesc = *midi_desc; - - set_out_notify(notify, dest, dev_id, MOM_OPEN, 0, 0); - - return MMSYSERR_NOERROR; -} - -static UINT midi_out_close(WORD dev_id, struct notify_context *notify) -{ - struct midi_dest *dest; - - TRACE("dev_id = %d\n", dev_id); - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - - dest = dests + dev_id; - - if (dest->caps.wTechnology == MOD_SYNTH) - synth_unit_close(dest->graph); - dest->graph = 0; - dest->synth = 0; - - set_out_notify(notify, dest, dev_id, MOM_CLOSE, 0, 0); - - dest->midiDesc.hMidi = 0; - - return MMSYSERR_NOERROR; -} - -static void midi_send(MIDIPortRef port, MIDIEndpointRef dest, UInt8 *buffer, unsigned len) -{ - Byte packet_buf[512]; - MIDIPacketList *packet_list = (MIDIPacketList *)packet_buf; - MIDIPacket *packet = MIDIPacketListInit(packet_list); - - packet = MIDIPacketListAdd(packet_list, sizeof(packet_buf), packet, mach_absolute_time(), len, buffer); - if (packet) MIDISend(port, dest, packet_list); -} - -static UINT midi_out_data(WORD dev_id, UINT data) -{ - struct midi_dest *dest; - UInt8 bytes[3]; - OSStatus sc; - - TRACE("dev_id = %d data = %08x\n", dev_id, data); - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - dest = dests + dev_id; - - bytes[0] = data & 0xff; - if (bytes[0] & 0x80) - { - bytes[1] = (data >> 8) & 0xff; - bytes[2] = (data >> 16) & 0xff; - if (bytes[0] < 0xF0) - dest->runningStatus = bytes[0]; - else if (bytes[0] <= 0xF7) - dest->runningStatus = 0; - } - else if (dest->runningStatus) - { - bytes[0] = dest->runningStatus; - bytes[1] = data & 0xff; - bytes[2] = (data >> 8) & 0xff; - } - else - { - FIXME("ooch %x\n", data); - return MMSYSERR_NOERROR; - } - - if (dest->caps.wTechnology == MOD_SYNTH) - { - sc = MusicDeviceMIDIEvent(dest->synth, bytes[0], bytes[1], bytes[2], 0); - if (sc != noErr) - { - ERR("MusicDeviceMIDIEvent returns %s\n", wine_dbgstr_fourcc(sc)); - return MMSYSERR_ERROR; - } - } - else - { - midi_send(midi_out_port, dest->dest, bytes, sizeof(bytes)); - } - - return MMSYSERR_NOERROR; -} - -static UINT midi_out_long_data(WORD dev_id, MIDIHDR *hdr, UINT hdr_size, struct notify_context *notify) -{ - struct midi_dest *dest; - OSStatus sc; - - TRACE("dev_id = %d midi_hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size); - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - if (!hdr) - { - WARN("Invalid Parameter\n"); - return MMSYSERR_INVALPARAM; - } - if (!hdr->lpData || !(hdr->dwFlags & MHDR_PREPARED)) - return MIDIERR_UNPREPARED; - - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_DONE; - hdr->dwFlags |= MHDR_INQUEUE; - - if ((UInt8)hdr->lpData[0] != 0xf0) - /* System Exclusive */ - ERR("Add missing 0xf0 marker at the beginning of system exclusive byte stream\n"); - - if ((UInt8)hdr->lpData[hdr->dwBufferLength - 1] != 0xF7) - /* Send end of System Exclusive */ - ERR("Add missing 0xf7 marker at the end of system exclusive byte stream\n"); - - dest = dests + dev_id; - - if (dest->caps.wTechnology == MOD_SYNTH) /* FIXME */ - { - sc = MusicDeviceSysEx(dest->synth, (const UInt8 *)hdr->lpData, hdr->dwBufferLength); - if (sc != noErr) - { - ERR("MusicDeviceSysEx returns %s\n", wine_dbgstr_fourcc(sc)); - return MMSYSERR_ERROR; - } - } - else if (dest->caps.wTechnology == MOD_MIDIPORT) - midi_send(midi_out_port, dest->dest, (UInt8 *)hdr->lpData, hdr->dwBufferLength); - - dest->runningStatus = 0; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - - set_out_notify(notify, dest, dev_id, MOM_DONE, (UINT_PTR)hdr, 0); - - return MMSYSERR_NOERROR; -} - -static UINT midi_out_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("dev_id = %d midi_hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("dev_id = %d midi_hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -static UINT midi_out_get_devcaps(WORD dev_id, MIDIOUTCAPSW *caps, UINT size) -{ - TRACE("dev_id = %d caps = %p size = %d\n", dev_id, caps, size); - - if (!caps) - { - WARN("Invalid Parameter\n"); - return MMSYSERR_INVALPARAM; - } - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - memcpy(caps, &dests[dev_id].caps, min(size, sizeof(*caps))); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_get_num_devs(void) -{ - TRACE("\n"); - return num_dests; -} - -static UINT midi_out_get_volume(WORD dev_id, UINT *volume) -{ - TRACE("%d\n", dev_id); - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - if (!volume) - { - WARN("Invalid Parameter\n"); - return MMSYSERR_INVALPARAM; - } - - if (dests[dev_id].caps.wTechnology == MOD_SYNTH) - { - static int once; - float left; - - if (!once++) FIXME("independent left/right volume not implemented\n"); - AudioUnitGetParameter(dests[dev_id].synth, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, &left); - *volume = (WORD)(left * 0xffff) + ((WORD)(left * 0xffff) << 16); - return MMSYSERR_NOERROR; - } - - return MMSYSERR_NOTSUPPORTED; -} - -static UINT midi_out_set_volume(WORD dev_id, UINT volume) -{ - TRACE("dev_id = %d vol = %08x\n", dev_id, volume); - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - if (dests[dev_id].caps.wTechnology == MOD_SYNTH) - { - float left, right; - static int once; - - if (!once++) FIXME("independent left/right volume not implemented\n"); - left = LOWORD(volume) / 65535.0f; - right = HIWORD(volume) / 65535.0f; - - AudioUnitSetParameter(dests[dev_id].synth, kHALOutputParam_Volume, kAudioUnitParameterFlag_Output, 0, left, 0); - return MMSYSERR_NOERROR; - } - - return MMSYSERR_NOTSUPPORTED; -} - -static UINT midi_out_reset(WORD dev_id) -{ - unsigned chn; - - TRACE("%d\n", dev_id); - - if (dev_id >= num_dests) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - if (dests[dev_id].caps.wTechnology == MOD_SYNTH) - { - for (chn = 0; chn < 16; chn++) - { - /* turn off every note */ - MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x7B, 0, 0); - /* remove sustain on channel */ - MusicDeviceMIDIEvent(dests[dev_id].synth, 0xB0 | chn, 0x40, 0, 0); - } - } - else FIXME("MOD_MIDIPORT\n"); - - dests[dev_id].runningStatus = 0; - - /* FIXME: the LongData buffers must also be returned to the app */ - return MMSYSERR_NOERROR; -} - -static UINT midi_in_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, struct notify_context *notify) -{ - struct midi_src *src; - - TRACE("dev_id = %d desc = %p flags = %08x\n", dev_id, midi_desc, flags); - - if (!midi_desc) - { - WARN("Invalid Parameter\n"); - return MMSYSERR_INVALPARAM; - } - if (dev_id >= num_srcs) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - src = srcs + dev_id; - - if (src->midiDesc.hMidi) - { - WARN("device already open !\n"); - return MMSYSERR_ALLOCATED; - } - if (flags & MIDI_IO_STATUS) - { - FIXME("No support for MIDI_IO_STATUS in flags yet, ignoring it\n"); - flags &= ~MIDI_IO_STATUS; - } - if (flags & ~CALLBACK_TYPEMASK) - { - FIXME("Bad flags\n"); - return MMSYSERR_INVALFLAG; - } - - src->wFlags = HIWORD(flags & CALLBACK_TYPEMASK); - src->lpQueueHdr = NULL; - src->midiDesc = *midi_desc; - src->startTime = 0; - src->state = 0; - - set_in_notify(notify, src, dev_id, MIM_OPEN, 0, 0); - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_close(WORD dev_id, struct notify_context *notify) -{ - struct midi_src *src; - - TRACE("dev_id = %d\n", dev_id); - - if (dev_id >= num_srcs) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - src = srcs + dev_id; - - if (!src->midiDesc.hMidi) - { - WARN("device not opened !\n"); - return MMSYSERR_ERROR; - } - if (src->lpQueueHdr) return MIDIERR_STILLPLAYING; - - set_in_notify(notify, src, dev_id, MIM_CLOSE, 0, 0); - src->midiDesc.hMidi = 0; - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - MIDIHDR **next; - - TRACE("dev_id = %d hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size); - - if (dev_id >= num_srcs) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - if (!hdr || hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr->dwBufferLength) - { - WARN("Invalid Parameter\n"); - return MMSYSERR_INVALPARAM; - } - if (hdr->dwFlags & MHDR_INQUEUE) - { - WARN("Still playing\n"); - return MIDIERR_STILLPLAYING; - } - if (!(hdr->dwFlags & MHDR_PREPARED)) - { - WARN("Unprepared\n"); - return MIDIERR_UNPREPARED; - } - - hdr->dwFlags &= ~WHDR_DONE; - hdr->dwFlags |= MHDR_INQUEUE; - hdr->dwBytesRecorded = 0; - hdr->lpNext = NULL; - - midi_in_lock(TRUE); - - next = &srcs[dev_id].lpQueueHdr; - while (*next) next = &(*next)->lpNext; - *next = hdr; - - midi_in_lock(FALSE); - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("dev_id = %d hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = NULL; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - return MMSYSERR_NOERROR; -} - -static UINT midi_in_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("dev_id = %d hdr = %p hdr_size = %d\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -static UINT midi_in_get_devcaps(WORD dev_id, MIDIINCAPSW *caps, UINT size) -{ - TRACE("dev_id = %d caps = %p size = %d\n", dev_id, caps, size); - - if (!caps) - { - WARN("Invalid Parameter\n"); - return MMSYSERR_INVALPARAM; - } - if (dev_id >= num_srcs) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - - memcpy(caps, &srcs[dev_id].caps, min(size, sizeof(*caps))); - return MMSYSERR_NOERROR; -} - -static UINT midi_in_get_num_devs(void) -{ - TRACE("\n"); - return num_srcs; -} - -static UINT midi_in_start(WORD dev_id) -{ - TRACE("%d\n", dev_id); - - if (dev_id >= num_srcs) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - srcs[dev_id].state = 1; - srcs[dev_id].startTime = get_time_ms(); - return MMSYSERR_NOERROR; -} - -static UINT midi_in_stop(WORD dev_id) -{ - TRACE("%d\n", dev_id); - - if (dev_id >= num_srcs) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - srcs[dev_id].state = 0; - return MMSYSERR_NOERROR; -} - -static UINT midi_in_reset(WORD dev_id, struct notify_context *notify) -{ - UINT cur_time = get_time_ms(); - UINT err = MMSYSERR_NOERROR; - struct midi_src *src; - MIDIHDR *hdr; - - TRACE("%d\n", dev_id); - - if (dev_id >= num_srcs) - { - WARN("bad device ID : %d\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - src = srcs + dev_id; - - midi_in_lock(TRUE); - - if (src->lpQueueHdr) - { - hdr = src->lpQueueHdr; - src->lpQueueHdr = hdr->lpNext; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - set_in_notify(notify, src, dev_id, MIM_LONGDATA, (UINT_PTR)hdr, cur_time - src->startTime); - if (src->lpQueueHdr) err = ERROR_RETRY; /* ask the client to call again */ - } - - midi_in_lock(FALSE); - - return err; -} - -NTSTATUS unix_midi_out_message(void *args) -{ - struct midi_out_message_params *params = args; - - params->notify->send_notify = FALSE; - - switch (params->msg) - { - case DRVM_INIT: - case DRVM_EXIT: - case DRVM_ENABLE: - case DRVM_DISABLE: - *params->err = MMSYSERR_NOERROR; - break; - case MODM_OPEN: - *params->err = midi_out_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify); - break; - case MODM_CLOSE: - *params->err = midi_out_close(params->dev_id, params->notify); - break; - case MODM_DATA: - *params->err = midi_out_data(params->dev_id, params->param_1); - break; - case MODM_LONGDATA: - *params->err = midi_out_long_data(params->dev_id, (MIDIHDR *)params->param_1, params->param_2, params->notify); - break; - case MODM_PREPARE: - *params->err = midi_out_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MODM_UNPREPARE: - *params->err = midi_out_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MODM_GETDEVCAPS: - *params->err = midi_out_get_devcaps(params->dev_id, (MIDIOUTCAPSW *)params->param_1, params->param_2); - break; - case MODM_GETNUMDEVS: - *params->err = midi_out_get_num_devs(); - break; - case MODM_GETVOLUME: - *params->err = midi_out_get_volume(params->dev_id, (UINT *)params->param_1); - break; - case MODM_SETVOLUME: - *params->err = midi_out_set_volume(params->dev_id, params->param_1); - break; - case MODM_RESET: - *params->err = midi_out_reset(params->dev_id); - break; - default: - TRACE("Unsupported message\n"); - *params->err = MMSYSERR_NOTSUPPORTED; - } - - return STATUS_SUCCESS; -} - -NTSTATUS unix_midi_in_message(void *args) -{ - struct midi_in_message_params *params = args; - - params->notify->send_notify = FALSE; - - switch (params->msg) - { - case DRVM_INIT: - case DRVM_EXIT: - case DRVM_ENABLE: - case DRVM_DISABLE: - *params->err = MMSYSERR_NOERROR; - break; - case MIDM_OPEN: - *params->err = midi_in_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify); - break; - case MIDM_CLOSE: - *params->err = midi_in_close(params->dev_id, params->notify); - break; - case MIDM_ADDBUFFER: - *params->err = midi_in_add_buffer(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_PREPARE: - *params->err = midi_in_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_UNPREPARE: - *params->err = midi_in_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_GETDEVCAPS: - *params->err = midi_in_get_devcaps(params->dev_id, (MIDIINCAPSW *)params->param_1, params->param_2); - break; - case MIDM_GETNUMDEVS: - *params->err = midi_in_get_num_devs(); - break; - case MIDM_START: - *params->err = midi_in_start(params->dev_id); - break; - case MIDM_STOP: - *params->err = midi_in_stop(params->dev_id); - break; - case MIDM_RESET: - *params->err = midi_in_reset(params->dev_id, params->notify); - break; - default: - TRACE("Unsupported message\n"); - *params->err = MMSYSERR_NOTSUPPORTED; - } - - return STATUS_SUCCESS; -} - -NTSTATUS unix_midi_notify_wait(void *args) -{ - struct midi_notify_wait_params *params = args; - - pthread_mutex_lock(¬ify_mutex); - - while (!notify_quit && notify_buffer_empty()) - pthread_cond_wait(¬ify_cond, ¬ify_mutex); - - *params->quit = notify_quit; - if (!notify_quit) notify_buffer_remove(params->notify); - - pthread_mutex_unlock(¬ify_mutex); - - return STATUS_SUCCESS; -} - -#ifdef _WIN64 - -typedef UINT PTR32; - -NTSTATUS unix_wow64_midi_init(void *args) -{ - struct - { - PTR32 err; - } *params32 = args; - struct midi_init_params params = - { - .err = ULongToPtr(params32->err) - }; - return unix_midi_init(¶ms); -} - -struct notify_context32 -{ - BOOL send_notify; - WORD dev_id; - WORD msg; - UINT param_1; - UINT param_2; - UINT callback; - UINT flags; - PTR32 device; - UINT instance; -}; - -static void notify_to_notify32(struct notify_context32 *notify32, - const struct notify_context *notify) -{ - notify32->send_notify = notify->send_notify; - notify32->dev_id = notify->dev_id; - notify32->msg = notify->msg; - notify32->param_1 = notify->param_1; - notify32->param_2 = notify->param_2; - notify32->callback = notify->callback; - notify32->flags = notify->flags; - notify32->device = PtrToUlong(notify->device); - notify32->instance = notify->instance; -} - -struct midi_open_desc32 -{ - PTR32 hMidi; - UINT dwCallback; - UINT dwInstance; - UINT dnDevNode; - UINT cIds; - MIDIOPENSTRMID rgIds; -}; - -struct midi_hdr32 -{ - PTR32 lpData; - UINT dwBufferLength; - UINT dwBytesRecorded; - UINT dwUser; - UINT dwFlags; - PTR32 lpNext; - UINT reserved; - UINT dwOffset; - UINT dwReserved[8]; -}; - -static UINT wow64_midi_out_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - return MMSYSERR_NOERROR; -} - -static UINT wow64_midi_out_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -NTSTATUS unix_wow64_midi_out_message(void *args) -{ - struct - { - UINT dev_id; - UINT msg; - UINT user; - UINT param_1; - UINT param_2; - PTR32 err; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_open_desc32 *desc32; - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIOPENDESC open_desc; - MIDIHDR hdr; - struct midi_out_message_params params = - { - .dev_id = params32->dev_id, - .msg = params32->msg, - .user = params32->user, - .param_1 = params32->param_1, - .param_2 = params32->param_2, - .err = ULongToPtr(params32->err), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - switch (params32->msg) - { - case MODM_OPEN: - desc32 = ULongToPtr(params32->param_1); - - open_desc.hMidi = ULongToPtr(desc32->hMidi); - open_desc.dwCallback = desc32->dwCallback; - open_desc.dwInstance = desc32->dwInstance; - open_desc.dnDevNode = desc32->dnDevNode; - open_desc.cIds = desc32->cIds; - open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID; - open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID; - - params.param_1 = (UINT_PTR)&open_desc; - break; - - case MODM_LONGDATA: - hdr32 = ULongToPtr(params32->param_1); - - memset(&hdr, 0, sizeof(hdr)); - hdr.lpData = ULongToPtr(hdr32->lpData); - hdr.dwBufferLength = hdr32->dwBufferLength; - hdr.dwFlags = hdr32->dwFlags; - - params.param_1 = (UINT_PTR)&hdr; - params.param_2 = sizeof(hdr); - break; - - case MODM_PREPARE: /* prepare and unprepare are easier to handle explicitly */ - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_out_prepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - - case MODM_UNPREPARE: - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_out_unprepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - } - - unix_midi_out_message(¶ms); - - switch (params32->msg) - { - case MODM_LONGDATA: - hdr32 = ULongToPtr(params32->param_1); - - hdr32->dwFlags = hdr.dwFlags; - break; - } - - if (notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MOM_DONE) - notify32->param_1 = params32->param_1; /* restore the 32-bit hdr */ - } - return STATUS_SUCCESS; -} - -static UINT wow64_midi_in_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - - return MMSYSERR_NOERROR; -} - -static UINT wow64_midi_in_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - - return MMSYSERR_NOERROR; -} - -NTSTATUS unix_wow64_midi_in_message(void *args) -{ - struct - { - UINT dev_id; - UINT msg; - UINT user; - UINT param_1; - UINT param_2; - PTR32 err; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_open_desc32 *desc32; - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIOPENDESC open_desc; - MIDIHDR *hdr = NULL; - struct midi_in_message_params params = - { - .dev_id = params32->dev_id, - .msg = params32->msg, - .user = params32->user, - .param_1 = params32->param_1, - .param_2 = params32->param_2, - .err = ULongToPtr(params32->err), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - switch (params32->msg) - { - case MIDM_OPEN: - desc32 = ULongToPtr(params32->param_1); - - open_desc.hMidi = ULongToPtr(desc32->hMidi); - open_desc.dwCallback = desc32->dwCallback; - open_desc.dwInstance = desc32->dwInstance; - open_desc.dnDevNode = desc32->dnDevNode; - open_desc.cIds = desc32->cIds; - open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID; - open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID; - - params.param_1 = (UINT_PTR)&open_desc; - break; - - case MIDM_ADDBUFFER: - hdr32 = ULongToPtr(params32->param_1); - - hdr = calloc(1, sizeof(*hdr)); - hdr->lpData = ULongToPtr(hdr32->lpData); - hdr->dwBufferLength = hdr32->dwBufferLength; - hdr->dwFlags = hdr32->dwFlags; - hdr->dwReserved[7] = params32->param_1; /* keep hdr32 for MIM_LONGDATA notification */ - - params.param_1 = (UINT_PTR)hdr; - params.param_2 = sizeof(*hdr); - break; - - case MIDM_PREPARE: /* prepare and unprepare are easier to handle explicitly */ - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_in_prepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - - case MIDM_UNPREPARE: - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_in_unprepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - } - - unix_midi_in_message(¶ms); - - switch (params32->msg) - { - case MIDM_ADDBUFFER: - hdr32 = ULongToPtr(params32->param_1); - - if (!*params.err) - { - hdr32->dwFlags = hdr->dwFlags; - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->lpNext = 0; - } - else - free(hdr); - break; - } - - if (notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MIM_LONGDATA) - { - hdr = (MIDIHDR *)notify.param_1; - notify32->param_1 = hdr->dwReserved[7]; - hdr32 = ULongToPtr(notify32->param_1); - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->dwFlags = hdr->dwFlags; - free(hdr); - } - } - return STATUS_SUCCESS; -} - -NTSTATUS unix_wow64_midi_notify_wait(void *args) -{ - struct - { - PTR32 quit; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIHDR *hdr; - struct midi_notify_wait_params params = - { - .quit = ULongToPtr(params32->quit), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - unix_midi_notify_wait(¶ms); - - if (!*params.quit && notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MIM_LONGDATA) - { - hdr = (MIDIHDR *)notify.param_1; - notify32->param_1 = hdr->dwReserved[7]; - hdr32 = ULongToPtr(notify32->param_1); - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->dwFlags = hdr->dwFlags; - free(hdr); - } - } - return STATUS_SUCCESS; -} - -#endif /* _WIN64 */ diff --git a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/midi.c b/pkgs/osu-wine/audio-revert/winecoreaudio.drv/midi.c deleted file mode 100644 index 4934923..0000000 --- a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/midi.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * MIDI driver for macOS (PE-side) - * - * Copyright 1994 Martin Ayotte - * Copyright 1998 Luiz Otavio L. Zorzella - * Copyright 1998, 1999 Eric POUECH - * Copyright 2005, 2006 Emmanuel Maillard - * Copyright 2021 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "winternl.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h" -#include "mmddk.h" -#include "mmdeviceapi.h" -#include "audioclient.h" -#include "wine/debug.h" -#include "wine/unixlib.h" -#include "coreaudio.h" -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(midi); - -static void notify_client(struct notify_context *notify) -{ - TRACE("dev_id=%d msg=%d param1=%04IX param2=%04IX\n", notify->dev_id, notify->msg, notify->param_1, notify->param_2); - - DriverCallback(notify->callback, notify->flags, notify->device, notify->msg, - notify->instance, notify->param_1, notify->param_2); -} - -static DWORD WINAPI notify_thread(void *p) -{ - struct midi_notify_wait_params params; - struct notify_context notify; - BOOL quit; - - params.notify = ¬ify; - params.quit = &quit; - - while (1) - { - UNIX_CALL(midi_notify_wait, ¶ms); - if (quit) break; - if (notify.send_notify) notify_client(¬ify); - } - return 0; -} - -static LONG CoreAudio_MIDIInit(void) -{ - struct midi_init_params params; - UINT err; - - params.err = &err; - - UNIX_CALL(midi_init, ¶ms); - if (err != DRV_SUCCESS) - { - ERR("can't create midi client\n"); - return err; - } - - CloseHandle(CreateThread(NULL, 0, notify_thread, NULL, 0, NULL)); - - return err; -} - -static LONG CoreAudio_MIDIRelease(void) -{ - TRACE("\n"); - - UNIX_CALL(midi_release, NULL); - - return DRV_SUCCESS; -} - -/************************************************************************** -* modMessage -*/ -DWORD WINAPI CoreAudio_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - struct midi_out_message_params params; - struct notify_context notify; - UINT err; - - TRACE("%d %08x %08Ix %08Ix %08Ix\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); - - params.dev_id = wDevID; - params.msg = wMsg; - params.user = dwUser; - params.param_1 = dwParam1; - params.param_2 = dwParam2; - params.err = &err; - params.notify = ¬ify; - - UNIX_CALL(midi_out_message, ¶ms); - - if (!err && notify.send_notify) notify_client(¬ify); - - return err; -} - -/************************************************************************** -* midMessage -*/ -DWORD WINAPI CoreAudio_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - struct midi_in_message_params params; - struct notify_context notify; - UINT err; - - TRACE("%d %08x %08Ix %08Ix %08Ix\n", wDevID, wMsg, dwUser, dwParam1, dwParam2); - - params.dev_id = wDevID; - params.msg = wMsg; - params.user = dwUser; - params.param_1 = dwParam1; - params.param_2 = dwParam2; - params.err = &err; - params.notify = ¬ify; - - do - { - UNIX_CALL(midi_in_message, ¶ms); - if ((!err || err == ERROR_RETRY) && notify.send_notify) notify_client(¬ify); - } while (err == ERROR_RETRY); - - return err; -} - -/************************************************************************** - * CoreAudio_drvLoad [internal] - */ -static LRESULT CoreAudio_drvLoad(void) -{ - TRACE("()\n"); - - if (CoreAudio_MIDIInit() != DRV_SUCCESS) - return DRV_FAILURE; - - return DRV_SUCCESS; -} - -/************************************************************************** - * CoreAudio_drvFree [internal] - */ -static LRESULT CoreAudio_drvFree(void) -{ - TRACE("()\n"); - CoreAudio_MIDIRelease(); - return DRV_SUCCESS; -} - -/************************************************************************** - * CoreAudio_drvOpen [internal] - */ -static LRESULT CoreAudio_drvOpen(LPSTR str) -{ - TRACE("(%s)\n", str); - return 1; -} - -/************************************************************************** - * CoreAudio_drvClose [internal] - */ -static DWORD CoreAudio_drvClose(DWORD dwDevID) -{ - TRACE("(%08lx)\n", dwDevID); - return 1; -} - -/************************************************************************** - * DriverProc (WINECOREAUDIO.1) - */ -LRESULT CALLBACK CoreAudio_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, - LPARAM dwParam1, LPARAM dwParam2) -{ - TRACE("(%08IX, %p, %s (%08X), %08IX, %08IX)\n", - dwDevID, hDriv, wMsg == DRV_LOAD ? "DRV_LOAD" : - wMsg == DRV_FREE ? "DRV_FREE" : - wMsg == DRV_OPEN ? "DRV_OPEN" : - wMsg == DRV_CLOSE ? "DRV_CLOSE" : - wMsg == DRV_ENABLE ? "DRV_ENABLE" : - wMsg == DRV_DISABLE ? "DRV_DISABLE" : - wMsg == DRV_QUERYCONFIGURE ? "DRV_QUERYCONFIGURE" : - wMsg == DRV_CONFIGURE ? "DRV_CONFIGURE" : - wMsg == DRV_INSTALL ? "DRV_INSTALL" : - wMsg == DRV_REMOVE ? "DRV_REMOVE" : "UNKNOWN", - wMsg, dwParam1, dwParam2); - - switch(wMsg) { - case DRV_LOAD: return CoreAudio_drvLoad(); - case DRV_FREE: return CoreAudio_drvFree(); - case DRV_OPEN: return CoreAudio_drvOpen((LPSTR)dwParam1); - case DRV_CLOSE: return CoreAudio_drvClose(dwDevID); - case DRV_ENABLE: return 1; - case DRV_DISABLE: return 1; - case DRV_QUERYCONFIGURE: return 1; - case DRV_CONFIGURE: MessageBoxA(0, "CoreAudio driver!", "CoreAudio driver", MB_OK); return 1; - case DRV_INSTALL: return DRVCNF_RESTART; - case DRV_REMOVE: return DRVCNF_RESTART; - default: - return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); - } -} diff --git a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/mmdevdrv.c b/pkgs/osu-wine/audio-revert/winecoreaudio.drv/mmdevdrv.c deleted file mode 100644 index 367f7ba..0000000 --- a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/mmdevdrv.c +++ /dev/null @@ -1,2414 +0,0 @@ -/* - * Copyright 2011 Andrew Eikum for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#define COBJMACROS - -#include - -#include "windef.h" -#include "winbase.h" -#include "winternl.h" -#include "winnls.h" -#include "winreg.h" -#include "wine/debug.h" -#include "wine/heap.h" -#include "wine/list.h" -#include "wine/unixlib.h" - -#include "ole2.h" -#include "mmdeviceapi.h" -#include "devpkey.h" -#include "dshow.h" -#include "dsound.h" - -#include "initguid.h" -#include "endpointvolume.h" -#include "audioclient.h" -#include "audiopolicy.h" -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(coreaudio); - -#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) - -static const REFERENCE_TIME DefaultPeriod = 100000; -static const REFERENCE_TIME MinimumPeriod = 50000; - -struct ACImpl; -typedef struct ACImpl ACImpl; - -typedef struct _AudioSession { - GUID guid; - struct list clients; - - IMMDevice *device; - - float master_vol; - UINT32 channel_count; - float *channel_vols; - BOOL mute; - - struct list entry; -} AudioSession; - -typedef struct _AudioSessionWrapper { - IAudioSessionControl2 IAudioSessionControl2_iface; - IChannelAudioVolume IChannelAudioVolume_iface; - ISimpleAudioVolume ISimpleAudioVolume_iface; - - LONG ref; - - ACImpl *client; - AudioSession *session; -} AudioSessionWrapper; - -struct ACImpl { - IAudioClient3 IAudioClient3_iface; - IAudioRenderClient IAudioRenderClient_iface; - IAudioCaptureClient IAudioCaptureClient_iface; - IAudioClock IAudioClock_iface; - IAudioClock2 IAudioClock2_iface; - IAudioStreamVolume IAudioStreamVolume_iface; - - LONG ref; - - IMMDevice *parent; - IUnknown *pUnkFTMarshal; - - EDataFlow dataflow; - UINT32 channel_count, period_ms; - DWORD flags; - HANDLE event; - float *vols; - - HANDLE timer; - - AudioSession *session; - AudioSessionWrapper *session_wrapper; - - stream_handle stream; - struct list entry; - - char device_name[1]; -}; - -static const IAudioClient3Vtbl AudioClient3_Vtbl; -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl; -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl; -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl; -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl; -static const IAudioClockVtbl AudioClock_Vtbl; -static const IAudioClock2Vtbl AudioClock2_Vtbl; -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl; -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl; -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl; - -typedef struct _SessionMgr { - IAudioSessionManager2 IAudioSessionManager2_iface; - - LONG ref; - - IMMDevice *device; -} SessionMgr; - -static const WCHAR *drv_key_devicesW = L"Software\\Wine\\Drivers\\winecoreaudio.drv\\devices"; - -static HANDLE g_timer_q; - -static CRITICAL_SECTION g_sessions_lock; -static CRITICAL_SECTION_DEBUG g_sessions_lock_debug = -{ - 0, 0, &g_sessions_lock, - { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") } -}; -static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 }; -static struct list g_sessions = LIST_INIT(g_sessions); - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client); - -static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface); -} - -static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface); -} - -static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface); -} - -static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface); -} - -static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface); -} - -static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface); -} - -static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface); -} - -static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface); -} - -static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); -} - -static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface) -{ - return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface); -} - -BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) -{ - switch (reason) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(dll); - if (__wine_init_unix_call()) - return FALSE; - g_timer_q = CreateTimerQueue(); - if(!g_timer_q) - return FALSE; - break; - - case DLL_PROCESS_DETACH: - if (reserved) break; - DeleteCriticalSection(&g_sessions_lock); - CloseHandle(g_timer_q); - break; - } - return TRUE; -} - -int WINAPI AUDDRV_GetPriority(void) -{ - return Priority_Neutral; -} - -static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name, - GUID *guid) -{ - HKEY key; - BOOL opened = FALSE; - LONG lr; - - if(!drv_key){ - lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE, - NULL, &drv_key, NULL); - if(lr != ERROR_SUCCESS){ - ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr); - return; - } - opened = TRUE; - } - - lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE, - NULL, &key, NULL); - if(lr != ERROR_SUCCESS){ - ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr); - goto exit; - } - - lr = RegSetValueExW(key, L"guid", 0, REG_BINARY, (BYTE*)guid, - sizeof(GUID)); - if(lr != ERROR_SUCCESS) - ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr); - - RegCloseKey(key); -exit: - if(opened) - RegCloseKey(drv_key); -} - -static void get_device_guid(EDataFlow flow, const char *dev, GUID *guid) -{ - HKEY key = NULL, dev_key; - DWORD type, size = sizeof(*guid); - WCHAR key_name[256]; - - if(flow == eCapture) - key_name[0] = '1'; - else - key_name[0] = '0'; - key_name[1] = ','; - - MultiByteToWideChar(CP_UNIXCP, 0, dev, -1, key_name + 2, ARRAY_SIZE(key_name) - 2); - - if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){ - if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){ - if(RegQueryValueExW(dev_key, L"guid", 0, &type, - (BYTE*)guid, &size) == ERROR_SUCCESS){ - if(type == REG_BINARY){ - RegCloseKey(dev_key); - RegCloseKey(key); - return; - } - ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n", - wine_dbgstr_w(key_name), type); - } - RegCloseKey(dev_key); - } - } - - CoCreateGuid(guid); - - set_device_guid(flow, key, key_name, guid); - - if(key) - RegCloseKey(key); -} - -static void set_stream_volumes(ACImpl *This, int channel) -{ - struct set_volumes_params params; - - params.stream = This->stream; - params.master_volume = This->session->mute ? 0.0f : This->session->master_vol; - params.volumes = This->vols; - params.session_volumes = This->session->channel_vols; - params.channel = channel; - - UNIX_CALL(set_volumes, ¶ms); -} - -HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, - GUID **guids_out, UINT *num, UINT *def_index) -{ - struct get_endpoint_ids_params params; - unsigned int i; - GUID *guids = NULL; - WCHAR **ids = NULL; - - TRACE("%d %p %p %p\n", flow, ids_out, num, def_index); - - params.flow = flow; - params.size = 1000; - params.endpoints = NULL; - do{ - heap_free(params.endpoints); - params.endpoints = heap_alloc(params.size); - UNIX_CALL(get_endpoint_ids, ¶ms); - }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)); - - if(FAILED(params.result)) goto end; - - ids = heap_alloc_zero(params.num * sizeof(*ids)); - guids = heap_alloc(params.num * sizeof(*guids)); - if(!ids || !guids){ - params.result = E_OUTOFMEMORY; - goto end; - } - - for(i = 0; i < params.num; i++){ - const WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name); - const char *device = (char *)params.endpoints + params.endpoints[i].device; - const unsigned int size = (wcslen(name) + 1) * sizeof(WCHAR); - - ids[i] = heap_alloc(size); - if(!ids[i]){ - params.result = E_OUTOFMEMORY; - goto end; - } - memcpy(ids[i], name, size); - get_device_guid(flow, device, guids + i); - } - *def_index = params.default_idx; - -end: - heap_free(params.endpoints); - if(FAILED(params.result)){ - heap_free(guids); - if(ids){ - for(i = 0; i < params.num; i++) heap_free(ids[i]); - heap_free(ids); - } - }else{ - *ids_out = ids; - *guids_out = guids; - *num = params.num; - } - - return params.result; -} - -static BOOL get_device_name_by_guid(const GUID *guid, char *name, const SIZE_T name_size, EDataFlow *flow) -{ - HKEY devices_key; - UINT i = 0; - WCHAR key_name[256]; - DWORD key_name_size; - - if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_READ, &devices_key) != ERROR_SUCCESS){ - ERR("No devices in registry?\n"); - return FALSE; - } - - while(1){ - HKEY key; - DWORD size, type; - GUID reg_guid; - - key_name_size = ARRAY_SIZE(key_name); - if(RegEnumKeyExW(devices_key, i++, key_name, &key_name_size, NULL, - NULL, NULL, NULL) != ERROR_SUCCESS) - break; - - if(RegOpenKeyExW(devices_key, key_name, 0, KEY_READ, &key) != ERROR_SUCCESS){ - WARN("Couldn't open key: %s\n", wine_dbgstr_w(key_name)); - continue; - } - - size = sizeof(reg_guid); - if(RegQueryValueExW(key, L"guid", 0, &type, - (BYTE*)®_guid, &size) == ERROR_SUCCESS){ - if(IsEqualGUID(®_guid, guid)){ - RegCloseKey(key); - RegCloseKey(devices_key); - - TRACE("Found matching device key: %s\n", wine_dbgstr_w(key_name)); - - if(key_name[0] == '0') - *flow = eRender; - else if(key_name[0] == '1') - *flow = eCapture; - else{ - ERR("Unknown device type: %c\n", key_name[0]); - return FALSE; - } - - WideCharToMultiByte(CP_UNIXCP, 0, key_name + 2, -1, name, name_size, NULL, NULL); - - return TRUE; - } - } - - RegCloseKey(key); - } - - RegCloseKey(devices_key); - - WARN("No matching device in registry for GUID %s\n", debugstr_guid(guid)); - - return FALSE; -} - -HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out) -{ - ACImpl *This; - char name[256]; - SIZE_T name_len; - EDataFlow dataflow; - HRESULT hr; - - TRACE("%s %p %p\n", debugstr_guid(guid), dev, out); - - if(!get_device_name_by_guid(guid, name, sizeof(name), &dataflow)) - return AUDCLNT_E_DEVICE_INVALIDATED; - - if(dataflow != eRender && dataflow != eCapture) - return E_INVALIDARG; - - name_len = strlen(name); - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, device_name[name_len + 1])); - if(!This) - return E_OUTOFMEMORY; - - This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl; - This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl; - This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl; - This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl; - This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl; - This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl; - - This->dataflow = dataflow; - memcpy(This->device_name, name, name_len + 1); - - hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal); - if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, This); - return hr; - } - - This->parent = dev; - IMMDevice_AddRef(This->parent); - - *out = (IAudioClient *)&This->IAudioClient3_iface; - IAudioClient3_AddRef(&This->IAudioClient3_iface); - - return S_OK; -} - -static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioClient) || - IsEqualIID(riid, &IID_IAudioClient2) || - IsEqualIID(riid, &IID_IAudioClient3)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct release_stream_params params; - ULONG ref; - - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref){ - if(This->timer){ - HANDLE event; - BOOL wait; - event = CreateEventW(NULL, TRUE, FALSE, NULL); - wait = !DeleteTimerQueueTimer(g_timer_q, This->timer, event); - wait = wait && GetLastError() == ERROR_IO_PENDING; - if(event && wait) - WaitForSingleObject(event, INFINITE); - CloseHandle(event); - } - if(This->stream){ - params.stream = This->stream; - params.timer_thread = NULL; - UNIX_CALL(release_stream, ¶ms); - } - if(This->session){ - EnterCriticalSection(&g_sessions_lock); - list_remove(&This->entry); - LeaveCriticalSection(&g_sessions_lock); - } - HeapFree(GetProcessHeap(), 0, This->vols); - IMMDevice_Release(This->parent); - IUnknown_Release(This->pUnkFTMarshal); - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static void dump_fmt(const WAVEFORMATEX *fmt) -{ - TRACE("wFormatTag: 0x%x (", fmt->wFormatTag); - switch(fmt->wFormatTag){ - case WAVE_FORMAT_PCM: - TRACE("WAVE_FORMAT_PCM"); - break; - case WAVE_FORMAT_IEEE_FLOAT: - TRACE("WAVE_FORMAT_IEEE_FLOAT"); - break; - case WAVE_FORMAT_EXTENSIBLE: - TRACE("WAVE_FORMAT_EXTENSIBLE"); - break; - default: - TRACE("Unknown"); - break; - } - TRACE(")\n"); - - TRACE("nChannels: %u\n", fmt->nChannels); - TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec); - TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec); - TRACE("nBlockAlign: %u\n", fmt->nBlockAlign); - TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample); - TRACE("cbSize: %u\n", fmt->cbSize); - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt; - TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask); - TRACE("Samples: %04x\n", fmtex->Samples.wReserved); - TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat)); - } -} - -static void session_init_vols(AudioSession *session, UINT channels) -{ - if(session->channel_count < channels){ - UINT i; - - if(session->channel_vols) - session->channel_vols = HeapReAlloc(GetProcessHeap(), 0, - session->channel_vols, sizeof(float) * channels); - else - session->channel_vols = HeapAlloc(GetProcessHeap(), 0, - sizeof(float) * channels); - if(!session->channel_vols) - return; - - for(i = session->channel_count; i < channels; ++i) - session->channel_vols[i] = 1.f; - - session->channel_count = channels; - } -} - -static AudioSession *create_session(const GUID *guid, IMMDevice *device, - UINT num_channels) -{ - AudioSession *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession)); - if(!ret) - return NULL; - - memcpy(&ret->guid, guid, sizeof(GUID)); - - ret->device = device; - - list_init(&ret->clients); - - list_add_head(&g_sessions, &ret->entry); - - session_init_vols(ret, num_channels); - - ret->master_vol = 1.f; - - return ret; -} - -/* if channels == 0, then this will return or create a session with - * matching dataflow and GUID. otherwise, channels must also match */ -static HRESULT get_audio_session(const GUID *sessionguid, - IMMDevice *device, UINT channels, AudioSession **out) -{ - AudioSession *session; - - if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){ - *out = create_session(&GUID_NULL, device, channels); - if(!*out) - return E_OUTOFMEMORY; - - return S_OK; - } - - *out = NULL; - LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){ - if(session->device == device && - IsEqualGUID(sessionguid, &session->guid)){ - session_init_vols(session, channels); - *out = session; - break; - } - } - - if(!*out){ - *out = create_session(sessionguid, device, channels); - if(!*out) - return E_OUTOFMEMORY; - } - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, - AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration, - REFERENCE_TIME period, const WAVEFORMATEX *fmt, - const GUID *sessionguid) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct release_stream_params release_params; - struct create_stream_params params; - stream_handle stream; - UINT32 i; - - TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags, - wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid)); - - if(!fmt) - return E_POINTER; - - dump_fmt(fmt); - - if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) - return E_INVALIDARG; - - if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS | - AUDCLNT_STREAMFLAGS_LOOPBACK | - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | - AUDCLNT_STREAMFLAGS_NOPERSIST | - AUDCLNT_STREAMFLAGS_RATEADJUST | - AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED | - AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | - AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){ - FIXME("Unknown flags: %08lx\n", flags); - return E_INVALIDARG; - } - - if(mode == AUDCLNT_SHAREMODE_SHARED){ - period = DefaultPeriod; - if( duration < 3 * period) - duration = 3 * period; - }else{ - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - if(((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask == 0 || - ((WAVEFORMATEXTENSIBLE*)fmt)->dwChannelMask & SPEAKER_RESERVED) - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - - if(!period) - period = DefaultPeriod; /* not minimum */ - if(period < MinimumPeriod || period > 5000000) - return AUDCLNT_E_INVALID_DEVICE_PERIOD; - if(duration > 20000000) /* the smaller the period, the lower this limit */ - return AUDCLNT_E_BUFFER_SIZE_ERROR; - if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){ - if(duration != period) - return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; - FIXME("EXCLUSIVE mode with EVENTCALLBACK\n"); - return AUDCLNT_E_DEVICE_IN_USE; - }else{ - if( duration < 8 * period) - duration = 8 * period; /* may grow above 2s */ - } - } - - EnterCriticalSection(&g_sessions_lock); - - if(This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_ALREADY_INITIALIZED; - } - - params.name = NULL; - params.device = This->device_name; - params.flow = This->dataflow; - params.share = mode; - params.flags = flags; - params.duration = duration; - params.period = period; - params.fmt = fmt; - params.channel_count = NULL; - params.stream = &stream; - - UNIX_CALL(create_stream, ¶ms); - if(FAILED(params.result)){ - LeaveCriticalSection(&g_sessions_lock); - return params.result; - } - - This->flags = flags; - This->channel_count = fmt->nChannels; - This->period_ms = period / 10000; - - This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float)); - if(!This->vols){ - params.result = E_OUTOFMEMORY; - goto end; - } - - for(i = 0; i < This->channel_count; ++i) - This->vols[i] = 1.f; - - params.result = get_audio_session(sessionguid, This->parent, fmt->nChannels, &This->session); - if(FAILED(params.result)) goto end; - - list_add_tail(&This->session->clients, &This->entry); - -end: - if(FAILED(params.result)){ - release_params.stream = stream; - UNIX_CALL(release_stream, &release_params); - HeapFree(GetProcessHeap(), 0, This->vols); - This->vols = NULL; - }else{ - This->stream = stream; - set_stream_volumes(This, -1); - } - - LeaveCriticalSection(&g_sessions_lock); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface, - UINT32 *frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_buffer_size_params params; - - TRACE("(%p)->(%p)\n", This, frames); - - if(!frames) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.frames = frames; - UNIX_CALL(get_buffer_size, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface, - REFERENCE_TIME *out) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_latency_params params; - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.latency = out; - UNIX_CALL(get_latency, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface, - UINT32 *numpad) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_current_padding_params params; - - TRACE("(%p)->(%p)\n", This, numpad); - - if(!numpad) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.padding = numpad; - UNIX_CALL(get_current_padding, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface, - AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *pwfx, - WAVEFORMATEX **outpwfx) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct is_format_supported_params params; - - TRACE("(%p)->(%x, %p, %p)\n", This, mode, pwfx, outpwfx); - if(pwfx) dump_fmt(pwfx); - - params.device = This->device_name; - params.flow = This->dataflow; - params.share = mode; - params.fmt_in = pwfx; - params.fmt_out = NULL; - - if(outpwfx){ - *outpwfx = NULL; - if(mode == AUDCLNT_SHAREMODE_SHARED) - params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out)); - } - UNIX_CALL(is_format_supported, ¶ms); - - if(params.result == S_FALSE) - *outpwfx = ¶ms.fmt_out->Format; - else - CoTaskMemFree(params.fmt_out); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, - WAVEFORMATEX **pwfx) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_mix_format_params params; - - TRACE("(%p)->(%p)\n", This, pwfx); - - if(!pwfx) - return E_POINTER; - *pwfx = NULL; - - params.device = This->device_name; - params.flow = This->dataflow; - params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE)); - if(!params.fmt) - return E_OUTOFMEMORY; - - UNIX_CALL(get_mix_format, ¶ms); - - if(SUCCEEDED(params.result)){ - *pwfx = ¶ms.fmt->Format; - dump_fmt(*pwfx); - }else - CoTaskMemFree(params.fmt); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, - REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod); - - if(!defperiod && !minperiod) - return E_POINTER; - - if(defperiod) - *defperiod = DefaultPeriod; - if(minperiod) - *minperiod = MinimumPeriod; - - return S_OK; -} - -void CALLBACK ca_period_cb(void *user, BOOLEAN timer) -{ - ACImpl *This = user; - - if(This->event) - SetEvent(This->event); -} - -static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct start_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - if((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event) - return AUDCLNT_E_EVENTHANDLE_NOT_SET; - - params.stream = This->stream; - UNIX_CALL(start, ¶ms); - - if(SUCCEEDED(params.result)){ - if(This->event && !This->timer){ - if(!CreateTimerQueueTimer(&This->timer, g_timer_q, ca_period_cb, This, 0, - This->period_ms, WT_EXECUTEINTIMERTHREAD)){ - This->timer = NULL; - IAudioClient3_Stop(iface); - WARN("Unable to create timer: %lu\n", GetLastError()); - return E_OUTOFMEMORY; - } - } - } - return params.result; -} - -static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct stop_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - UNIX_CALL(stop, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct reset_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - UNIX_CALL(reset, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface, - HANDLE event) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - HRESULT hr = S_OK; - - TRACE("(%p)->(%p)\n", This, event); - - if(!event) - return E_INVALIDARG; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - EnterCriticalSection(&g_sessions_lock); - - if(!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) - hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED; - else if(This->event){ - FIXME("called twice\n"); - hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME); - }else - This->event = event; - - LeaveCriticalSection(&g_sessions_lock); - - return hr; -} - -static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid, - void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - HRESULT hr; - - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - EnterCriticalSection(&g_sessions_lock); - - if(IsEqualIID(riid, &IID_IAudioRenderClient)){ - if(This->dataflow != eRender){ - hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE; - goto end; - } - IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface); - *ppv = &This->IAudioRenderClient_iface; - }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){ - if(This->dataflow != eCapture){ - hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE; - goto end; - } - IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface); - *ppv = &This->IAudioCaptureClient_iface; - }else if(IsEqualIID(riid, &IID_IAudioClock)){ - IAudioClock_AddRef(&This->IAudioClock_iface); - *ppv = &This->IAudioClock_iface; - }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){ - IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface); - *ppv = &This->IAudioStreamVolume_iface; - }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - hr = E_OUTOFMEMORY; - goto end; - } - }else - IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface); - - *ppv = &This->session_wrapper->IAudioSessionControl2_iface; - }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - hr = E_OUTOFMEMORY; - goto end; - } - }else - IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface); - - *ppv = &This->session_wrapper->IChannelAudioVolume_iface; - }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - hr = E_OUTOFMEMORY; - goto end; - } - }else - ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface); - - *ppv = &This->session_wrapper->ISimpleAudioVolume_iface; - } - - if(*ppv) hr = S_OK; - else{ - FIXME("stub %s\n", debugstr_guid(riid)); - hr = E_NOINTERFACE; - } - -end: - LeaveCriticalSection(&g_sessions_lock); - return hr; -} - -static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface, - AUDIO_STREAM_CATEGORY category, BOOL *offload_capable) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable); - - if(!offload_capable) - return E_INVALIDARG; - - *offload_capable = FALSE; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface, - const AudioClientProperties *prop) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop; - - TRACE("(%p)->(%p)\n", This, prop); - - if(!legacy_prop) - return E_POINTER; - - if(legacy_prop->cbSize == sizeof(AudioClientProperties)){ - TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n", - legacy_prop->bIsOffload, - legacy_prop->eCategory, - prop->Options); - }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){ - TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n", - legacy_prop->bIsOffload, - legacy_prop->eCategory); - }else{ - WARN("Unsupported Size = %d\n", legacy_prop->cbSize); - return E_INVALIDARG; - } - - - if(legacy_prop->bIsOffload) - return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface, - const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration, - REFERENCE_TIME *max_duration) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface, - const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames, - UINT32 *min_period_frames, UINT32 *max_period_frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames, - min_period_frames, max_period_frames); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface, - WAVEFORMATEX **cur_format, UINT32 *cur_period_frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface, - DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format, - const GUID *session_guid) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid)); - - return E_NOTIMPL; -} - -static const IAudioClient3Vtbl AudioClient3_Vtbl = -{ - AudioClient_QueryInterface, - AudioClient_AddRef, - AudioClient_Release, - AudioClient_Initialize, - AudioClient_GetBufferSize, - AudioClient_GetStreamLatency, - AudioClient_GetCurrentPadding, - AudioClient_IsFormatSupported, - AudioClient_GetMixFormat, - AudioClient_GetDevicePeriod, - AudioClient_Start, - AudioClient_Stop, - AudioClient_Reset, - AudioClient_SetEventHandle, - AudioClient_GetService, - AudioClient_IsOffloadCapable, - AudioClient_SetClientProperties, - AudioClient_GetBufferSizeLimits, - AudioClient_GetSharedModeEnginePeriod, - AudioClient_GetCurrentSharedModeEnginePeriod, - AudioClient_InitializeSharedAudioStream, -}; - -static HRESULT WINAPI AudioRenderClient_QueryInterface( - IAudioRenderClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioRenderClient)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface, - UINT32 frames, BYTE **data) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - struct get_render_buffer_params params; - - TRACE("(%p)->(%u, %p)\n", This, frames, data); - - if(!data) - return E_POINTER; - *data = NULL; - - params.stream = This->stream; - params.frames = frames; - params.data = data; - UNIX_CALL(get_render_buffer, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioRenderClient_ReleaseBuffer( - IAudioRenderClient *iface, UINT32 frames, DWORD flags) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - struct release_render_buffer_params params; - - TRACE("(%p)->(%u, %lx)\n", This, frames, flags); - - params.stream = This->stream; - params.written_frames = frames; - params.flags = flags; - UNIX_CALL(release_render_buffer, ¶ms); - return params.result; -} - -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = { - AudioRenderClient_QueryInterface, - AudioRenderClient_AddRef, - AudioRenderClient_Release, - AudioRenderClient_GetBuffer, - AudioRenderClient_ReleaseBuffer -}; - -static HRESULT WINAPI AudioCaptureClient_QueryInterface( - IAudioCaptureClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioCaptureClient)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface, - BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos, - UINT64 *qpcpos) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct get_capture_buffer_params params; - - TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags, - devpos, qpcpos); - - if(!data) - return E_POINTER; - - *data = NULL; - - if(!frames || !flags) - return E_POINTER; - - params.stream = This->stream; - params.data = data; - params.frames = frames; - params.flags = (UINT *)flags; - params.devpos = devpos; - params.qpcpos = qpcpos; - UNIX_CALL(get_capture_buffer, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer( - IAudioCaptureClient *iface, UINT32 done) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct release_capture_buffer_params params; - - TRACE("(%p)->(%u)\n", This, done); - - params.stream = This->stream; - params.done = done; - UNIX_CALL(release_capture_buffer, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize( - IAudioCaptureClient *iface, UINT32 *frames) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct get_next_packet_size_params params; - - TRACE("(%p)->(%p)\n", This, frames); - - if(!frames) - return E_POINTER; - - params.stream = This->stream; - params.frames = frames; - UNIX_CALL(get_next_packet_size, ¶ms); - return params.result; -} - -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl = -{ - AudioCaptureClient_QueryInterface, - AudioCaptureClient_AddRef, - AudioCaptureClient_Release, - AudioCaptureClient_GetBuffer, - AudioCaptureClient_ReleaseBuffer, - AudioCaptureClient_GetNextPacketSize -}; - -static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IAudioClock2)) - *ppv = &This->IAudioClock2_iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioClock_Release(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq) -{ - ACImpl *This = impl_from_IAudioClock(iface); - struct get_frequency_params params; - - TRACE("(%p)->(%p)\n", This, freq); - - params.stream = This->stream; - params.freq = freq; - UNIX_CALL(get_frequency, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos, - UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock(iface); - struct get_position_params params; - - TRACE("(%p)->(%p, %p)\n", This, pos, qpctime); - - if(!pos) - return E_POINTER; - - params.stream = This->stream; - params.pos = pos; - params.qpctime = qpctime; - UNIX_CALL(get_position, ¶ms); - return params.result; -} - -static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface, - DWORD *chars) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%p)\n", This, chars); - - if(!chars) - return E_POINTER; - - *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ; - - return S_OK; -} - -static const IAudioClockVtbl AudioClock_Vtbl = -{ - AudioClock_QueryInterface, - AudioClock_AddRef, - AudioClock_Release, - AudioClock_GetFrequency, - AudioClock_GetPosition, - AudioClock_GetCharacteristics -}; - -static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv); -} - -static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface, - UINT64 *pos, UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - - FIXME("(%p)->(%p, %p)\n", This, pos, qpctime); - - return E_NOTIMPL; -} - -static const IAudioClock2Vtbl AudioClock2_Vtbl = -{ - AudioClock2_QueryInterface, - AudioClock2_AddRef, - AudioClock2_Release, - AudioClock2_GetDevicePosition -}; - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client) -{ - AudioSessionWrapper *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(AudioSessionWrapper)); - if(!ret) - return NULL; - - ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl; - ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl; - ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl; - - ret->ref = 1; - - ret->client = client; - if(client){ - ret->session = client->session; - IAudioClient3_AddRef(&client->IAudioClient3_iface); - } - - return ret; -} - -static HRESULT WINAPI AudioSessionControl_QueryInterface( - IAudioSessionControl2 *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionControl) || - IsEqualIID(riid, &IID_IAudioSessionControl2)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - - EnterCriticalSection(&g_sessions_lock); - - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref){ - if(This->client){ - This->client->session_wrapper = NULL; - AudioClient_Release(&This->client->IAudioClient3_iface); - } - HeapFree(GetProcessHeap(), 0, This); - } - - LeaveCriticalSection(&g_sessions_lock); - return ref; -} - -static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface, - AudioSessionState *state) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - struct is_started_params params; - ACImpl *client; - - TRACE("(%p)->(%p)\n", This, state); - - if(!state) - return NULL_PTR_ERR; - - EnterCriticalSection(&g_sessions_lock); - - if(list_empty(&This->session->clients)){ - *state = AudioSessionStateExpired; - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - - LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){ - params.stream = client->stream; - UNIX_CALL(is_started, ¶ms); - if(params.result == S_OK){ - *state = AudioSessionStateActive; - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - } - - LeaveCriticalSection(&g_sessions_lock); - - *state = AudioSessionStateInactive; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetDisplayName( - IAudioSessionControl2 *iface, WCHAR **name) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, name); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetDisplayName( - IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetIconPath( - IAudioSessionControl2 *iface, WCHAR **path) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, path); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetIconPath( - IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetGroupingParam( - IAudioSessionControl2 *iface, GUID *group) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, group); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetGroupingParam( - IAudioSessionControl2 *iface, const GUID *group, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group), - debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetProcessId( - IAudioSessionControl2 *iface, DWORD *pid) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%p)\n", This, pid); - - if(!pid) - return E_POINTER; - - *pid = GetCurrentProcessId(); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession( - IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)\n", This); - - return S_FALSE; -} - -static HRESULT WINAPI AudioSessionControl_SetDuckingPreference( - IAudioSessionControl2 *iface, BOOL optout) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%d)\n", This, optout); - - return S_OK; -} - -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl = -{ - AudioSessionControl_QueryInterface, - AudioSessionControl_AddRef, - AudioSessionControl_Release, - AudioSessionControl_GetState, - AudioSessionControl_GetDisplayName, - AudioSessionControl_SetDisplayName, - AudioSessionControl_GetIconPath, - AudioSessionControl_SetIconPath, - AudioSessionControl_GetGroupingParam, - AudioSessionControl_SetGroupingParam, - AudioSessionControl_RegisterAudioSessionNotification, - AudioSessionControl_UnregisterAudioSessionNotification, - AudioSessionControl_GetSessionIdentifier, - AudioSessionControl_GetSessionInstanceIdentifier, - AudioSessionControl_GetProcessId, - AudioSessionControl_IsSystemSoundsSession, - AudioSessionControl_SetDuckingPreference -}; - -static HRESULT WINAPI SimpleAudioVolume_QueryInterface( - ISimpleAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_ISimpleAudioVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume( - ISimpleAudioVolume *iface, float level, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context)); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->master_vol = level; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client, -1); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume( - ISimpleAudioVolume *iface, float *level) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, level); - - if(!level) - return NULL_PTR_ERR; - - *level = session->master_vol; - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface, - BOOL mute, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context)); - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->mute = mute; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client, -1); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface, - BOOL *mute) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, mute); - - if(!mute) - return NULL_PTR_ERR; - - *mute = session->mute; - - return S_OK; -} - -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl = -{ - SimpleAudioVolume_QueryInterface, - SimpleAudioVolume_AddRef, - SimpleAudioVolume_Release, - SimpleAudioVolume_SetMasterVolume, - SimpleAudioVolume_GetMasterVolume, - SimpleAudioVolume_SetMute, - SimpleAudioVolume_GetMute -}; - -static HRESULT WINAPI AudioStreamVolume_QueryInterface( - IAudioStreamVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioStreamVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelCount( - IAudioStreamVolume *iface, UINT32 *out) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - *out = This->channel_count; - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_SetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%d, %f)\n", This, index, level); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(index >= This->channel_count) - return E_INVALIDARG; - - EnterCriticalSection(&g_sessions_lock); - - This->vols[index] = level; - - WARN("CoreAudio doesn't support per-channel volume control\n"); - set_stream_volumes(This, index); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float *level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%d, %p)\n", This, index, level); - - if(!level) - return E_POINTER; - - if(index >= This->channel_count) - return E_INVALIDARG; - - *level = This->vols[index]; - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_SetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, const float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - UINT32 i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if(!levels) - return E_POINTER; - - if(count != This->channel_count) - return E_INVALIDARG; - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - This->vols[i] = levels[i]; - - set_stream_volumes(This, -1); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_GetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - UINT32 i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if(!levels) - return E_POINTER; - - if(count != This->channel_count) - return E_INVALIDARG; - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - levels[i] = This->vols[i]; - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl = -{ - AudioStreamVolume_QueryInterface, - AudioStreamVolume_AddRef, - AudioStreamVolume_Release, - AudioStreamVolume_GetChannelCount, - AudioStreamVolume_SetChannelVolume, - AudioStreamVolume_GetChannelVolume, - AudioStreamVolume_SetAllVolumes, - AudioStreamVolume_GetAllVolumes -}; - -static HRESULT WINAPI ChannelAudioVolume_QueryInterface( - IChannelAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IChannelAudioVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelCount( - IChannelAudioVolume *iface, UINT32 *out) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, out); - - if(!out) - return NULL_PTR_ERR; - - *out = session->channel_count; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float level, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%d, %f, %s)\n", session, index, level, - wine_dbgstr_guid(context)); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(index >= session->channel_count) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->channel_vols[index] = level; - - WARN("CoreAudio doesn't support per-channel volume control\n"); - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client, index); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float *level) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%d, %p)\n", session, index, level); - - if(!level) - return NULL_PTR_ERR; - - if(index >= session->channel_count) - return E_INVALIDARG; - - *level = session->channel_vols[index]; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, const float *levels, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - UINT32 i; - - TRACE("(%p)->(%d, %p, %s)\n", session, count, levels, - wine_dbgstr_guid(context)); - - if(!levels) - return NULL_PTR_ERR; - - if(count != session->channel_count) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - session->channel_vols[i] = levels[i]; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client, -1); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, float *levels) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - int i; - - TRACE("(%p)->(%d, %p)\n", session, count, levels); - - if(!levels) - return NULL_PTR_ERR; - - if(count != session->channel_count) - return E_INVALIDARG; - - for(i = 0; i < count; ++i) - levels[i] = session->channel_vols[i]; - - return S_OK; -} - -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl = -{ - ChannelAudioVolume_QueryInterface, - ChannelAudioVolume_AddRef, - ChannelAudioVolume_Release, - ChannelAudioVolume_GetChannelCount, - ChannelAudioVolume_SetChannelVolume, - ChannelAudioVolume_GetChannelVolume, - ChannelAudioVolume_SetAllVolumes, - ChannelAudioVolume_GetAllVolumes -}; - -static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface, - REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionManager) || - IsEqualIID(riid, &IID_IAudioSessionManager2)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref) - HeapFree(GetProcessHeap(), 0, This); - return ref; -} - -static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - IAudioSessionControl **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if(FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - ISimpleAudioVolume **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if(FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = &wrapper->ISimpleAudioVolume_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator( - IAudioSessionManager2 *iface, IAudioSessionEnumerator **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, out); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification( - IAudioSessionManager2 *iface, const WCHAR *session_id, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification( - IAudioSessionManager2 *iface, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl = -{ - AudioSessionManager_QueryInterface, - AudioSessionManager_AddRef, - AudioSessionManager_Release, - AudioSessionManager_GetAudioSessionControl, - AudioSessionManager_GetSimpleAudioVolume, - AudioSessionManager_GetSessionEnumerator, - AudioSessionManager_RegisterSessionNotification, - AudioSessionManager_UnregisterSessionNotification, - AudioSessionManager_RegisterDuckNotification, - AudioSessionManager_UnregisterDuckNotification -}; - -HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device, - IAudioSessionManager2 **out) -{ - SessionMgr *This; - - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr)); - if(!This) - return E_OUTOFMEMORY; - - This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl; - This->device = device; - This->ref = 1; - - *out = &This->IAudioSessionManager2_iface; - - return S_OK; -} diff --git a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/unixlib.h b/pkgs/osu-wine/audio-revert/winecoreaudio.drv/unixlib.h deleted file mode 100644 index 932a772..0000000 --- a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/unixlib.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Unixlib header file for winecoreaudio driver. - * - * Copyright 2021 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "../mmdevapi/unixlib.h" - -NTSTATUS unix_midi_init( void * ); -NTSTATUS unix_midi_release( void * ); -NTSTATUS unix_midi_out_message( void * ); -NTSTATUS unix_midi_in_message( void * ); -NTSTATUS unix_midi_notify_wait( void * ); - -#ifdef _WIN64 -NTSTATUS unix_wow64_midi_init(void *args); -NTSTATUS unix_wow64_midi_out_message(void *args); -NTSTATUS unix_wow64_midi_in_message(void *args); -NTSTATUS unix_wow64_midi_notify_wait(void *args); -#endif - -#define UNIX_CALL( func, params ) WINE_UNIX_CALL( func, params ) diff --git a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/winecoreaudio.drv.spec b/pkgs/osu-wine/audio-revert/winecoreaudio.drv/winecoreaudio.drv.spec deleted file mode 100644 index 9d9f781..0000000 --- a/pkgs/osu-wine/audio-revert/winecoreaudio.drv/winecoreaudio.drv.spec +++ /dev/null @@ -1,10 +0,0 @@ -# WinMM driver functions -@ stdcall -private DriverProc(long long long long long) CoreAudio_DriverProc -@ stdcall -private midMessage(long long long long long) CoreAudio_midMessage -@ stdcall -private modMessage(long long long long long) CoreAudio_modMessage - -# MMDevAPI driver functions -@ stdcall -private GetPriority() AUDDRV_GetPriority -@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs -@ stdcall -private GetAudioEndpoint(ptr ptr ptr) AUDDRV_GetAudioEndpoint -@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/Makefile.in b/pkgs/osu-wine/audio-revert/wineoss.drv/Makefile.in deleted file mode 100644 index a453388..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/Makefile.in +++ /dev/null @@ -1,14 +0,0 @@ -MODULE = wineoss.drv -UNIXLIB = wineoss.so -IMPORTS = uuid ole32 user32 advapi32 -DELAYIMPORTS = winmm -UNIX_LIBS = $(OSS4_LIBS) $(PTHREAD_LIBS) -UNIX_CFLAGS = $(OSS4_CFLAGS) - -SOURCES = \ - midi.c \ - midipatch.c \ - mmaux.c \ - mmdevdrv.c \ - oss.c \ - ossmidi.c diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/midi.c b/pkgs/osu-wine/audio-revert/wineoss.drv/midi.c deleted file mode 100644 index ca842bb..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/midi.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * MIDI driver for OSS (PE-side) - * - * Copyright 1994 Martin Ayotte - * Copyright 1998 Luiz Otavio L. Zorzella (init procedures) - * Copyright 1998, 1999 Eric POUECH - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* TODO: - * + use better instrument definition for OPL/2 (midiPatch.c) or - * use existing instrument definition (from playmidi or kmid) - * with a .winerc option - * + have a look at OPL/3 ? - * + implement asynchronous playback of MidiHdr - * + implement STREAM'ed MidiHdr (question: how shall we share the - * code between the midiStream functions in MMSYSTEM/WINMM and - * the code for the low level driver) - * + use a more accurate read mechanism than the one of snooping on - * timers (like select on fd) - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winternl.h" -#include "mmddk.h" -#include "audioclient.h" - -#include "wine/debug.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(midi); - -/*======================================================================* - * Low level MIDI implementation * - *======================================================================*/ - -static void notify_client(struct notify_context *notify) -{ - TRACE("dev_id = %d msg = %d param1 = %04IX param2 = %04IX\n", - notify->dev_id, notify->msg, notify->param_1, notify->param_2); - - DriverCallback(notify->callback, notify->flags, notify->device, notify->msg, - notify->instance, notify->param_1, notify->param_2); -} - -/*======================================================================* - * MIDI entry points * - *======================================================================*/ - -/************************************************************************** - * midMessage (WINEOSS.@) - */ -DWORD WINAPI OSS_midMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - struct midi_in_message_params params; - struct notify_context notify; - UINT err; - - TRACE("(%04X, %04X, %08IX, %08IX, %08IX);\n", - wDevID, wMsg, dwUser, dwParam1, dwParam2); - - params.dev_id = wDevID; - params.msg = wMsg; - params.user = dwUser; - params.param_1 = dwParam1; - params.param_2 = dwParam2; - params.err = &err; - params.notify = ¬ify; - - do - { - OSS_CALL(midi_in_message, ¶ms); - if ((!err || err == ERROR_RETRY) && notify.send_notify) notify_client(¬ify); - } while (err == ERROR_RETRY); - - return err; -} - -/************************************************************************** - * modMessage (WINEOSS.@) - */ -DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - struct midi_out_message_params params; - struct notify_context notify; - UINT err; - - TRACE("(%04X, %04X, %08IX, %08IX, %08IX);\n", - wDevID, wMsg, dwUser, dwParam1, dwParam2); - - params.dev_id = wDevID; - params.msg = wMsg; - params.user = dwUser; - params.param_1 = dwParam1; - params.param_2 = dwParam2; - params.err = &err; - params.notify = ¬ify; - - OSS_CALL(midi_out_message, ¶ms); - - if (!err && notify.send_notify) notify_client(¬ify); - - return err; -} - -static DWORD WINAPI notify_thread(void *p) -{ - struct midi_notify_wait_params params; - struct notify_context notify; - BOOL quit; - - params.notify = ¬ify; - params.quit = &quit; - - while (1) - { - OSS_CALL(midi_notify_wait, ¶ms); - if (quit) break; - if (notify.send_notify) notify_client(¬ify); - } - return 0; -} - -/************************************************************************** - * DriverProc (WINEOSS.1) - */ -LRESULT CALLBACK OSS_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, - LPARAM dwParam1, LPARAM dwParam2) -{ - TRACE("(%08IX, %p, %08X, %08IX, %08IX)\n", - dwDevID, hDriv, wMsg, dwParam1, dwParam2); - - switch(wMsg) { - case DRV_LOAD: - CloseHandle(CreateThread(NULL, 0, notify_thread, NULL, 0, NULL)); - return 1; - case DRV_FREE: - OSS_CALL(midi_release, NULL); - return 1; - case DRV_OPEN: - case DRV_CLOSE: - case DRV_ENABLE: - case DRV_DISABLE: - case DRV_QUERYCONFIGURE: - case DRV_CONFIGURE: - return 1; - case DRV_INSTALL: - case DRV_REMOVE: - return DRV_SUCCESS; - default: - return 0; - } -} diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/midipatch.c b/pkgs/osu-wine/audio-revert/wineoss.drv/midipatch.c deleted file mode 100644 index 4ff4862..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/midipatch.c +++ /dev/null @@ -1,293 +0,0 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ - -/* - * FM patches for wine MIDI driver - * - * Copyright 1999 Eric Pouech - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* - * Eric POUECH : MIDI FM patches for GM instruments - */ - -#if 0 -#pragma makedep unix -#endif - -#define NOT_DEFINED 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - -const unsigned char midiFMInstrumentPatches[128 * 16] = { -/* 0 Acoustic Grand Piano */ 0x21, 0x11, 0x4c, 0x00, 0xf1, 0xf2, 0x63, 0x72, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 1 Bright Acoustic Piano */ 0x01, 0x11, 0x4f, 0x00, 0xf1, 0xd2, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 2 Electric Grand Piano */ 0x01, 0x01, 0x4f, 0x04, 0xf1, 0xd2, 0x50, 0x7c, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 3 Honky-Tonk Piano */ 0x81, 0x13, 0x9d, 0x00, 0xf2, 0xf2, 0x51, 0xf1, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 4 Rhodes Piano */ 0x01, 0x01, 0x4f, 0x04, 0xf1, 0xd2, 0x50, 0x7c, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 5 Chorused Piano */ 0x01, 0x11, 0x4d, 0x00, 0xf1, 0xd2, 0x60, 0x7b, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 6 Harpsichord */ 0x32, 0x16, 0x87, 0x80, 0xa1, 0x7d, 0x10, 0x33, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 7 Clavinet */ 0x13, 0x08, 0x80, 0x00, 0xfb, 0xe8, 0xff, 0xff, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 8 Celesta */ 0x14, 0x04, 0x07, 0x00, 0x93, 0xb6, 0x73, 0x62, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 9 Glockenspiel */ 0x07, 0x12, 0x4f, 0x00, 0xf2, 0xf2, 0x60, 0x72, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 10 Music Box */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 11 Vibraphone */ 0x44, 0x60, 0x53, 0x80, 0xf5, 0xfd, 0x33, 0x25, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 12 Marimba */ 0x05, 0x01, 0x4e, 0x00, 0xda, 0xf9, 0x25, 0x15, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 13 Xylophone */ 0x11, 0x31, 0x2d, 0x00, 0xc8, 0xf5, 0x2f, 0xf5, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 14 Tubular Bells */ 0x03, 0x17, 0x4f, 0x03, 0xf1, 0xf2, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 15 Dulcimer */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 16 Hammond Organ */ 0x72, 0x71, 0xcd, 0x80, 0x91, 0x91, 0x2a, 0x2a, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 17 Percussive Organ */ 0x0c, 0x00, 0x00, 0x00, 0xf8, 0xd6, 0xb5, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 18 Rock Organ */ 0x72, 0x70, 0xce, 0x80, 0x9f, 0x94, 0x12, 0x11, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 19 Church Organ */ 0xa5, 0xb1, 0xd2, 0x80, 0x81, 0xf1, 0x03, 0x05, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 20 Reed Organ */ 0x3e, 0xb1, 0x29, 0x80, 0xfb, 0xa0, 0xf0, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 21 Accordion */ 0x24, 0x31, 0x4f, 0x00, 0xf2, 0x52, 0x0b, 0x0b, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 22 Harmonica */ 0x22, 0xf2, 0x8f, 0x40, 0x41, 0x61, 0x03, 0x05, 0x02, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 23 Tango Accordion */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 24 Acoustic Nylon Guitar */ 0x01, 0x01, 0x11, 0x00, 0xf2, 0xf5, 0x1f, 0x88, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 25 Acoustic Steel Guitar */ 0x01, 0xa1, 0x46, 0x03, 0xf1, 0x31, 0x83, 0x86, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 26 Electric Jazz Guitar */ 0x03, 0x11, 0x5e, 0x00, 0x85, 0xd2, 0x51, 0x71, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 27 Electric Clean Guitar */ 0x32, 0x16, 0x87, 0x80, 0xa1, 0x7d, 0x10, 0x33, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 28 Electric Muted Guitar */ 0x13, 0x11, 0x96, 0x80, 0xff, 0xff, 0x21, 0x03, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 29 Overdriven Guitar */ 0x07, 0x14, 0x8f, 0x80, 0x82, 0x82, 0x7d, 0x7d, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 30 Distortion Guitar */ 0x05, 0x01, 0x8f, 0x80, 0xda, 0xf9, 0x15, 0x14, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 31 Guitar Harmonics */ 0xc3, 0x01, 0x05, 0x0d, 0x91, 0xf1, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 32 Acoustic Bass */ 0x21, 0x01, 0x2a, 0x00, 0xf2, 0xf5, 0x1f, 0x88, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 33 Electric Bass Fingered */ 0x01, 0x21, 0x15, 0x80, 0x25, 0x65, 0x2f, 0x6c, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 34 Electric Bass Picked */ 0x01, 0x01, 0x1d, 0x00, 0xf2, 0xf5, 0xef, 0x78, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 35 Fretless Bass */ 0x30, 0x21, 0x1e, 0x00, 0xf2, 0xf5, 0xef, 0x78, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 Slap Bass 1 */ 0x20, 0x21, 0x40, 0x00, 0x7b, 0x75, 0x04, 0x72, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 37 Slap Bass 2 */ 0x20, 0x21, 0x40, 0x00, 0x7b, 0xf5, 0x04, 0x72, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 38 Synth Bass 1 */ 0x41, 0x91, 0x83, 0x00, 0x65, 0x32, 0x05, 0x74, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 39 Synth Bass 2 */ 0x30, 0xb1, 0x88, 0x80, 0xd5, 0x61, 0x19, 0x1b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 40 Violin */ 0x72, 0x62, 0x1c, 0x05, 0x51, 0x52, 0x03, 0x13, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 41 Viola */ 0x70, 0x71, 0xd0, 0x80, 0x52, 0x31, 0x11, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 42 Cello */ 0x70, 0x71, 0xc5, 0x80, 0x52, 0x31, 0x11, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 43 Contrabass */ 0x01, 0x00, 0x00, 0x00, 0x94, 0x83, 0xb6, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 44 Tremolo Strings */ 0x71, 0xa1, 0x8b, 0x40, 0x71, 0x42, 0x11, 0x15, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 45 Pizzicato Strings */ 0xf2, 0xe1, 0x40, 0x80, 0xf5, 0xfd, 0xa8, 0xad, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 46 Orchestral Harp */ 0x21, 0x11, 0x11, 0x00, 0xa3, 0xc4, 0x43, 0x22, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 47 Timpani */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 48 String Ensemble 1 */ 0xe1, 0x21, 0x4f, 0x00, 0xc1, 0x32, 0xd3, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 49 String Ensemble 2 */ 0xe1, 0x21, 0x4f, 0x00, 0xb1, 0x12, 0xd3, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 50 Synth Strings 1 */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 51 Synth Strings 2 */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 52 Choir Aahs */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 53 Voice oohs */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 54 Synth Voice */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 55 Orchestra Hit */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 56 Trumpet */ 0x31, 0xa1, 0x1c, 0x80, 0x41, 0x92, 0x0b, 0x3b, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 57 Trombone */ 0x21, 0xa1, 0x18, 0x80, 0x53, 0x52, 0x1d, 0x3b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 58 Tuba */ 0x21, 0x21, 0x19, 0x80, 0x43, 0x85, 0x8c, 0x2f, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 59 Muted Trumpet */ 0x31, 0xa1, 0x1c, 0x80, 0x41, 0x92, 0x0b, 0x3b, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 60 French Horn */ 0x21, 0x21, 0x9f, 0x80, 0x53, 0xaa, 0x5a, 0x1a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 61 Brass Section */ 0x21, 0x21, 0x16, 0x00, 0x71, 0x81, 0xae, 0x9e, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 62 Synth Brass 1 */ 0x61, 0x60, 0x1c, 0x00, 0x71, 0x81, 0xae, 0x2e, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 63 Synth Brass 2 */ 0x21, 0x21, 0x8e, 0x80, 0xbb, 0x90, 0x29, 0x0a, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 64 Soprano Sax */ 0x01, 0x12, 0x4f, 0x00, 0x71, 0x52, 0x53, 0x7c, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 65 Alto Sax */ 0x01, 0x13, 0x4f, 0x00, 0x71, 0x62, 0x53, 0x84, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 66 Tenor Sax */ 0x01, 0x13, 0x8d, 0x00, 0x51, 0x52, 0x53, 0x7c, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 67 Baritone Sax */ 0x01, 0x12, 0x4f, 0x00, 0x71, 0x22, 0x53, 0x7c, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 68 Oboe */ 0x71, 0x62, 0xc5, 0x05, 0x6e, 0x8b, 0x17, 0x0e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 69 English Horn */ 0xe1, 0xe4, 0x23, 0x00, 0x71, 0x82, 0xae, 0x9e, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 70 Bassoon */ 0x30, 0xb1, 0xcd, 0x80, 0xd5, 0x61, 0x19, 0x1b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 71 Clarinet */ 0x32, 0xa1, 0x1c, 0x80, 0x51, 0x82, 0x15, 0x45, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 72 Piccolo */ 0xe4, 0xe4, 0x0f, 0x00, 0x70, 0x60, 0x0f, 0x9f, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 73 Flute */ 0xe1, 0x61, 0x27, 0x80, 0x53, 0x53, 0x8a, 0x57, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 74 Recorder */ 0x61, 0x61, 0x27, 0x80, 0x74, 0x65, 0x8f, 0x2a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 75 Pan Flute */ 0xe0, 0xa1, 0xec, 0x00, 0x6e, 0x65, 0x8f, 0x2a, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 76 Bottle Blow */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 77 Shakuhashi */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 78 Whistle */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 79 Ocarina */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 80 Synth lead 1 - Sq wave lead */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 81 Synth lead 2 - Sawtooth Wave */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 82 Synth lead 3 - Caliope lead */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 83 Synth lead 4 - Chiff lead */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 84 Synth lead 5 - Charang */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 85 Synth lead 6 - Solo Synth Voice */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 86 Synth lead 7 - Bright Saw Wave */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 87 Synth lead 8 - Brass and Lead */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 88 Synth pad 1 - Fantasia Pad */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 89 Synth pad 2 - Warm Pad */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 90 Synth pad 3 - Poly Synth Pad */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 91 Synth pad 4 - Space Voice Pad */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 92 Synth pad 5 - Bowed Glass Pad */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 93 Synth pad 6 - Metal Pad */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 94 Synth pad 7 - Halo Pad */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 95 Synth pad 8 - Sweep Pad */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 96 Synth SFX 1 - Ice Rain */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 97 Synth SFX 2 - Soundtrack */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 98 Synth SFX 3 - Crystal */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 99 Synth SFX 4 - Atmosphere */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 100 Synth SFX 5 - Brightness */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 101 Synth SFX 6 - Goblin */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 102 Synth SFX 7 - Echo drops */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 103 Synth SFX 8 - Star Theme */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 104 Sitar */ 0x01, 0x08, 0x40, 0x00, 0xf2, 0xf2, 0x54, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 105 Banjo */ 0x31, 0x16, 0x87, 0x80, 0xa1, 0x7d, 0x11, 0x43, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 106 Shamisen */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 107 Koto */ 0x0e, 0x02, 0x40, 0x00, 0x09, 0xf7, 0x53, 0x94, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 108 Kalimba */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 109 Bagpipe */ 0x31, 0x22, 0x43, 0x05, 0x6e, 0x8b, 0x17, 0x0c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 110 Fiddle */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 111 Shanai */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 112 Tinkle Bell */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 113 Agogo */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 114 Steel Drums */ 0x00, 0x00, 0x0b, 0x00, 0xa8, 0xd6, 0x4c, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 115 Woodblock */ 0x02, 0x11, 0x4f, 0x00, 0x71, 0x52, 0x53, 0x7c, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 116 Taiko Drum */ 0x12, 0x02, 0x0b, 0x00, 0x95, 0xd4, 0x4c, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 117 Melodic Tom */ 0x01, 0x02, 0x00, 0x00, 0xfa, 0xda, 0xbf, 0xbf, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 118 Synth Drum */ 0x06, 0x00, 0x00, 0x00, 0xf0, 0xf6, 0xf0, 0xb4, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 119 Reverse Cymbal */ 0x64, 0x03, 0x00, 0x40, 0xb2, 0x97, 0x82, 0xd4, 0x02, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 120 Guitar Fret Noise */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 121 Breath Noise */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 122 Seashore */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 123 Bird Tweet */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 124 Telephone Ring */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 125 Helicopter */ 0xf0, 0xe2, 0x00, 0xc0, 0x1e, 0x11, 0x11, 0x11, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 126 Applause */ 0x07, 0x01, 0x87, 0x80, 0xf0, 0xf0, 0x05, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 127 Gunshot */ 0x0c, 0x50, 0x00, 0x21, 0xf8, 0x09, 0xb6, 0x04, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -const unsigned char midiFMDrumsPatches[16 * 128] = { -/* 1 Not defined */ NOT_DEFINED -/* 2 Not defined */ NOT_DEFINED -/* 3 Not defined */ NOT_DEFINED -/* 4 Not defined */ NOT_DEFINED -/* 5 Not defined */ NOT_DEFINED -/* 6 Not defined */ NOT_DEFINED -/* 7 Not defined */ NOT_DEFINED -/* 8 Not defined */ NOT_DEFINED -/* 9 Not defined */ NOT_DEFINED -/* 10 Not defined */ NOT_DEFINED -/* 11 Not defined */ NOT_DEFINED -/* 12 Not defined */ NOT_DEFINED -/* 13 Not defined */ NOT_DEFINED -/* 14 Not defined */ NOT_DEFINED -/* 15 Not defined */ NOT_DEFINED -/* 16 Not defined */ NOT_DEFINED -/* 17 Not defined */ NOT_DEFINED -/* 18 Not defined */ NOT_DEFINED -/* 19 Not defined */ NOT_DEFINED -/* 20 Not defined */ NOT_DEFINED -/* 21 Not defined */ NOT_DEFINED -/* 22 Not defined */ NOT_DEFINED -/* 23 Not defined */ NOT_DEFINED -/* 24 Not defined */ NOT_DEFINED -/* 25 Not defined */ NOT_DEFINED -/* 26 Not defined */ NOT_DEFINED -/* 27 Not defined */ NOT_DEFINED -/* 28 Not defined */ NOT_DEFINED -/* 29 Not defined */ NOT_DEFINED -/* 30 Not defined */ NOT_DEFINED -/* 31 Not defined */ NOT_DEFINED -/* 32 Not defined */ NOT_DEFINED -/* 33 Not defined */ NOT_DEFINED -/* 34 Not defined */ NOT_DEFINED -/* 35 Acoustic Bass Drum */ 0x00, 0x00, 0x0d, 0x00, 0xe8, 0xa5, 0xef, 0xff, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 Bass Drum 1 */ 0x00, 0x00, 0x0b, 0x00, 0xa8, 0xd6, 0x4c, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 37 Side Stick */ NOT_DEFINED -/* 38 Acoustic Snare */ 0x2e, 0x02, 0x0a, 0x1b, 0xff, 0xf6, 0x0f, 0x4a, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, /* snare */ -/* 39 Hand Clap */ NOT_DEFINED -/* 40 Electric Snare */ 0x0c, 0xd0, 0x00, 0x00, 0xc7, 0x70, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* rksnare */ -/* 41 Low Floor Tom */ NOT_DEFINED -/* 42 Closed Hi-Hat */ 0x64, 0x03, 0x02, 0x40, 0xb2, 0x97, 0xa2, 0xd4, 0x02, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, /* cymbal */ -/* 43 High Floor Tom */ NOT_DEFINED -/* 44 Pedal Hi-Hat */ NOT_DEFINED -/* 45 Low Tom */ 0x01, 0x02, 0x00, 0x00, 0xfa, 0xda, 0xbf, 0xbf, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* tom */ -/* 46 Open Hi-Hat */ NOT_DEFINED -/* 47 Low-Mid Tom */ 0x02, 0x30, 0x00, 0x00, 0xc8, 0xe0, 0x97, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* tom2 */ -/* 48 Hi-Mid Tom */ NOT_DEFINED -/* 49 Crash Cymbal 1 */ NOT_DEFINED -/* 50 High Tom */ NOT_DEFINED -/* 51 Ride Cymbal 1 */ 0x64, 0x03, 0x00, 0x40, 0xb2, 0x97, 0x82, 0xd4, 0x02, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, /* bcymbal */ -/* 52 Chinese Cymbal */ NOT_DEFINED -/* 53 Ride Bell */ NOT_DEFINED -/* 54 Tambourine */ NOT_DEFINED -/* 55 Splash Cymbal */ NOT_DEFINED -/* 56 Cowbell */ NOT_DEFINED -/* 57 Crash Cymbal 2 */ NOT_DEFINED -/* 58 Vibrasl */ NOT_DEFINED -/* 59 Ride Cymbal */ NOT_DEFINED -/* 60 Hi Bon */ NOT_DEFINED -/* 61 Low Bon */ NOT_DEFINED -/* 62 Mute Hi Con */ NOT_DEFINED -/* 63 Open Hi Con */ NOT_DEFINED -/* 64 Low Con */ NOT_DEFINED -/* 65 High Timba */ NOT_DEFINED -/* 66 Low Timba */ NOT_DEFINED -/* 67 High Ago */ NOT_DEFINED -/* 68 Low Ago */ NOT_DEFINED -/* 69 Caba */ NOT_DEFINED -/* 70 Marac */ NOT_DEFINED -/* 71 Short Whist */ NOT_DEFINED -/* 72 Long Whist */ NOT_DEFINED -/* 73 Short Gui */ NOT_DEFINED -/* 74 Long Gui */ NOT_DEFINED -/* 75 Clav */ 0x13, 0x08, 0x80, 0x00, 0xfb, 0xe8, 0xff, 0xff, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, /* claves */ -/* 76 Hi Wood Blo */ NOT_DEFINED -/* 77 Low Wood Blo */ NOT_DEFINED -/* 78 Mute Cui */ NOT_DEFINED -/* 79 Open Cui */ NOT_DEFINED -/* 80 Mute Triang */ NOT_DEFINED -/* 81 Open Triang */ 0x26, 0x1e, 0x03, 0x00, 0xe0, 0xff, 0xf0, 0x31, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, /* triangle */ -/* 82 Not defined */ NOT_DEFINED -/* 83 Not defined */ NOT_DEFINED -/* 84 Not defined */ NOT_DEFINED -/* 85 Not defined */ NOT_DEFINED -/* 86 Not defined */ NOT_DEFINED -/* 87 Not defined */ NOT_DEFINED -/* 88 Not defined */ NOT_DEFINED -/* 89 Not defined */ NOT_DEFINED -/* 90 Not defined */ NOT_DEFINED -/* 91 Not defined */ NOT_DEFINED -/* 92 Not defined */ NOT_DEFINED -/* 93 Not defined */ NOT_DEFINED -/* 94 Not defined */ NOT_DEFINED -/* 95 Not defined */ NOT_DEFINED -/* 96 Not defined */ NOT_DEFINED -/* 97 Not defined */ NOT_DEFINED -/* 98 Not defined */ NOT_DEFINED -/* 99 Not defined */ NOT_DEFINED -/* 100 Not defined */ NOT_DEFINED -/* 101 Not defined */ NOT_DEFINED -/* 102 Not defined */ NOT_DEFINED -/* 103 Not defined */ NOT_DEFINED -/* 104 Not defined */ NOT_DEFINED -/* 105 Not defined */ NOT_DEFINED -/* 106 Not defined */ NOT_DEFINED -/* 107 Not defined */ NOT_DEFINED -/* 108 Not defined */ NOT_DEFINED -/* 109 Not defined */ NOT_DEFINED -/* 110 Not defined */ NOT_DEFINED -/* 111 Not defined */ NOT_DEFINED -/* 112 Not defined */ NOT_DEFINED -/* 113 Not defined */ NOT_DEFINED -/* 114 Not defined */ NOT_DEFINED -/* 115 Not defined */ NOT_DEFINED -/* 116 Not defined */ NOT_DEFINED -/* 117 Not defined */ NOT_DEFINED -/* 118 Not defined */ NOT_DEFINED -/* 119 Not defined */ NOT_DEFINED -/* 120 Not defined */ NOT_DEFINED -/* 121 Not defined */ NOT_DEFINED -/* 122 Not defined */ NOT_DEFINED -/* 123 Not defined */ NOT_DEFINED -/* 124 Not defined */ NOT_DEFINED -/* 125 Not defined */ NOT_DEFINED -/* 126 Not defined */ NOT_DEFINED -/* 127 Not defined */ NOT_DEFINED -/* 128 Not defined */ NOT_DEFINED -}; diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/mmaux.c b/pkgs/osu-wine/audio-revert/wineoss.drv/mmaux.c deleted file mode 100644 index f86ec6f..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/mmaux.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Sample AUXILIARY Wine Driver - * - * Copyright 1994 Martin Ayotte - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include - -#include "windef.h" -#include "winbase.h" -#include "mmddk.h" -#include "audioclient.h" -#include "winternl.h" - -#include "wine/debug.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(mmaux); - -/************************************************************************** - * auxMessage (WINEOSS.2) - */ -DWORD WINAPI OSS_auxMessage(UINT wDevID, UINT wMsg, DWORD_PTR dwUser, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - struct aux_message_params params; - UINT err; - - TRACE("(%04X, %04X, %08IX, %08IX, %08IX);\n", - wDevID, wMsg, dwUser, dwParam1, dwParam2); - - params.dev_id = wDevID; - params.msg = wMsg; - params.user = dwUser; - params.param_1 = dwParam1; - params.param_2 = dwParam2; - params.err = &err; - OSS_CALL(aux_message, ¶ms); - - return err; -} diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/mmdevdrv.c b/pkgs/osu-wine/audio-revert/wineoss.drv/mmdevdrv.c deleted file mode 100644 index 7411f87..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/mmdevdrv.c +++ /dev/null @@ -1,2385 +0,0 @@ -/* - * Copyright 2011 Andrew Eikum for CodeWeavers - * 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define COBJMACROS -#include - -#include "windef.h" -#include "winbase.h" -#include "winternl.h" -#include "winnls.h" -#include "winreg.h" - -#include "ole2.h" -#include "mmdeviceapi.h" -#include "devpkey.h" -#include "dshow.h" -#include "dsound.h" - -#include "initguid.h" -#include "endpointvolume.h" -#include "audiopolicy.h" -#include "audioclient.h" - -#include "wine/debug.h" -#include "wine/list.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -WINE_DEFAULT_DEBUG_CHANNEL(oss); - -#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) - -static const REFERENCE_TIME DefaultPeriod = 100000; -static const REFERENCE_TIME MinimumPeriod = 50000; - -struct ACImpl; -typedef struct ACImpl ACImpl; - -typedef struct _AudioSession { - GUID guid; - struct list clients; - - IMMDevice *device; - - float master_vol; - UINT32 channel_count; - float *channel_vols; - BOOL mute; - - struct list entry; -} AudioSession; - -typedef struct _AudioSessionWrapper { - IAudioSessionControl2 IAudioSessionControl2_iface; - IChannelAudioVolume IChannelAudioVolume_iface; - ISimpleAudioVolume ISimpleAudioVolume_iface; - - LONG ref; - - ACImpl *client; - AudioSession *session; -} AudioSessionWrapper; - -struct ACImpl { - IAudioClient3 IAudioClient3_iface; - IAudioRenderClient IAudioRenderClient_iface; - IAudioCaptureClient IAudioCaptureClient_iface; - IAudioClock IAudioClock_iface; - IAudioClock2 IAudioClock2_iface; - IAudioStreamVolume IAudioStreamVolume_iface; - - LONG ref; - - IMMDevice *parent; - IUnknown *pUnkFTMarshal; - - EDataFlow dataflow; - float *vols; - UINT32 channel_count; - stream_handle stream; - - HANDLE timer_thread; - - AudioSession *session; - AudioSessionWrapper *session_wrapper; - - struct list entry; - - /* Keep at end */ - char devnode[0]; -}; - -typedef struct _SessionMgr { - IAudioSessionManager2 IAudioSessionManager2_iface; - - LONG ref; - - IMMDevice *device; -} SessionMgr; - -typedef struct _OSSDevice { - struct list entry; - EDataFlow flow; - GUID guid; - char devnode[0]; -} OSSDevice; - -static struct list g_devices = LIST_INIT(g_devices); - -static const WCHAR drv_key_devicesW[] = {'S','o','f','t','w','a','r','e','\\', - 'W','i','n','e','\\','D','r','i','v','e','r','s','\\', - 'w','i','n','e','o','s','s','.','d','r','v','\\','d','e','v','i','c','e','s',0}; -static const WCHAR guidW[] = {'g','u','i','d',0}; - -static CRITICAL_SECTION g_sessions_lock; -static CRITICAL_SECTION_DEBUG g_sessions_lock_debug = -{ - 0, 0, &g_sessions_lock, - { &g_sessions_lock_debug.ProcessLocksList, &g_sessions_lock_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": g_sessions_lock") } -}; -static CRITICAL_SECTION g_sessions_lock = { &g_sessions_lock_debug, -1, 0, 0, 0, 0 }; -static struct list g_sessions = LIST_INIT(g_sessions); - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client); - -static const IAudioClient3Vtbl AudioClient3_Vtbl; -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl; -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl; -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl; -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl; -static const IAudioClockVtbl AudioClock_Vtbl; -static const IAudioClock2Vtbl AudioClock2_Vtbl; -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl; -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl; -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl; - -static inline ACImpl *impl_from_IAudioClient3(IAudioClient3 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClient3_iface); -} - -static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface); -} - -static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface); -} - -static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface); -} - -static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface); -} - -static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface); -} - -static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface); -} - -static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface); -} - -static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); -} - -static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface) -{ - return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface); -} - -BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) -{ - switch (reason) - { - case DLL_PROCESS_ATTACH: - if(__wine_init_unix_call()) return FALSE; - break; - - case DLL_PROCESS_DETACH: - if (!reserved) - { - OSSDevice *iter, *iter2; - - DeleteCriticalSection(&g_sessions_lock); - - LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &g_devices, OSSDevice, entry){ - HeapFree(GetProcessHeap(), 0, iter); - } - } - break; - } - return TRUE; -} - -int WINAPI AUDDRV_GetPriority(void) -{ - struct test_connect_params params; - - params.name = NULL; - - OSS_CALL(test_connect, ¶ms); - - return params.priority; -} - -static HRESULT stream_release(stream_handle stream, HANDLE timer_thread) -{ - struct release_stream_params params; - - params.stream = stream; - params.timer_thread = timer_thread; - OSS_CALL(release_stream, ¶ms); - - return params.result; -} - -static DWORD WINAPI timer_thread(void *user) -{ - struct timer_loop_params params; - struct ACImpl *This = user; - - params.stream = This->stream; - OSS_CALL(timer_loop, ¶ms); - - return 0; -} - -static void set_device_guid(EDataFlow flow, HKEY drv_key, const WCHAR *key_name, - GUID *guid) -{ - HKEY key; - BOOL opened = FALSE; - LONG lr; - - if(!drv_key){ - lr = RegCreateKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, NULL, 0, KEY_WRITE, - NULL, &drv_key, NULL); - if(lr != ERROR_SUCCESS){ - ERR("RegCreateKeyEx(drv_key) failed: %lu\n", lr); - return; - } - opened = TRUE; - } - - lr = RegCreateKeyExW(drv_key, key_name, 0, NULL, 0, KEY_WRITE, - NULL, &key, NULL); - if(lr != ERROR_SUCCESS){ - ERR("RegCreateKeyEx(%s) failed: %lu\n", wine_dbgstr_w(key_name), lr); - goto exit; - } - - lr = RegSetValueExW(key, guidW, 0, REG_BINARY, (BYTE*)guid, - sizeof(GUID)); - if(lr != ERROR_SUCCESS) - ERR("RegSetValueEx(%s\\guid) failed: %lu\n", wine_dbgstr_w(key_name), lr); - - RegCloseKey(key); -exit: - if(opened) - RegCloseKey(drv_key); -} - -static void get_device_guid(EDataFlow flow, const char *device, GUID *guid) -{ - HKEY key = NULL, dev_key; - DWORD type, size = sizeof(*guid); - WCHAR key_name[256]; - - if(flow == eCapture) - key_name[0] = '1'; - else - key_name[0] = '0'; - key_name[1] = ','; - MultiByteToWideChar(CP_UNIXCP, 0, device, -1, key_name + 2, ARRAY_SIZE(key_name) - 2); - - if(RegOpenKeyExW(HKEY_CURRENT_USER, drv_key_devicesW, 0, KEY_WRITE|KEY_READ, &key) == ERROR_SUCCESS){ - if(RegOpenKeyExW(key, key_name, 0, KEY_READ, &dev_key) == ERROR_SUCCESS){ - if(RegQueryValueExW(dev_key, guidW, 0, &type, - (BYTE*)guid, &size) == ERROR_SUCCESS){ - if(type == REG_BINARY){ - RegCloseKey(dev_key); - RegCloseKey(key); - return; - } - ERR("Invalid type for device %s GUID: %lu; ignoring and overwriting\n", - wine_dbgstr_w(key_name), type); - } - RegCloseKey(dev_key); - } - } - - CoCreateGuid(guid); - - set_device_guid(flow, key, key_name, guid); - - if(key) - RegCloseKey(key); -} - -static void set_stream_volumes(ACImpl *This) -{ - struct set_volumes_params params; - - params.stream = This->stream; - params.master_volume = (This->session->mute ? 0.0f : This->session->master_vol); - params.volumes = This->vols; - params.session_volumes = This->session->channel_vols; - params.channel = 0; - OSS_CALL(set_volumes, ¶ms); -} - -static const OSSDevice *get_ossdevice_from_guid(const GUID *guid) -{ - OSSDevice *dev_item; - LIST_FOR_EACH_ENTRY(dev_item, &g_devices, OSSDevice, entry) - if(IsEqualGUID(guid, &dev_item->guid)) - return dev_item; - return NULL; -} - -static void device_add(OSSDevice *oss_dev) -{ - if(get_ossdevice_from_guid(&oss_dev->guid)) /* already in list */ - HeapFree(GetProcessHeap(), 0, oss_dev); - else - list_add_tail(&g_devices, &oss_dev->entry); -} - -HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids_out, GUID **guids_out, - UINT *num, UINT *def_index) -{ - struct get_endpoint_ids_params params; - GUID *guids = NULL; - WCHAR **ids = NULL; - unsigned int i; - - TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index); - - params.flow = flow; - params.size = 1000; - params.endpoints = NULL; - do{ - HeapFree(GetProcessHeap(), 0, params.endpoints); - params.endpoints = HeapAlloc(GetProcessHeap(), 0, params.size); - OSS_CALL(get_endpoint_ids, ¶ms); - }while(params.result == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)); - - if(FAILED(params.result)) goto end; - - ids = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, params.num * sizeof(*ids)); - guids = HeapAlloc(GetProcessHeap(), 0, params.num * sizeof(*guids)); - if(!ids || !guids){ - params.result = E_OUTOFMEMORY; - goto end; - } - - for(i = 0; i < params.num; i++){ - WCHAR *name = (WCHAR *)((char *)params.endpoints + params.endpoints[i].name); - char *device = (char *)params.endpoints + params.endpoints[i].device; - unsigned int name_size = (wcslen(name) + 1) * sizeof(WCHAR); - unsigned int dev_size = strlen(device) + 1; - OSSDevice *oss_dev; - - ids[i] = HeapAlloc(GetProcessHeap(), 0, name_size); - oss_dev = HeapAlloc(GetProcessHeap(), 0, offsetof(OSSDevice, devnode[dev_size])); - if(!ids[i] || !oss_dev){ - HeapFree(GetProcessHeap(), 0, oss_dev); - params.result = E_OUTOFMEMORY; - goto end; - } - memcpy(ids[i], name, name_size); - get_device_guid(flow, device, guids + i); - - oss_dev->flow = flow; - oss_dev->guid = guids[i]; - memcpy(oss_dev->devnode, device, dev_size); - device_add(oss_dev); - } - *def_index = params.default_idx; - -end: - HeapFree(GetProcessHeap(), 0, params.endpoints); - if(FAILED(params.result)){ - HeapFree(GetProcessHeap(), 0, guids); - if(ids){ - for(i = 0; i < params.num; i++) - HeapFree(GetProcessHeap(), 0, ids[i]); - HeapFree(GetProcessHeap(), 0, ids); - } - }else{ - *ids_out = ids; - *guids_out = guids; - *num = params.num; - } - - return params.result; -} - -HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, - IAudioClient **out) -{ - ACImpl *This; - const OSSDevice *oss_dev; - HRESULT hr; - int len; - - TRACE("%s %p %p\n", debugstr_guid(guid), dev, out); - - oss_dev = get_ossdevice_from_guid(guid); - if(!oss_dev){ - WARN("Unknown GUID: %s\n", debugstr_guid(guid)); - return AUDCLNT_E_DEVICE_INVALIDATED; - } - len = strlen(oss_dev->devnode); - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, offsetof(ACImpl, devnode[len + 1])); - if(!This) - return E_OUTOFMEMORY; - - hr = CoCreateFreeThreadedMarshaler((IUnknown *)&This->IAudioClient3_iface, &This->pUnkFTMarshal); - if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, This); - return hr; - } - - This->dataflow = oss_dev->flow; - strcpy(This->devnode, oss_dev->devnode); - - This->IAudioClient3_iface.lpVtbl = &AudioClient3_Vtbl; - This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl; - This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl; - This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl; - This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl; - This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl; - - This->parent = dev; - IMMDevice_AddRef(This->parent); - - *out = (IAudioClient *)&This->IAudioClient3_iface; - IAudioClient3_AddRef(&This->IAudioClient3_iface); - - return S_OK; -} - -static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient3 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioClient) || - IsEqualIID(riid, &IID_IAudioClient2) || - IsEqualIID(riid, &IID_IAudioClient3)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClient_AddRef(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioClient_Release(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - ULONG ref; - - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref){ - IAudioClient3_Stop(iface); - IMMDevice_Release(This->parent); - IUnknown_Release(This->pUnkFTMarshal); - if(This->session){ - EnterCriticalSection(&g_sessions_lock); - list_remove(&This->entry); - LeaveCriticalSection(&g_sessions_lock); - } - HeapFree(GetProcessHeap(), 0, This->vols); - if(This->stream) - stream_release(This->stream, This->timer_thread); - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static void dump_fmt(const WAVEFORMATEX *fmt) -{ - TRACE("wFormatTag: 0x%x (", fmt->wFormatTag); - switch(fmt->wFormatTag){ - case WAVE_FORMAT_PCM: - TRACE("WAVE_FORMAT_PCM"); - break; - case WAVE_FORMAT_IEEE_FLOAT: - TRACE("WAVE_FORMAT_IEEE_FLOAT"); - break; - case WAVE_FORMAT_EXTENSIBLE: - TRACE("WAVE_FORMAT_EXTENSIBLE"); - break; - default: - TRACE("Unknown"); - break; - } - TRACE(")\n"); - - TRACE("nChannels: %u\n", fmt->nChannels); - TRACE("nSamplesPerSec: %lu\n", fmt->nSamplesPerSec); - TRACE("nAvgBytesPerSec: %lu\n", fmt->nAvgBytesPerSec); - TRACE("nBlockAlign: %u\n", fmt->nBlockAlign); - TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample); - TRACE("cbSize: %u\n", fmt->cbSize); - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt; - TRACE("dwChannelMask: %08lx\n", fmtex->dwChannelMask); - TRACE("Samples: %04x\n", fmtex->Samples.wReserved); - TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat)); - } -} - -static void session_init_vols(AudioSession *session, UINT channels) -{ - if(session->channel_count < channels){ - UINT i; - - if(session->channel_vols) - session->channel_vols = HeapReAlloc(GetProcessHeap(), 0, - session->channel_vols, sizeof(float) * channels); - else - session->channel_vols = HeapAlloc(GetProcessHeap(), 0, - sizeof(float) * channels); - if(!session->channel_vols) - return; - - for(i = session->channel_count; i < channels; ++i) - session->channel_vols[i] = 1.f; - - session->channel_count = channels; - } -} - -static AudioSession *create_session(const GUID *guid, IMMDevice *device, - UINT num_channels) -{ - AudioSession *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession)); - if(!ret) - return NULL; - - memcpy(&ret->guid, guid, sizeof(GUID)); - - ret->device = device; - - list_init(&ret->clients); - - list_add_head(&g_sessions, &ret->entry); - - session_init_vols(ret, num_channels); - - ret->master_vol = 1.f; - - return ret; -} - -/* if channels == 0, then this will return or create a session with - * matching dataflow and GUID. otherwise, channels must also match */ -static HRESULT get_audio_session(const GUID *sessionguid, - IMMDevice *device, UINT channels, AudioSession **out) -{ - AudioSession *session; - - if(!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)){ - *out = create_session(&GUID_NULL, device, channels); - if(!*out) - return E_OUTOFMEMORY; - - return S_OK; - } - - *out = NULL; - LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry){ - if(session->device == device && - IsEqualGUID(sessionguid, &session->guid)){ - session_init_vols(session, channels); - *out = session; - break; - } - } - - if(!*out){ - *out = create_session(sessionguid, device, channels); - if(!*out) - return E_OUTOFMEMORY; - } - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Initialize(IAudioClient3 *iface, - AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration, - REFERENCE_TIME period, const WAVEFORMATEX *fmt, - const GUID *sessionguid) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct create_stream_params params; - stream_handle stream; - unsigned int i; - - TRACE("(%p)->(%x, %lx, %s, %s, %p, %s)\n", This, mode, flags, - wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid)); - - if(!fmt) - return E_POINTER; - - dump_fmt(fmt); - - if(mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) - return E_INVALIDARG; - - if(flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS | - AUDCLNT_STREAMFLAGS_LOOPBACK | - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | - AUDCLNT_STREAMFLAGS_NOPERSIST | - AUDCLNT_STREAMFLAGS_RATEADJUST | - AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED | - AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | - AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)){ - FIXME("Unknown flags: %08lx\n", flags); - return E_INVALIDARG; - } - - if(mode == AUDCLNT_SHAREMODE_SHARED){ - period = DefaultPeriod; - if( duration < 3 * period) - duration = 3 * period; - }else{ - if(!period) - period = DefaultPeriod; /* not minimum */ - if(period < MinimumPeriod || period > 5000000) - return AUDCLNT_E_INVALID_DEVICE_PERIOD; - if(duration > 20000000) /* the smaller the period, the lower this limit */ - return AUDCLNT_E_BUFFER_SIZE_ERROR; - if(flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK){ - if(duration != period) - return AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL; - FIXME("EXCLUSIVE mode with EVENTCALLBACK\n"); - return AUDCLNT_E_DEVICE_IN_USE; - }else{ - if( duration < 8 * period) - duration = 8 * period; /* may grow above 2s */ - } - } - - EnterCriticalSection(&g_sessions_lock); - - if(This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_ALREADY_INITIALIZED; - } - - params.name = NULL; - params.device = This->devnode; - params.flow = This->dataflow; - params.share = mode; - params.flags = flags; - params.duration = duration; - params.period = period; - params.fmt = fmt; - params.channel_count = NULL; - params.stream = &stream; - - OSS_CALL(create_stream, ¶ms); - if(FAILED(params.result)){ - LeaveCriticalSection(&g_sessions_lock); - return params.result; - } - - This->channel_count = fmt->nChannels; - This->vols = HeapAlloc(GetProcessHeap(), 0, This->channel_count * sizeof(float)); - if(!This->vols){ - params.result = E_OUTOFMEMORY; - goto exit; - } - for(i = 0; i < This->channel_count; ++i) - This->vols[i] = 1.f; - - params.result = get_audio_session(sessionguid, This->parent, This->channel_count, - &This->session); - -exit: - if(FAILED(params.result)){ - stream_release(stream, NULL); - HeapFree(GetProcessHeap(), 0, This->vols); - This->vols = NULL; - } else { - list_add_tail(&This->session->clients, &This->entry); - This->stream = stream; - set_stream_volumes(This); - } - - LeaveCriticalSection(&g_sessions_lock); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient3 *iface, - UINT32 *frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_buffer_size_params params; - - TRACE("(%p)->(%p)\n", This, frames); - - if(!frames) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.frames = frames; - - OSS_CALL(get_buffer_size, ¶ms); - TRACE("buffer size: %u\n", *frames); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient3 *iface, - REFERENCE_TIME *latency) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_latency_params params; - - TRACE("(%p)->(%p)\n", This, latency); - - if(!latency) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.latency = latency; - OSS_CALL(get_latency, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient3 *iface, - UINT32 *numpad) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_current_padding_params params; - - TRACE("(%p)->(%p)\n", This, numpad); - - if(!numpad) - return E_POINTER; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.padding = numpad; - OSS_CALL(get_current_padding, ¶ms); - TRACE("padding: %u\n", *numpad); - - return params.result; -} - -static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient3 *iface, - AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt, - WAVEFORMATEX **out) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct is_format_supported_params params; - - TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out); - if(fmt) dump_fmt(fmt); - - params.device = This->devnode; - params.flow = This->dataflow; - params.share = mode; - params.fmt_in = fmt; - params.fmt_out = NULL; - - if(out){ - *out = NULL; - if(mode == AUDCLNT_SHAREMODE_SHARED) - params.fmt_out = CoTaskMemAlloc(sizeof(*params.fmt_out)); - } - OSS_CALL(is_format_supported, ¶ms); - - if(params.result == S_FALSE) - *out = ¶ms.fmt_out->Format; - else - CoTaskMemFree(params.fmt_out); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient3 *iface, - WAVEFORMATEX **pwfx) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct get_mix_format_params params; - - TRACE("(%p)->(%p)\n", This, pwfx); - - if(!pwfx) - return E_POINTER; - *pwfx = NULL; - - params.device = This->devnode; - params.flow = This->dataflow; - params.fmt = CoTaskMemAlloc(sizeof(WAVEFORMATEXTENSIBLE)); - if(!params.fmt) - return E_OUTOFMEMORY; - - OSS_CALL(get_mix_format, ¶ms); - - if(SUCCEEDED(params.result)){ - *pwfx = ¶ms.fmt->Format; - dump_fmt(*pwfx); - } else - CoTaskMemFree(params.fmt); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient3 *iface, - REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod); - - if(!defperiod && !minperiod) - return E_POINTER; - - if(defperiod) - *defperiod = DefaultPeriod; - if(minperiod) - *minperiod = MinimumPeriod; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Start(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct start_params params; - - TRACE("(%p)\n", This); - - EnterCriticalSection(&g_sessions_lock); - - if(!This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_NOT_INITIALIZED; - } - - params.stream = This->stream; - OSS_CALL(start, ¶ms); - - if(SUCCEEDED(params.result) && !This->timer_thread){ - This->timer_thread = CreateThread(NULL, 0, timer_thread, This, 0, NULL); - SetThreadPriority(This->timer_thread, THREAD_PRIORITY_TIME_CRITICAL); - } - - LeaveCriticalSection(&g_sessions_lock); - - return params.result; -} - -static HRESULT WINAPI AudioClient_Stop(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct stop_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - OSS_CALL(stop, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_Reset(IAudioClient3 *iface) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct reset_params params; - - TRACE("(%p)\n", This); - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - OSS_CALL(reset, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient3 *iface, - HANDLE event) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - struct set_event_handle_params params; - - TRACE("(%p)->(%p)\n", This, event); - - if(!event) - return E_INVALIDARG; - - if(!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - - params.stream = This->stream; - params.event = event; - OSS_CALL(set_event_handle, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClient_GetService(IAudioClient3 *iface, REFIID riid, - void **ppv) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - EnterCriticalSection(&g_sessions_lock); - - if(!This->stream){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_NOT_INITIALIZED; - } - - if(IsEqualIID(riid, &IID_IAudioRenderClient)){ - if(This->dataflow != eRender){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - } - IAudioRenderClient_AddRef(&This->IAudioRenderClient_iface); - *ppv = &This->IAudioRenderClient_iface; - }else if(IsEqualIID(riid, &IID_IAudioCaptureClient)){ - if(This->dataflow != eCapture){ - LeaveCriticalSection(&g_sessions_lock); - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - } - IAudioCaptureClient_AddRef(&This->IAudioCaptureClient_iface); - *ppv = &This->IAudioCaptureClient_iface; - }else if(IsEqualIID(riid, &IID_IAudioClock)){ - IAudioClock_AddRef(&This->IAudioClock_iface); - *ppv = &This->IAudioClock_iface; - }else if(IsEqualIID(riid, &IID_IAudioStreamVolume)){ - IAudioStreamVolume_AddRef(&This->IAudioStreamVolume_iface); - *ppv = &This->IAudioStreamVolume_iface; - }else if(IsEqualIID(riid, &IID_IAudioSessionControl)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - IAudioSessionControl2_AddRef(&This->session_wrapper->IAudioSessionControl2_iface); - - *ppv = &This->session_wrapper->IAudioSessionControl2_iface; - }else if(IsEqualIID(riid, &IID_IChannelAudioVolume)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - IChannelAudioVolume_AddRef(&This->session_wrapper->IChannelAudioVolume_iface); - - *ppv = &This->session_wrapper->IChannelAudioVolume_iface; - }else if(IsEqualIID(riid, &IID_ISimpleAudioVolume)){ - if(!This->session_wrapper){ - This->session_wrapper = AudioSessionWrapper_Create(This); - if(!This->session_wrapper){ - LeaveCriticalSection(&g_sessions_lock); - return E_OUTOFMEMORY; - } - }else - ISimpleAudioVolume_AddRef(&This->session_wrapper->ISimpleAudioVolume_iface); - - *ppv = &This->session_wrapper->ISimpleAudioVolume_iface; - } - - if(*ppv){ - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - - LeaveCriticalSection(&g_sessions_lock); - - FIXME("stub %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static HRESULT WINAPI AudioClient_IsOffloadCapable(IAudioClient3 *iface, - AUDIO_STREAM_CATEGORY category, BOOL *offload_capable) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - TRACE("(%p)->(0x%x, %p)\n", This, category, offload_capable); - - if(!offload_capable) - return E_INVALIDARG; - - *offload_capable = FALSE; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_SetClientProperties(IAudioClient3 *iface, - const AudioClientProperties *prop) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - const Win8AudioClientProperties *legacy_prop = (const Win8AudioClientProperties *)prop; - - TRACE("(%p)->(%p)\n", This, prop); - - if(!legacy_prop) - return E_POINTER; - - if(legacy_prop->cbSize == sizeof(AudioClientProperties)){ - TRACE("{ bIsOffload: %u, eCategory: 0x%x, Options: 0x%x }\n", - legacy_prop->bIsOffload, - legacy_prop->eCategory, - prop->Options); - }else if(legacy_prop->cbSize == sizeof(Win8AudioClientProperties)){ - TRACE("{ bIsOffload: %u, eCategory: 0x%x }\n", - legacy_prop->bIsOffload, - legacy_prop->eCategory); - }else{ - WARN("Unsupported Size = %d\n", legacy_prop->cbSize); - return E_INVALIDARG; - } - - - if(legacy_prop->bIsOffload) - return AUDCLNT_E_ENDPOINT_OFFLOAD_NOT_CAPABLE; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_GetBufferSizeLimits(IAudioClient3 *iface, - const WAVEFORMATEX *format, BOOL event_driven, REFERENCE_TIME *min_duration, - REFERENCE_TIME *max_duration) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %u, %p, %p)\n", This, format, event_driven, min_duration, max_duration); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_GetSharedModeEnginePeriod(IAudioClient3 *iface, - const WAVEFORMATEX *format, UINT32 *default_period_frames, UINT32 *unit_period_frames, - UINT32 *min_period_frames, UINT32 *max_period_frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %p, %p, %p, %p)\n", This, format, default_period_frames, unit_period_frames, - min_period_frames, max_period_frames); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_GetCurrentSharedModeEnginePeriod(IAudioClient3 *iface, - WAVEFORMATEX **cur_format, UINT32 *cur_period_frames) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(%p, %p)\n", This, cur_format, cur_period_frames); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioClient_InitializeSharedAudioStream(IAudioClient3 *iface, - DWORD flags, UINT32 period_frames, const WAVEFORMATEX *format, - const GUID *session_guid) -{ - ACImpl *This = impl_from_IAudioClient3(iface); - - FIXME("(%p)->(0x%lx, %u, %p, %s)\n", This, flags, period_frames, format, debugstr_guid(session_guid)); - - return E_NOTIMPL; -} - -static const IAudioClient3Vtbl AudioClient3_Vtbl = -{ - AudioClient_QueryInterface, - AudioClient_AddRef, - AudioClient_Release, - AudioClient_Initialize, - AudioClient_GetBufferSize, - AudioClient_GetStreamLatency, - AudioClient_GetCurrentPadding, - AudioClient_IsFormatSupported, - AudioClient_GetMixFormat, - AudioClient_GetDevicePeriod, - AudioClient_Start, - AudioClient_Stop, - AudioClient_Reset, - AudioClient_SetEventHandle, - AudioClient_GetService, - AudioClient_IsOffloadCapable, - AudioClient_SetClientProperties, - AudioClient_GetBufferSizeLimits, - AudioClient_GetSharedModeEnginePeriod, - AudioClient_GetCurrentSharedModeEnginePeriod, - AudioClient_InitializeSharedAudioStream, -}; - -static HRESULT WINAPI AudioRenderClient_QueryInterface( - IAudioRenderClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioRenderClient)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface, - UINT32 frames, BYTE **data) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - struct get_render_buffer_params params; - - TRACE("(%p)->(%u, %p)\n", This, frames, data); - - if(!data) - return E_POINTER; - - *data = NULL; - - params.stream = This->stream; - params.frames = frames; - params.data = data; - OSS_CALL(get_render_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioRenderClient_ReleaseBuffer( - IAudioRenderClient *iface, UINT32 written_frames, DWORD flags) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - struct release_render_buffer_params params; - - TRACE("(%p)->(%u, %lx)\n", This, written_frames, flags); - - params.stream = This->stream; - params.written_frames = written_frames; - params.flags = flags; - OSS_CALL(release_render_buffer, ¶ms); - - return params.result; -} - -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = { - AudioRenderClient_QueryInterface, - AudioRenderClient_AddRef, - AudioRenderClient_Release, - AudioRenderClient_GetBuffer, - AudioRenderClient_ReleaseBuffer -}; - -static HRESULT WINAPI AudioCaptureClient_QueryInterface( - IAudioCaptureClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioCaptureClient)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->pUnkFTMarshal, riid, ppv); - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface, - BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos, - UINT64 *qpcpos) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct get_capture_buffer_params params; - - TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags, - devpos, qpcpos); - - if(!data) - return E_POINTER; - - *data = NULL; - - if(!frames || !flags) - return E_POINTER; - - params.stream = This->stream; - params.data = data; - params.frames = frames; - params.flags = (UINT*)flags; - params.devpos = devpos; - params.qpcpos = qpcpos; - OSS_CALL(get_capture_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer( - IAudioCaptureClient *iface, UINT32 done) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct release_capture_buffer_params params; - - TRACE("(%p)->(%u)\n", This, done); - - params.stream = This->stream; - params.done = done; - OSS_CALL(release_capture_buffer, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize( - IAudioCaptureClient *iface, UINT32 *frames) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - struct get_next_packet_size_params params; - - TRACE("(%p)->(%p)\n", This, frames); - - if(!frames) - return E_POINTER; - - params.stream = This->stream; - params.frames = frames; - OSS_CALL(get_next_packet_size, ¶ms); - - return params.result; -} - -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl = -{ - AudioCaptureClient_QueryInterface, - AudioCaptureClient_AddRef, - AudioCaptureClient_Release, - AudioCaptureClient_GetBuffer, - AudioCaptureClient_ReleaseBuffer, - AudioCaptureClient_GetNextPacketSize -}; - -static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock)) - *ppv = iface; - else if(IsEqualIID(riid, &IID_IAudioClock2)) - *ppv = &This->IAudioClock2_iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioClock_Release(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq) -{ - ACImpl *This = impl_from_IAudioClock(iface); - struct get_frequency_params params; - - TRACE("(%p)->(%p)\n", This, freq); - - params.stream = This->stream; - params.freq = freq; - OSS_CALL(get_frequency, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos, - UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock(iface); - struct get_position_params params; - - TRACE("(%p)->(%p, %p)\n", This, pos, qpctime); - - if(!pos) - return E_POINTER; - - params.stream = This->stream; - params.device = FALSE; - params.pos = pos; - params.qpctime = qpctime; - OSS_CALL(get_position, ¶ms); - - return params.result; -} - -static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface, - DWORD *chars) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%p)\n", This, chars); - - if(!chars) - return E_POINTER; - - *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ; - - return S_OK; -} - -static const IAudioClockVtbl AudioClock_Vtbl = -{ - AudioClock_QueryInterface, - AudioClock_AddRef, - AudioClock_Release, - AudioClock_GetFrequency, - AudioClock_GetPosition, - AudioClock_GetCharacteristics -}; - -static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv); -} - -static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface, - UINT64 *pos, UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - - FIXME("(%p)->(%p, %p)\n", This, pos, qpctime); - - return E_NOTIMPL; -} - -static const IAudioClock2Vtbl AudioClock2_Vtbl = -{ - AudioClock2_QueryInterface, - AudioClock2_AddRef, - AudioClock2_Release, - AudioClock2_GetDevicePosition -}; - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client) -{ - AudioSessionWrapper *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(AudioSessionWrapper)); - if(!ret) - return NULL; - - ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl; - ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl; - ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl; - - ret->ref = 1; - - ret->client = client; - if(client){ - ret->session = client->session; - AudioClient_AddRef(&client->IAudioClient3_iface); - } - - return ret; -} - -static HRESULT WINAPI AudioSessionControl_QueryInterface( - IAudioSessionControl2 *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionControl) || - IsEqualIID(riid, &IID_IAudioSessionControl2)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref){ - if(This->client){ - EnterCriticalSection(&g_sessions_lock); - This->client->session_wrapper = NULL; - LeaveCriticalSection(&g_sessions_lock); - AudioClient_Release(&This->client->IAudioClient3_iface); - } - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface, - AudioSessionState *state) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - struct is_started_params params; - ACImpl *client; - - TRACE("(%p)->(%p)\n", This, state); - - if(!state) - return NULL_PTR_ERR; - - EnterCriticalSection(&g_sessions_lock); - - if(list_empty(&This->session->clients)){ - *state = AudioSessionStateExpired; - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - - LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry){ - params.stream = client->stream; - OSS_CALL(is_started, ¶ms); - if(params.result == S_OK){ - *state = AudioSessionStateActive; - LeaveCriticalSection(&g_sessions_lock); - return S_OK; - } - } - - LeaveCriticalSection(&g_sessions_lock); - - *state = AudioSessionStateInactive; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetDisplayName( - IAudioSessionControl2 *iface, WCHAR **name) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, name); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetDisplayName( - IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetIconPath( - IAudioSessionControl2 *iface, WCHAR **path) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, path); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetIconPath( - IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetGroupingParam( - IAudioSessionControl2 *iface, GUID *group) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, group); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetGroupingParam( - IAudioSessionControl2 *iface, const GUID *group, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group), - debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetProcessId( - IAudioSessionControl2 *iface, DWORD *pid) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%p)\n", This, pid); - - if(!pid) - return E_POINTER; - - *pid = GetCurrentProcessId(); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession( - IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)\n", This); - - return S_FALSE; -} - -static HRESULT WINAPI AudioSessionControl_SetDuckingPreference( - IAudioSessionControl2 *iface, BOOL optout) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%d)\n", This, optout); - - return S_OK; -} - -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl = -{ - AudioSessionControl_QueryInterface, - AudioSessionControl_AddRef, - AudioSessionControl_Release, - AudioSessionControl_GetState, - AudioSessionControl_GetDisplayName, - AudioSessionControl_SetDisplayName, - AudioSessionControl_GetIconPath, - AudioSessionControl_SetIconPath, - AudioSessionControl_GetGroupingParam, - AudioSessionControl_SetGroupingParam, - AudioSessionControl_RegisterAudioSessionNotification, - AudioSessionControl_UnregisterAudioSessionNotification, - AudioSessionControl_GetSessionIdentifier, - AudioSessionControl_GetSessionInstanceIdentifier, - AudioSessionControl_GetProcessId, - AudioSessionControl_IsSystemSoundsSession, - AudioSessionControl_SetDuckingPreference -}; - -static HRESULT WINAPI SimpleAudioVolume_QueryInterface( - ISimpleAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_ISimpleAudioVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume( - ISimpleAudioVolume *iface, float level, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context)); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->master_vol = level; - - TRACE("OSS doesn't support setting volume\n"); - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume( - ISimpleAudioVolume *iface, float *level) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, level); - - if(!level) - return NULL_PTR_ERR; - - *level = session->master_vol; - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface, - BOOL mute, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context)); - - EnterCriticalSection(&g_sessions_lock); - - session->mute = mute; - - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface, - BOOL *mute) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, mute); - - if(!mute) - return NULL_PTR_ERR; - - *mute = This->session->mute; - - return S_OK; -} - -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl = -{ - SimpleAudioVolume_QueryInterface, - SimpleAudioVolume_AddRef, - SimpleAudioVolume_Release, - SimpleAudioVolume_SetMasterVolume, - SimpleAudioVolume_GetMasterVolume, - SimpleAudioVolume_SetMute, - SimpleAudioVolume_GetMute -}; - -static HRESULT WINAPI AudioStreamVolume_QueryInterface( - IAudioStreamVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioStreamVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient3_AddRef(&This->IAudioClient3_iface); -} - -static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient3_Release(&This->IAudioClient3_iface); -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelCount( - IAudioStreamVolume *iface, UINT32 *out) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%p)\n", This, out); - - if(!out) - return E_POINTER; - - *out = This->channel_count; - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_SetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%d, %f)\n", This, index, level); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(index >= This->channel_count) - return E_INVALIDARG; - - EnterCriticalSection(&g_sessions_lock); - - This->vols[index] = level; - - TRACE("OSS doesn't support setting volume\n"); - set_stream_volumes(This); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float *level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%d, %p)\n", This, index, level); - - if(!level) - return E_POINTER; - - if(index >= This->channel_count) - return E_INVALIDARG; - - *level = This->vols[index]; - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_SetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, const float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - int i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if(!levels) - return E_POINTER; - - if(count != This->channel_count) - return E_INVALIDARG; - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - This->vols[i] = levels[i]; - - TRACE("OSS doesn't support setting volume\n"); - set_stream_volumes(This); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI AudioStreamVolume_GetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - int i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if(!levels) - return E_POINTER; - - if(count != This->channel_count) - return E_INVALIDARG; - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - levels[i] = This->vols[i]; - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl = -{ - AudioStreamVolume_QueryInterface, - AudioStreamVolume_AddRef, - AudioStreamVolume_Release, - AudioStreamVolume_GetChannelCount, - AudioStreamVolume_SetChannelVolume, - AudioStreamVolume_GetChannelVolume, - AudioStreamVolume_SetAllVolumes, - AudioStreamVolume_GetAllVolumes -}; - -static HRESULT WINAPI ChannelAudioVolume_QueryInterface( - IChannelAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IChannelAudioVolume)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelCount( - IChannelAudioVolume *iface, UINT32 *out) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, out); - - if(!out) - return NULL_PTR_ERR; - - *out = session->channel_count; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float level, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - - TRACE("(%p)->(%d, %f, %s)\n", session, index, level, - wine_dbgstr_guid(context)); - - if(level < 0.f || level > 1.f) - return E_INVALIDARG; - - if(index >= session->channel_count) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - session->channel_vols[index] = level; - - TRACE("OSS doesn't support setting volume\n"); - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float *level) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%d, %p)\n", session, index, level); - - if(!level) - return NULL_PTR_ERR; - - if(index >= session->channel_count) - return E_INVALIDARG; - - *level = session->channel_vols[index]; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, const float *levels, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - ACImpl *client; - int i; - - TRACE("(%p)->(%d, %p, %s)\n", session, count, levels, - wine_dbgstr_guid(context)); - - if(!levels) - return NULL_PTR_ERR; - - if(count != session->channel_count) - return E_INVALIDARG; - - if(context) - FIXME("Notifications not supported yet\n"); - - EnterCriticalSection(&g_sessions_lock); - - for(i = 0; i < count; ++i) - session->channel_vols[i] = levels[i]; - - TRACE("OSS doesn't support setting volume\n"); - LIST_FOR_EACH_ENTRY(client, &session->clients, ACImpl, entry) - set_stream_volumes(client); - - LeaveCriticalSection(&g_sessions_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, float *levels) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - int i; - - TRACE("(%p)->(%d, %p)\n", session, count, levels); - - if(!levels) - return NULL_PTR_ERR; - - if(count != session->channel_count) - return E_INVALIDARG; - - for(i = 0; i < count; ++i) - levels[i] = session->channel_vols[i]; - - return S_OK; -} - -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl = -{ - ChannelAudioVolume_QueryInterface, - ChannelAudioVolume_AddRef, - ChannelAudioVolume_Release, - ChannelAudioVolume_GetChannelCount, - ChannelAudioVolume_SetChannelVolume, - ChannelAudioVolume_GetChannelVolume, - ChannelAudioVolume_SetAllVolumes, - ChannelAudioVolume_GetAllVolumes -}; - -static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface, - REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if(!ppv) - return E_POINTER; - *ppv = NULL; - - if(IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionManager) || - IsEqualIID(riid, &IID_IAudioSessionManager2)) - *ppv = iface; - if(*ppv){ - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %lu\n", This, ref); - if(!ref) - HeapFree(GetProcessHeap(), 0, This); - return ref; -} - -static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - IAudioSessionControl **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if(FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - ISimpleAudioVolume **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %lx, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if(FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if(!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = &wrapper->ISimpleAudioVolume_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator( - IAudioSessionManager2 *iface, IAudioSessionEnumerator **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, out); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification( - IAudioSessionManager2 *iface, const WCHAR *session_id, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification( - IAudioSessionManager2 *iface, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl = -{ - AudioSessionManager_QueryInterface, - AudioSessionManager_AddRef, - AudioSessionManager_Release, - AudioSessionManager_GetAudioSessionControl, - AudioSessionManager_GetSimpleAudioVolume, - AudioSessionManager_GetSessionEnumerator, - AudioSessionManager_RegisterSessionNotification, - AudioSessionManager_UnregisterSessionNotification, - AudioSessionManager_RegisterDuckNotification, - AudioSessionManager_UnregisterDuckNotification -}; - -HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device, - IAudioSessionManager2 **out) -{ - SessionMgr *This; - - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr)); - if(!This) - return E_OUTOFMEMORY; - - This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl; - This->device = device; - This->ref = 1; - - *out = &This->IAudioSessionManager2_iface; - - return S_OK; -} diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/oss.c b/pkgs/osu-wine/audio-revert/wineoss.drv/oss.c deleted file mode 100644 index 4bc8bc2..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/oss.c +++ /dev/null @@ -1,2055 +0,0 @@ -/* - * OSS driver (unixlib) - * - * Copyright 2011 Andrew Eikum for CodeWeavers - * 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#if 0 -#pragma makedep unix -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "winternl.h" -#include "initguid.h" -#include "audioclient.h" -#include "mmddk.h" - -#include "wine/debug.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -struct oss_stream -{ - WAVEFORMATEX *fmt; - EDataFlow flow; - UINT flags; - AUDCLNT_SHAREMODE share; - HANDLE event; - - int fd; - - BOOL playing, mute, please_quit; - UINT64 written_frames, last_pos_frames; - UINT32 period_frames, bufsize_frames, held_frames, tmp_buffer_frames, in_oss_frames; - UINT32 oss_bufsize_bytes, lcl_offs_frames; /* offs into local_buffer where valid data starts */ - REFERENCE_TIME period; - - BYTE *local_buffer, *tmp_buffer; - INT32 getbuf_last; /* <0 when using tmp_buffer */ - - pthread_mutex_t lock; -}; - -WINE_DEFAULT_DEBUG_CHANNEL(oss); - -/* copied from kernelbase */ -static int muldiv( int a, int b, int c ) -{ - LONGLONG ret; - - if (!c) return -1; - - /* We want to deal with a positive divisor to simplify the logic. */ - if (c < 0) - { - a = -a; - c = -c; - } - - /* If the result is positive, we "add" to round. else, we subtract to round. */ - if ((a < 0 && b < 0) || (a >= 0 && b >= 0)) - ret = (((LONGLONG)a * b) + (c / 2)) / c; - else - ret = (((LONGLONG)a * b) - (c / 2)) / c; - - if (ret > 2147483647 || ret < -2147483647) return -1; - return ret; -} - -static void oss_lock(struct oss_stream *stream) -{ - pthread_mutex_lock(&stream->lock); -} - -static void oss_unlock(struct oss_stream *stream) -{ - pthread_mutex_unlock(&stream->lock); -} - -static NTSTATUS oss_unlock_result(struct oss_stream *stream, - HRESULT *result, HRESULT value) -{ - *result = value; - oss_unlock(stream); - return STATUS_SUCCESS; -} - -static struct oss_stream *handle_get_stream(stream_handle h) -{ - return (struct oss_stream *)(UINT_PTR)h; -} - -static NTSTATUS oss_test_connect(void *args) -{ - struct test_connect_params *params = args; - int mixer_fd; - oss_sysinfo sysinfo; - - /* Attempt to determine if we are running on OSS or ALSA's OSS - * compatibility layer. There is no official way to do that, so just check - * for validity as best as possible, without rejecting valid OSS - * implementations. */ - - mixer_fd = open("/dev/mixer", O_RDONLY, 0); - if(mixer_fd < 0){ - TRACE("Priority_Unavailable: open failed\n"); - params->priority = Priority_Unavailable; - return STATUS_SUCCESS; - } - - sysinfo.version[0] = 0xFF; - sysinfo.versionnum = ~0; - if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){ - TRACE("Priority_Unavailable: ioctl failed\n"); - close(mixer_fd); - params->priority = Priority_Unavailable; - return STATUS_SUCCESS; - } - - close(mixer_fd); - - if(sysinfo.version[0] < '4' || sysinfo.version[0] > '9'){ - TRACE("Priority_Low: sysinfo.version[0]: %x\n", sysinfo.version[0]); - params->priority = Priority_Low; - return STATUS_SUCCESS; - } - if(sysinfo.versionnum & 0x80000000){ - TRACE("Priority_Low: sysinfo.versionnum: %x\n", sysinfo.versionnum); - params->priority = Priority_Low; - return STATUS_SUCCESS; - } - - TRACE("Priority_Preferred: Seems like valid OSS!\n"); - - params->priority = Priority_Preferred; - return STATUS_SUCCESS; -} - -/* dst must be large enough to hold devnode */ -static void oss_clean_devnode(char *dest, const char *devnode) -{ - const char *dot, *slash; - size_t len; - - strcpy(dest, devnode); - dot = strrchr(dest, '.'); - if(!dot) - return; - - slash = strrchr(dest, '/'); - if(slash && dot < slash) - return; - - len = dot - dest; - dest[len] = '\0'; -} - -static int open_device(const char *device, EDataFlow flow) -{ - int flags = ((flow == eRender) ? O_WRONLY : O_RDONLY) | O_NONBLOCK; - - return open(device, flags, 0); -} - -static void get_default_device(EDataFlow flow, char device[OSS_DEVNODE_SIZE]) -{ - int fd, err; - oss_audioinfo ai; - - device[0] = '\0'; - fd = open_device("/dev/dsp", flow); - if(fd < 0){ - WARN("Couldn't open default device!\n"); - return; - } - - ai.dev = -1; - if((err = ioctl(fd, SNDCTL_ENGINEINFO, &ai)) < 0){ - WARN("SNDCTL_ENGINEINFO failed: %d (%s)\n", err, strerror(errno)); - close(fd); - return; - } - close(fd); - - TRACE("Default devnode: %s\n", ai.devnode); - oss_clean_devnode(device, ai.devnode); - return; -} - -static NTSTATUS oss_get_endpoint_ids(void *args) -{ - struct get_endpoint_ids_params *params = args; - oss_sysinfo sysinfo; - oss_audioinfo ai; - static int print_once = 0; - static const WCHAR outW[] = {'O','u','t',':',' ',0}; - static const WCHAR inW[] = {'I','n',':',' ',0}; - struct endpoint_info - { - WCHAR name[ARRAY_SIZE(ai.name) + ARRAY_SIZE(outW)]; - char device[OSS_DEVNODE_SIZE]; - } *info; - unsigned int i, j, num, needed, name_len, device_len, offset, default_idx = 0; - char default_device[OSS_DEVNODE_SIZE]; - struct endpoint *endpoint; - int mixer_fd; - - mixer_fd = open("/dev/mixer", O_RDONLY, 0); - if(mixer_fd < 0){ - ERR("OSS /dev/mixer doesn't seem to exist\n"); - params->result = AUDCLNT_E_SERVICE_NOT_RUNNING; - return STATUS_SUCCESS; - } - - if(ioctl(mixer_fd, SNDCTL_SYSINFO, &sysinfo) < 0){ - close(mixer_fd); - if(errno == EINVAL){ - ERR("OSS version too old, need at least OSSv4\n"); - params->result = AUDCLNT_E_SERVICE_NOT_RUNNING; - return STATUS_SUCCESS; - } - - ERR("Error getting SNDCTL_SYSINFO: %d (%s)\n", errno, strerror(errno)); - params->result = E_FAIL; - return STATUS_SUCCESS; - } - - if(!print_once){ - TRACE("OSS sysinfo:\n"); - TRACE("product: %s\n", sysinfo.product); - TRACE("version: %s\n", sysinfo.version); - TRACE("versionnum: %x\n", sysinfo.versionnum); - TRACE("numaudios: %d\n", sysinfo.numaudios); - TRACE("nummixers: %d\n", sysinfo.nummixers); - TRACE("numcards: %d\n", sysinfo.numcards); - TRACE("numaudioengines: %d\n", sysinfo.numaudioengines); - print_once = 1; - } - - if(sysinfo.numaudios <= 0){ - WARN("No audio devices!\n"); - close(mixer_fd); - params->result = AUDCLNT_E_SERVICE_NOT_RUNNING; - return STATUS_SUCCESS; - } - - info = malloc(sysinfo.numaudios * sizeof(*info)); - if(!info){ - close(mixer_fd); - params->result = E_OUTOFMEMORY; - return STATUS_SUCCESS; - } - - get_default_device(params->flow, default_device); - - num = 0; - for(i = 0; i < sysinfo.numaudios; ++i){ - char devnode[OSS_DEVNODE_SIZE]; - int fd, prefix_len; - const WCHAR *prefix; - - memset(&ai, 0, sizeof(ai)); - ai.dev = i; - if(ioctl(mixer_fd, SNDCTL_AUDIOINFO, &ai) < 0){ - WARN("Error getting AUDIOINFO for dev %d: %d (%s)\n", i, errno, - strerror(errno)); - continue; - } - - oss_clean_devnode(devnode, ai.devnode); - - /* check for duplicates */ - for(j = 0; j < num; j++) - if(!strcmp(devnode, info[j].device)) - break; - if(j < num) - continue; - - fd = open_device(devnode, params->flow); - if(fd < 0){ - WARN("Opening device \"%s\" failed, pretending it doesn't exist: %d (%s)\n", - devnode, errno, strerror(errno)); - continue; - } - close(fd); - - if((params->flow == eCapture && !(ai.caps & PCM_CAP_INPUT)) || - (params->flow == eRender && !(ai.caps & PCM_CAP_OUTPUT))) - continue; - - strcpy(info[num].device, devnode); - - if(params->flow == eRender){ - prefix = outW; - prefix_len = ARRAY_SIZE(outW) - 1; - }else{ - prefix = inW; - prefix_len = ARRAY_SIZE(inW) - 1; - } - memcpy(info[num].name, prefix, prefix_len * sizeof(WCHAR)); - ntdll_umbstowcs(ai.name, strlen(ai.name) + 1, info[num].name + prefix_len, - ARRAY_SIZE(info[num].name) - prefix_len); - if(!strcmp(default_device, info[num].device)) - default_idx = num; - num++; - } - close(mixer_fd); - - offset = needed = num * sizeof(*params->endpoints); - endpoint = params->endpoints; - - for(i = 0; i < num; i++){ - name_len = wcslen(info[i].name) + 1; - device_len = strlen(info[i].device) + 1; - needed += name_len * sizeof(WCHAR) + ((device_len + 1) & ~1); - - if(needed <= params->size){ - endpoint->name = offset; - memcpy((char *)params->endpoints + offset, info[i].name, name_len * sizeof(WCHAR)); - offset += name_len * sizeof(WCHAR); - endpoint->device = offset; - memcpy((char *)params->endpoints + offset, info[i].device, device_len); - offset += (device_len + 1) & ~1; - endpoint++; - } - } - free(info); - - params->num = num; - params->default_idx = default_idx; - - if(needed > params->size){ - params->size = needed; - params->result = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - } else - params->result = S_OK; - - return STATUS_SUCCESS; -} - -static UINT get_channel_mask(unsigned int channels) -{ - switch(channels){ - case 0: - return 0; - case 1: - return KSAUDIO_SPEAKER_MONO; - case 2: - return KSAUDIO_SPEAKER_STEREO; - case 3: - return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY; - case 4: - return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */ - case 5: - return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY; - case 6: - return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */ - case 7: - return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER; - case 8: - return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */ - } - FIXME("Unknown speaker configuration: %u\n", channels); - return 0; -} - -static int get_oss_format(const WAVEFORMATEX *fmt) -{ - WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)fmt; - - if(fmt->wFormatTag == WAVE_FORMAT_PCM || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))){ - switch(fmt->wBitsPerSample){ - case 8: - return AFMT_U8; - case 16: - return AFMT_S16_LE; - case 24: - return AFMT_S24_LE; - case 32: - return AFMT_S32_LE; - } - return -1; - } - -#ifdef AFMT_FLOAT - if(fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))){ - if(fmt->wBitsPerSample != 32) - return -1; - - return AFMT_FLOAT; - } -#endif - - return -1; -} - -static WAVEFORMATEXTENSIBLE *clone_format(const WAVEFORMATEX *fmt) -{ - WAVEFORMATEXTENSIBLE *ret; - size_t size; - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - size = sizeof(WAVEFORMATEXTENSIBLE); - else - size = sizeof(WAVEFORMATEX); - - ret = malloc(size); - if(!ret) - return NULL; - - memcpy(ret, fmt, size); - - ret->Format.cbSize = size - sizeof(WAVEFORMATEX); - - return ret; -} - -static HRESULT setup_oss_device(AUDCLNT_SHAREMODE share, int fd, - const WAVEFORMATEX *fmt, WAVEFORMATEXTENSIBLE *out) -{ - const WAVEFORMATEXTENSIBLE *fmtex = (const WAVEFORMATEXTENSIBLE *)fmt; - int tmp, oss_format; - double tenth; - HRESULT ret = S_OK; - WAVEFORMATEXTENSIBLE *closest; - - tmp = oss_format = get_oss_format(fmt); - if(oss_format < 0) - return AUDCLNT_E_UNSUPPORTED_FORMAT; - if(ioctl(fd, SNDCTL_DSP_SETFMT, &tmp) < 0){ - WARN("SETFMT failed: %d (%s)\n", errno, strerror(errno)); - return E_FAIL; - } - if(tmp != oss_format){ - TRACE("Format unsupported by this OSS version: %x\n", oss_format); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - - if(fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - (fmtex->Format.nAvgBytesPerSec == 0 || - fmtex->Format.nBlockAlign == 0 || - fmtex->Samples.wValidBitsPerSample > fmtex->Format.wBitsPerSample)) - return E_INVALIDARG; - - if(fmt->nChannels == 0) - return AUDCLNT_E_UNSUPPORTED_FORMAT; - - closest = clone_format(fmt); - if(!closest) - return E_OUTOFMEMORY; - - tmp = fmt->nSamplesPerSec; - if(ioctl(fd, SNDCTL_DSP_SPEED, &tmp) < 0){ - WARN("SPEED failed: %d (%s)\n", errno, strerror(errno)); - free(closest); - return E_FAIL; - } - tenth = fmt->nSamplesPerSec * 0.1; - if(tmp > fmt->nSamplesPerSec + tenth || tmp < fmt->nSamplesPerSec - tenth){ - ret = S_FALSE; - closest->Format.nSamplesPerSec = tmp; - } - - tmp = fmt->nChannels; - if(ioctl(fd, SNDCTL_DSP_CHANNELS, &tmp) < 0){ - WARN("CHANNELS failed: %d (%s)\n", errno, strerror(errno)); - free(closest); - return E_FAIL; - } - if(tmp != fmt->nChannels){ - ret = S_FALSE; - closest->Format.nChannels = tmp; - } - - if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) - closest->dwChannelMask = get_channel_mask(closest->Format.nChannels); - - if(fmt->nBlockAlign != fmt->nChannels * fmt->wBitsPerSample / 8 || - fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec || - (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - fmtex->Samples.wValidBitsPerSample < fmtex->Format.wBitsPerSample)) - ret = S_FALSE; - - if(share == AUDCLNT_SHAREMODE_EXCLUSIVE && - fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE){ - if(fmtex->dwChannelMask == 0 || fmtex->dwChannelMask & SPEAKER_RESERVED) - ret = S_FALSE; - } - - if(ret == S_FALSE && !out) - ret = AUDCLNT_E_UNSUPPORTED_FORMAT; - - if(ret == S_FALSE && out){ - closest->Format.nBlockAlign = - closest->Format.nChannels * closest->Format.wBitsPerSample / 8; - closest->Format.nAvgBytesPerSec = - closest->Format.nBlockAlign * closest->Format.nSamplesPerSec; - if(closest->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) - closest->Samples.wValidBitsPerSample = closest->Format.wBitsPerSample; - memcpy(out, closest, closest->Format.cbSize + sizeof(WAVEFORMATEX)); - } - free(closest); - - TRACE("returning: %08x\n", (unsigned)ret); - return ret; -} - -static ULONG_PTR zero_bits(void) -{ -#ifdef _WIN64 - return !NtCurrentTeb()->WowTebOffset ? 0 : 0x7fffffff; -#else - return 0; -#endif -} - -static NTSTATUS oss_create_stream(void *args) -{ - struct create_stream_params *params = args; - WAVEFORMATEXTENSIBLE *fmtex; - struct oss_stream *stream; - oss_audioinfo ai; - SIZE_T size; - - stream = calloc(1, sizeof(*stream)); - if(!stream){ - params->result = E_OUTOFMEMORY; - return STATUS_SUCCESS; - } - - stream->flow = params->flow; - pthread_mutex_init(&stream->lock, NULL); - - stream->fd = open_device(params->device, params->flow); - if(stream->fd < 0){ - WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno)); - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - goto exit; - } - - ai.dev = -1; - if(ioctl(stream->fd, SNDCTL_ENGINEINFO, &ai) < 0){ - WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno)); - params->result = E_FAIL; - goto exit; - } - - TRACE("OSS audioinfo:\n"); - TRACE("devnode: %s\n", ai.devnode); - TRACE("name: %s\n", ai.name); - TRACE("busy: %x\n", ai.busy); - TRACE("caps: %x\n", ai.caps); - TRACE("iformats: %x\n", ai.iformats); - TRACE("oformats: %x\n", ai.oformats); - TRACE("enabled: %d\n", ai.enabled); - TRACE("min_rate: %d\n", ai.min_rate); - TRACE("max_rate: %d\n", ai.max_rate); - TRACE("min_channels: %d\n", ai.min_channels); - TRACE("max_channels: %d\n", ai.max_channels); - - params->result = setup_oss_device(params->share, stream->fd, params->fmt, NULL); - if(FAILED(params->result)) - goto exit; - - fmtex = clone_format(params->fmt); - if(!fmtex){ - params->result = E_OUTOFMEMORY; - goto exit; - } - stream->fmt = &fmtex->Format; - - stream->period = params->period; - stream->period_frames = muldiv(params->fmt->nSamplesPerSec, params->period, 10000000); - - stream->bufsize_frames = muldiv(params->duration, params->fmt->nSamplesPerSec, 10000000); - if(params->share == AUDCLNT_SHAREMODE_EXCLUSIVE) - stream->bufsize_frames -= stream->bufsize_frames % stream->period_frames; - size = stream->bufsize_frames * params->fmt->nBlockAlign; - if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, zero_bits(), - &size, MEM_COMMIT, PAGE_READWRITE)){ - params->result = E_OUTOFMEMORY; - goto exit; - } - - stream->share = params->share; - stream->flags = params->flags; - stream->oss_bufsize_bytes = 0; - -exit: - if(FAILED(params->result)){ - if(stream->fd >= 0) close(stream->fd); - if(stream->local_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE); - } - pthread_mutex_destroy(&stream->lock); - free(stream->fmt); - free(stream); - }else{ - *params->stream = (stream_handle)(UINT_PTR)stream; - } - - return STATUS_SUCCESS; -} - -static NTSTATUS oss_release_stream(void *args) -{ - struct release_stream_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - SIZE_T size; - - if(params->timer_thread){ - stream->please_quit = TRUE; - NtWaitForSingleObject(params->timer_thread, FALSE, NULL); - NtClose(params->timer_thread); - } - - close(stream->fd); - if(stream->local_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->local_buffer, &size, MEM_RELEASE); - } - if(stream->tmp_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE); - } - free(stream->fmt); - pthread_mutex_destroy(&stream->lock); - free(stream); - - params->result = S_OK; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_start(void *args) -{ - struct start_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - - if((stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !stream->event) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_EVENTHANDLE_NOT_SET); - - if(stream->playing) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_NOT_STOPPED); - - stream->playing = TRUE; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_stop(void *args) -{ - struct stop_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - - if(!stream->playing) - return oss_unlock_result(stream, ¶ms->result, S_FALSE); - - stream->playing = FALSE; - stream->in_oss_frames = 0; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_reset(void *args) -{ - struct reset_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - - if(stream->playing) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_NOT_STOPPED); - - if(stream->getbuf_last) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_BUFFER_OPERATION_PENDING); - - if(stream->flow == eRender){ - stream->written_frames = 0; - stream->last_pos_frames = 0; - }else{ - stream->written_frames += stream->held_frames; - } - stream->held_frames = 0; - stream->lcl_offs_frames = 0; - stream->in_oss_frames = 0; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static void silence_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 frames) -{ - WAVEFORMATEXTENSIBLE *fmtex = (WAVEFORMATEXTENSIBLE*)stream->fmt; - if((stream->fmt->wFormatTag == WAVE_FORMAT_PCM || - (stream->fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - IsEqualGUID(&fmtex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) && - stream->fmt->wBitsPerSample == 8) - memset(buffer, 128, frames * stream->fmt->nBlockAlign); - else - memset(buffer, 0, frames * stream->fmt->nBlockAlign); -} - -static void oss_write_data(struct oss_stream *stream) -{ - ssize_t written_bytes; - UINT32 written_frames, in_oss_frames, write_limit, max_period, write_offs_frames, new_frames; - SIZE_T to_write_frames, to_write_bytes, advanced; - audio_buf_info bi; - BYTE *buf; - - if(ioctl(stream->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0){ - WARN("GETOSPACE failed: %d (%s)\n", errno, strerror(errno)); - return; - } - - max_period = max(bi.fragsize / stream->fmt->nBlockAlign, stream->period_frames); - - if(bi.bytes > stream->oss_bufsize_bytes){ - TRACE("New buffer size (%u) is larger than old buffer size (%u)\n", - bi.bytes, stream->oss_bufsize_bytes); - stream->oss_bufsize_bytes = bi.bytes; - in_oss_frames = 0; - }else - in_oss_frames = (stream->oss_bufsize_bytes - bi.bytes) / stream->fmt->nBlockAlign; - - if(in_oss_frames > stream->in_oss_frames){ - TRACE("Capping reported frames from %u to %u\n", - in_oss_frames, stream->in_oss_frames); - in_oss_frames = stream->in_oss_frames; - } - - write_limit = 0; - while(write_limit + in_oss_frames < max_period * 3) - write_limit += max_period; - if(write_limit == 0) - return; - - /* vvvvvv - in_oss_frames - * [--xxxxxxxxxx] - * [xxxxxxxxxx--] - * ^^^^^^^^^^ - held_frames - * ^ - lcl_offs_frames - */ - advanced = stream->in_oss_frames - in_oss_frames; - if(advanced > stream->held_frames) - advanced = stream->held_frames; - stream->lcl_offs_frames += advanced; - stream->lcl_offs_frames %= stream->bufsize_frames; - stream->held_frames -= advanced; - stream->in_oss_frames = in_oss_frames; - TRACE("advanced by %lu, lcl_offs: %u, held: %u, in_oss: %u\n", - advanced, stream->lcl_offs_frames, stream->held_frames, stream->in_oss_frames); - - - if(stream->held_frames == stream->in_oss_frames) - return; - - write_offs_frames = (stream->lcl_offs_frames + stream->in_oss_frames) % stream->bufsize_frames; - new_frames = stream->held_frames - stream->in_oss_frames; - - if(write_offs_frames + new_frames > stream->bufsize_frames) - to_write_frames = stream->bufsize_frames - write_offs_frames; - else - to_write_frames = new_frames; - - to_write_frames = min(to_write_frames, write_limit); - to_write_bytes = to_write_frames * stream->fmt->nBlockAlign; - TRACE("going to write %lu frames from %u (%lu of %u)\n", to_write_frames, - write_offs_frames, to_write_frames + write_offs_frames, - stream->bufsize_frames); - - buf = stream->local_buffer + write_offs_frames * stream->fmt->nBlockAlign; - - if(stream->mute) - silence_buffer(stream, buf, to_write_frames); - - written_bytes = write(stream->fd, buf, to_write_bytes); - if(written_bytes < 0){ - /* EAGAIN is OSS buffer full, log that too */ - WARN("write failed: %d (%s)\n", errno, strerror(errno)); - return; - } - written_frames = written_bytes / stream->fmt->nBlockAlign; - - stream->in_oss_frames += written_frames; - - if(written_frames < to_write_frames){ - /* OSS buffer probably full */ - return; - } - - if(new_frames > written_frames && written_frames < write_limit){ - /* wrapped and have some data back at the start to write */ - - to_write_frames = min(write_limit - written_frames, new_frames - written_frames); - to_write_bytes = to_write_frames * stream->fmt->nBlockAlign; - - if(stream->mute) - silence_buffer(stream, stream->local_buffer, to_write_frames); - - TRACE("wrapping to write %lu frames from beginning\n", to_write_frames); - - written_bytes = write(stream->fd, stream->local_buffer, to_write_bytes); - if(written_bytes < 0){ - WARN("write failed: %d (%s)\n", errno, strerror(errno)); - return; - } - written_frames = written_bytes / stream->fmt->nBlockAlign; - stream->in_oss_frames += written_frames; - } -} - -static void oss_read_data(struct oss_stream *stream) -{ - UINT64 pos, readable; - ssize_t nread; - - pos = (stream->held_frames + stream->lcl_offs_frames) % stream->bufsize_frames; - readable = (stream->bufsize_frames - pos) * stream->fmt->nBlockAlign; - - nread = read(stream->fd, stream->local_buffer + pos * stream->fmt->nBlockAlign, - readable); - if(nread < 0){ - WARN("read failed: %d (%s)\n", errno, strerror(errno)); - return; - } - - stream->held_frames += nread / stream->fmt->nBlockAlign; - - if(stream->held_frames > stream->bufsize_frames){ - WARN("Overflow of unread data\n"); - stream->lcl_offs_frames += stream->held_frames; - stream->lcl_offs_frames %= stream->bufsize_frames; - stream->held_frames = stream->bufsize_frames; - } -} - -static NTSTATUS oss_timer_loop(void *args) -{ - struct timer_loop_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - LARGE_INTEGER delay, now, next; - int adjust; - - oss_lock(stream); - - delay.QuadPart = -stream->period; - NtQueryPerformanceCounter(&now, NULL); - next.QuadPart = now.QuadPart + stream->period; - - while(!stream->please_quit){ - if(stream->playing){ - if(stream->flow == eRender && stream->held_frames) - oss_write_data(stream); - else if(stream->flow == eCapture) - oss_read_data(stream); - } - if(stream->event) - NtSetEvent(stream->event, NULL); - oss_unlock(stream); - - NtDelayExecution(FALSE, &delay); - - oss_lock(stream); - NtQueryPerformanceCounter(&now, NULL); - adjust = next.QuadPart - now.QuadPart; - if(adjust > stream->period / 2) - adjust = stream->period / 2; - else if(adjust < -stream->period / 2) - adjust = -stream->period / 2; - delay.QuadPart = -(stream->period + adjust); - next.QuadPart += stream->period; - } - - oss_unlock(stream); - - return STATUS_SUCCESS; -} - -static NTSTATUS oss_get_render_buffer(void *args) -{ - struct get_render_buffer_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - UINT32 write_pos, frames = params->frames; - BYTE **data = params->data; - SIZE_T size; - - oss_lock(stream); - - if(stream->getbuf_last) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_OUT_OF_ORDER); - - if(!frames) - return oss_unlock_result(stream, ¶ms->result, S_OK); - - if(stream->held_frames + frames > stream->bufsize_frames) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_BUFFER_TOO_LARGE); - - write_pos = - (stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames; - if(write_pos + frames > stream->bufsize_frames){ - if(stream->tmp_buffer_frames < frames){ - if(stream->tmp_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE); - stream->tmp_buffer = NULL; - } - size = frames * stream->fmt->nBlockAlign; - if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(), - &size, MEM_COMMIT, PAGE_READWRITE)){ - stream->tmp_buffer_frames = 0; - return oss_unlock_result(stream, ¶ms->result, E_OUTOFMEMORY); - } - stream->tmp_buffer_frames = frames; - } - *data = stream->tmp_buffer; - stream->getbuf_last = -frames; - }else{ - *data = stream->local_buffer + write_pos * stream->fmt->nBlockAlign; - stream->getbuf_last = frames; - } - - silence_buffer(stream, *data, frames); - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static void oss_wrap_buffer(struct oss_stream *stream, BYTE *buffer, UINT32 written_frames) -{ - UINT32 write_offs_frames = - (stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames; - UINT32 write_offs_bytes = write_offs_frames * stream->fmt->nBlockAlign; - UINT32 chunk_frames = stream->bufsize_frames - write_offs_frames; - UINT32 chunk_bytes = chunk_frames * stream->fmt->nBlockAlign; - UINT32 written_bytes = written_frames * stream->fmt->nBlockAlign; - - if(written_bytes <= chunk_bytes){ - memcpy(stream->local_buffer + write_offs_bytes, buffer, written_bytes); - }else{ - memcpy(stream->local_buffer + write_offs_bytes, buffer, chunk_bytes); - memcpy(stream->local_buffer, buffer + chunk_bytes, - written_bytes - chunk_bytes); - } -} - -static NTSTATUS oss_release_render_buffer(void *args) -{ - struct release_render_buffer_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - UINT32 written_frames = params->written_frames; - UINT flags = params->flags; - BYTE *buffer; - - oss_lock(stream); - - if(!written_frames){ - stream->getbuf_last = 0; - return oss_unlock_result(stream, ¶ms->result, S_OK); - } - - if(!stream->getbuf_last) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_OUT_OF_ORDER); - - if(written_frames > (stream->getbuf_last >= 0 ? stream->getbuf_last : -stream->getbuf_last)) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_INVALID_SIZE); - - if(stream->getbuf_last >= 0) - buffer = stream->local_buffer + stream->fmt->nBlockAlign * - ((stream->lcl_offs_frames + stream->held_frames) % stream->bufsize_frames); - else - buffer = stream->tmp_buffer; - - if(flags & AUDCLNT_BUFFERFLAGS_SILENT) - silence_buffer(stream, buffer, written_frames); - - if(stream->getbuf_last < 0) - oss_wrap_buffer(stream, buffer, written_frames); - - stream->held_frames += written_frames; - stream->written_frames += written_frames; - stream->getbuf_last = 0; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_get_capture_buffer(void *args) -{ - struct get_capture_buffer_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - UINT64 *devpos = params->devpos, *qpcpos = params->qpcpos; - UINT32 *frames = params->frames; - UINT *flags = params->flags; - BYTE **data = params->data; - SIZE_T size; - - oss_lock(stream); - - if(stream->getbuf_last) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_OUT_OF_ORDER); - - if(stream->held_frames < stream->period_frames){ - *frames = 0; - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_S_BUFFER_EMPTY); - } - - *flags = 0; - - *frames = stream->period_frames; - - if(stream->lcl_offs_frames + *frames > stream->bufsize_frames){ - UINT32 chunk_bytes, offs_bytes, frames_bytes; - if(stream->tmp_buffer_frames < *frames){ - if(stream->tmp_buffer){ - size = 0; - NtFreeVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, &size, MEM_RELEASE); - stream->tmp_buffer = NULL; - } - size = *frames * stream->fmt->nBlockAlign; - if(NtAllocateVirtualMemory(GetCurrentProcess(), (void **)&stream->tmp_buffer, zero_bits(), - &size, MEM_COMMIT, PAGE_READWRITE)){ - stream->tmp_buffer_frames = 0; - return oss_unlock_result(stream, ¶ms->result, E_OUTOFMEMORY); - } - stream->tmp_buffer_frames = *frames; - } - - *data = stream->tmp_buffer; - chunk_bytes = (stream->bufsize_frames - stream->lcl_offs_frames) * - stream->fmt->nBlockAlign; - offs_bytes = stream->lcl_offs_frames * stream->fmt->nBlockAlign; - frames_bytes = *frames * stream->fmt->nBlockAlign; - memcpy(stream->tmp_buffer, stream->local_buffer + offs_bytes, chunk_bytes); - memcpy(stream->tmp_buffer + chunk_bytes, stream->local_buffer, - frames_bytes - chunk_bytes); - }else - *data = stream->local_buffer + - stream->lcl_offs_frames * stream->fmt->nBlockAlign; - - stream->getbuf_last = *frames; - - if(devpos) - *devpos = stream->written_frames; - if(qpcpos){ - LARGE_INTEGER stamp, freq; - NtQueryPerformanceCounter(&stamp, &freq); - *qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart; - } - - return oss_unlock_result(stream, ¶ms->result, *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY); -} - -static NTSTATUS oss_release_capture_buffer(void *args) -{ - struct release_capture_buffer_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - UINT32 done = params->done; - - oss_lock(stream); - - if(!done){ - stream->getbuf_last = 0; - return oss_unlock_result(stream, ¶ms->result, S_OK); - } - - if(!stream->getbuf_last) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_OUT_OF_ORDER); - - if(stream->getbuf_last != done) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_INVALID_SIZE); - - stream->written_frames += done; - stream->held_frames -= done; - stream->lcl_offs_frames += done; - stream->lcl_offs_frames %= stream->bufsize_frames; - stream->getbuf_last = 0; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_is_format_supported(void *args) -{ - struct is_format_supported_params *params = args; - int fd; - - params->result = S_OK; - - if(!params->fmt_in || (params->share == AUDCLNT_SHAREMODE_SHARED && !params->fmt_out)) - params->result = E_POINTER; - else if(params->share != AUDCLNT_SHAREMODE_SHARED && params->share != AUDCLNT_SHAREMODE_EXCLUSIVE) - params->result = E_INVALIDARG; - else if(params->fmt_in->wFormatTag == WAVE_FORMAT_EXTENSIBLE && - params->fmt_in->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) - params->result = E_INVALIDARG; - if(FAILED(params->result)) - return STATUS_SUCCESS; - - fd = open_device(params->device, params->flow); - if(fd < 0){ - WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno)); - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - return STATUS_SUCCESS; - } - params->result = setup_oss_device(params->share, fd, params->fmt_in, params->fmt_out); - close(fd); - - return STATUS_SUCCESS; -} - -static NTSTATUS oss_get_mix_format(void *args) -{ - struct get_mix_format_params *params = args; - WAVEFORMATEXTENSIBLE *fmt = params->fmt; - oss_audioinfo ai; - int formats, fd; - - if(params->flow != eRender && params->flow != eCapture){ - params->result = E_UNEXPECTED; - return STATUS_SUCCESS; - } - - fd = open_device(params->device, params->flow); - if(fd < 0){ - WARN("Unable to open device %s: %d (%s)\n", params->device, errno, strerror(errno)); - params->result = AUDCLNT_E_DEVICE_INVALIDATED; - return STATUS_SUCCESS; - } - - ai.dev = -1; - if(ioctl(fd, SNDCTL_ENGINEINFO, &ai) < 0){ - WARN("Unable to get audio info for device %s: %d (%s)\n", params->device, errno, strerror(errno)); - close(fd); - params->result = E_FAIL; - return STATUS_SUCCESS; - } - close(fd); - - if(params->flow == eRender) - formats = ai.oformats; - else - formats = ai.iformats; - - fmt->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; - if(formats & AFMT_S16_LE){ - fmt->Format.wBitsPerSample = 16; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; -#ifdef AFMT_FLOAT - }else if(formats & AFMT_FLOAT){ - fmt->Format.wBitsPerSample = 32; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; -#endif - }else if(formats & AFMT_U8){ - fmt->Format.wBitsPerSample = 8; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else if(formats & AFMT_S32_LE){ - fmt->Format.wBitsPerSample = 32; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else if(formats & AFMT_S24_LE){ - fmt->Format.wBitsPerSample = 24; - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - }else{ - WARN("Didn't recognize any available OSS formats: %x\n", formats); - params->result = E_FAIL; - return STATUS_SUCCESS; - } - - /* some OSS drivers are buggy, so set reasonable defaults if - * the reported values seem wacky */ - fmt->Format.nChannels = max(ai.max_channels, ai.min_channels); - if(fmt->Format.nChannels == 0 || fmt->Format.nChannels > 8) - fmt->Format.nChannels = 2; - - /* For most hardware on Windows, users must choose a configuration with an even - * number of channels (stereo, quad, 5.1, 7.1). Users can then disable - * channels, but those channels are still reported to applications from - * GetMixFormat! Some applications behave badly if given an odd number of - * channels (e.g. 2.1). */ - if(fmt->Format.nChannels > 1 && (fmt->Format.nChannels & 0x1)) - { - if(fmt->Format.nChannels < ai.max_channels) - fmt->Format.nChannels += 1; - else - /* We could "fake" more channels and downmix the emulated channels, - * but at that point you really ought to tweak your OSS setup or - * just use PulseAudio. */ - WARN("Some Windows applications behave badly with an odd number of channels (%u)!\n", fmt->Format.nChannels); - } - - if(ai.max_rate == 0) - fmt->Format.nSamplesPerSec = 44100; - else - fmt->Format.nSamplesPerSec = min(ai.max_rate, 44100); - if(fmt->Format.nSamplesPerSec < ai.min_rate) - fmt->Format.nSamplesPerSec = ai.min_rate; - - fmt->dwChannelMask = get_channel_mask(fmt->Format.nChannels); - - fmt->Format.nBlockAlign = (fmt->Format.wBitsPerSample * - fmt->Format.nChannels) / 8; - fmt->Format.nAvgBytesPerSec = fmt->Format.nSamplesPerSec * - fmt->Format.nBlockAlign; - - fmt->Samples.wValidBitsPerSample = fmt->Format.wBitsPerSample; - fmt->Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - - params->result = S_OK; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_get_buffer_size(void *args) -{ - struct get_buffer_size_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - - *params->frames = stream->bufsize_frames; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_get_latency(void *args) -{ - struct get_latency_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - - /* pretend we process audio in Period chunks, so max latency includes - * the period time. Some native machines add .6666ms in shared mode. */ - *params->latency = stream->period + 6666; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_get_current_padding(void *args) -{ - struct get_current_padding_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - - *params->padding = stream->held_frames; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_get_next_packet_size(void *args) -{ - struct get_next_packet_size_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - UINT32 *frames = params->frames; - - oss_lock(stream); - - *frames = stream->held_frames < stream->period_frames ? 0 : stream->period_frames; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_get_frequency(void *args) -{ - struct get_frequency_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - UINT64 *freq = params->freq; - - oss_lock(stream); - - if(stream->share == AUDCLNT_SHAREMODE_SHARED) - *freq = (UINT64)stream->fmt->nSamplesPerSec * stream->fmt->nBlockAlign; - else - *freq = stream->fmt->nSamplesPerSec; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_get_position(void *args) -{ - struct get_position_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - UINT64 *pos = params->pos, *qpctime = params->qpctime; - - oss_lock(stream); - - if(stream->flow == eRender){ - *pos = stream->written_frames - stream->held_frames; - if(*pos < stream->last_pos_frames) - *pos = stream->last_pos_frames; - }else if(stream->flow == eCapture){ - audio_buf_info bi; - UINT32 held; - - if(ioctl(stream->fd, SNDCTL_DSP_GETISPACE, &bi) < 0){ - TRACE("GETISPACE failed: %d (%s)\n", errno, strerror(errno)); - held = 0; - }else{ - if(bi.bytes <= bi.fragsize) - held = 0; - else - held = bi.bytes / stream->fmt->nBlockAlign; - } - - *pos = stream->written_frames + held; - } - - stream->last_pos_frames = *pos; - - TRACE("returning: %s\n", wine_dbgstr_longlong(*pos)); - if(stream->share == AUDCLNT_SHAREMODE_SHARED) - *pos *= stream->fmt->nBlockAlign; - - if(qpctime){ - LARGE_INTEGER stamp, freq; - NtQueryPerformanceCounter(&stamp, &freq); - *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart; - } - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_set_volumes(void *args) -{ - struct set_volumes_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - stream->mute = !params->master_volume; - oss_unlock(stream); - - return STATUS_SUCCESS; -} - -static NTSTATUS oss_set_event_handle(void *args) -{ - struct set_event_handle_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - - if(!(stream->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) - return oss_unlock_result(stream, ¶ms->result, AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED); - - if (stream->event){ - FIXME("called twice\n"); - return oss_unlock_result(stream, ¶ms->result, HRESULT_FROM_WIN32(ERROR_INVALID_NAME)); - } - - stream->event = params->event; - - return oss_unlock_result(stream, ¶ms->result, S_OK); -} - -static NTSTATUS oss_is_started(void *args) -{ - struct is_started_params *params = args; - struct oss_stream *stream = handle_get_stream(params->stream); - - oss_lock(stream); - - return oss_unlock_result(stream, ¶ms->result, stream->playing ? S_OK : S_FALSE); -} - -/* Aux driver */ - -static unsigned int num_aux; - -#define MIXER_DEV "/dev/mixer" - -static UINT aux_init(void) -{ - int mixer; - - TRACE("()\n"); - - if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) - { - WARN("mixer device not available !\n"); - num_aux = 0; - } - else - { - close(mixer); - num_aux = 6; - } - return 0; -} - -static UINT aux_exit(void) -{ - TRACE("()\n"); - return 0; -} - -static UINT aux_get_devcaps(WORD dev_id, AUXCAPSW *caps, UINT size) -{ - int mixer, volume; - static const WCHAR ini[] = {'O','S','S',' ','A','u','x',' ','#','0',0}; - - TRACE("(%04X, %p, %u);\n", dev_id, caps, size); - if (caps == NULL) return MMSYSERR_NOTENABLED; - if (dev_id >= num_aux) return MMSYSERR_BADDEVICEID; - if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) - { - WARN("mixer device not available !\n"); - return MMSYSERR_NOTENABLED; - } - if (ioctl(mixer, SOUND_MIXER_READ_LINE, &volume) == -1) - { - close(mixer); - WARN("unable to read mixer !\n"); - return MMSYSERR_NOTENABLED; - } - close(mixer); - caps->wMid = 0xAA; - caps->wPid = 0x55 + dev_id; - caps->vDriverVersion = 0x0100; - memcpy(caps->szPname, ini, sizeof(ini)); - caps->szPname[9] = '0' + dev_id; /* 6 at max */ - caps->wTechnology = (dev_id == 2) ? AUXCAPS_CDAUDIO : AUXCAPS_AUXIN; - caps->wReserved1 = 0; - caps->dwSupport = AUXCAPS_VOLUME | AUXCAPS_LRVOLUME; - - return MMSYSERR_NOERROR; -} - -static UINT aux_get_volume(WORD dev_id, UINT *vol) -{ - int mixer, volume, left, right, cmd; - - TRACE("(%04X, %p);\n", dev_id, vol); - if (vol == NULL) return MMSYSERR_NOTENABLED; - if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) - { - WARN("mixer device not available !\n"); - return MMSYSERR_NOTENABLED; - } - switch(dev_id) - { - case 0: - TRACE("SOUND_MIXER_READ_PCM !\n"); - cmd = SOUND_MIXER_READ_PCM; - break; - case 1: - TRACE("SOUND_MIXER_READ_SYNTH !\n"); - cmd = SOUND_MIXER_READ_SYNTH; - break; - case 2: - TRACE("SOUND_MIXER_READ_CD !\n"); - cmd = SOUND_MIXER_READ_CD; - break; - case 3: - TRACE("SOUND_MIXER_READ_LINE !\n"); - cmd = SOUND_MIXER_READ_LINE; - break; - case 4: - TRACE("SOUND_MIXER_READ_MIC !\n"); - cmd = SOUND_MIXER_READ_MIC; - break; - case 5: - TRACE("SOUND_MIXER_READ_VOLUME !\n"); - cmd = SOUND_MIXER_READ_VOLUME; - break; - default: - WARN("invalid device id=%04X !\n", dev_id); - close(mixer); - return MMSYSERR_NOTENABLED; - } - if (ioctl(mixer, cmd, &volume) == -1) - { - WARN("unable to read mixer !\n"); - close(mixer); - return MMSYSERR_NOTENABLED; - } - close(mixer); - left = LOBYTE(LOWORD(volume)); - right = HIBYTE(LOWORD(volume)); - TRACE("left=%d right=%d !\n", left, right); - *vol = MAKELONG((left * 0xFFFFL) / 100, (right * 0xFFFFL) / 100); - return MMSYSERR_NOERROR; -} - -static UINT aux_set_volume(WORD dev_id, UINT vol) -{ - int mixer; - int volume, left, right; - int cmd; - - TRACE("(%04X, %08X);\n", dev_id, vol); - - left = (LOWORD(vol) * 100) >> 16; - right = (HIWORD(vol) * 100) >> 16; - volume = (right << 8) | left; - - if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) - { - WARN("mixer device not available !\n"); - return MMSYSERR_NOTENABLED; - } - - switch(dev_id) - { - case 0: - TRACE("SOUND_MIXER_WRITE_PCM !\n"); - cmd = SOUND_MIXER_WRITE_PCM; - break; - case 1: - TRACE("SOUND_MIXER_WRITE_SYNTH !\n"); - cmd = SOUND_MIXER_WRITE_SYNTH; - break; - case 2: - TRACE("SOUND_MIXER_WRITE_CD !\n"); - cmd = SOUND_MIXER_WRITE_CD; - break; - case 3: - TRACE("SOUND_MIXER_WRITE_LINE !\n"); - cmd = SOUND_MIXER_WRITE_LINE; - break; - case 4: - TRACE("SOUND_MIXER_WRITE_MIC !\n"); - cmd = SOUND_MIXER_WRITE_MIC; - break; - case 5: - TRACE("SOUND_MIXER_WRITE_VOLUME !\n"); - cmd = SOUND_MIXER_WRITE_VOLUME; - break; - default: - WARN("invalid device id=%04X !\n", dev_id); - close(mixer); - return MMSYSERR_NOTENABLED; - } - if (ioctl(mixer, cmd, &volume) == -1) - { - WARN("unable to set mixer !\n"); - close(mixer); - return MMSYSERR_NOTENABLED; - } - close(mixer); - return MMSYSERR_NOERROR; -} - -static NTSTATUS oss_aux_message(void *args) -{ - struct aux_message_params *params = args; - - switch (params->msg) - { - case DRVM_INIT: - *params->err = aux_init(); - break; - case DRVM_EXIT: - *params->err = aux_exit(); - break; - case DRVM_ENABLE: - case DRVM_DISABLE: - /* FIXME: Pretend this is supported */ - *params->err = 0; - break; - case AUXDM_GETDEVCAPS: - *params->err = aux_get_devcaps(params->dev_id, (AUXCAPSW *)params->param_1, params->param_2); - break; - case AUXDM_GETNUMDEVS: - TRACE("return %d;\n", num_aux); - *params->err = num_aux; - break; - case AUXDM_GETVOLUME: - *params->err = aux_get_volume(params->dev_id, (UINT *)params->param_1); - break; - case AUXDM_SETVOLUME: - *params->err = aux_set_volume(params->dev_id, params->param_1); - break; - default: - WARN("unknown message !\n"); - *params->err = MMSYSERR_NOTSUPPORTED; - break; - } - - return STATUS_SUCCESS; -} - -unixlib_entry_t __wine_unix_call_funcs[] = -{ - NULL, - NULL, - NULL, - oss_get_endpoint_ids, - oss_create_stream, - oss_release_stream, - oss_start, - oss_stop, - oss_reset, - oss_timer_loop, - oss_get_render_buffer, - oss_release_render_buffer, - oss_get_capture_buffer, - oss_release_capture_buffer, - oss_is_format_supported, - oss_get_mix_format, - NULL, - oss_get_buffer_size, - oss_get_latency, - oss_get_current_padding, - oss_get_next_packet_size, - oss_get_frequency, - oss_get_position, - oss_set_volumes, - oss_set_event_handle, - oss_test_connect, - oss_is_started, - NULL, - NULL, - oss_midi_release, - oss_midi_out_message, - oss_midi_in_message, - oss_midi_notify_wait, - oss_aux_message, -}; - -#ifdef _WIN64 - -typedef UINT PTR32; - -static NTSTATUS oss_wow64_test_connect(void *args) -{ - struct - { - PTR32 name; - enum driver_priority priority; - } *params32 = args; - struct test_connect_params params = - { - .name = ULongToPtr(params32->name), - }; - oss_test_connect(¶ms); - params32->priority = params.priority; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_endpoint_ids(void *args) -{ - struct - { - EDataFlow flow; - PTR32 endpoints; - unsigned int size; - HRESULT result; - unsigned int num; - unsigned int default_idx; - } *params32 = args; - struct get_endpoint_ids_params params = - { - .flow = params32->flow, - .endpoints = ULongToPtr(params32->endpoints), - .size = params32->size - }; - oss_get_endpoint_ids(¶ms); - params32->size = params.size; - params32->result = params.result; - params32->num = params.num; - params32->default_idx = params.default_idx; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_create_stream(void *args) -{ - struct - { - PTR32 name; - PTR32 device; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - UINT flags; - REFERENCE_TIME duration; - REFERENCE_TIME period; - PTR32 fmt; - HRESULT result; - PTR32 channel_count; - PTR32 stream; - } *params32 = args; - struct create_stream_params params = - { - .name = ULongToPtr(params32->name), - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .share = params32->share, - .flags = params32->flags, - .duration = params32->duration, - .period = params32->period, - .fmt = ULongToPtr(params32->fmt), - .channel_count = ULongToPtr(params32->channel_count), - .stream = ULongToPtr(params32->stream) - }; - oss_create_stream(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_release_stream(void *args) -{ - struct - { - stream_handle stream; - PTR32 timer_thread; - HRESULT result; - } *params32 = args; - struct release_stream_params params = - { - .stream = params32->stream, - .timer_thread = ULongToHandle(params32->timer_thread) - }; - oss_release_stream(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_render_buffer(void *args) -{ - struct - { - stream_handle stream; - UINT32 frames; - HRESULT result; - PTR32 data; - } *params32 = args; - BYTE *data = NULL; - struct get_render_buffer_params params = - { - .stream = params32->stream, - .frames = params32->frames, - .data = &data - }; - oss_get_render_buffer(¶ms); - params32->result = params.result; - *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data); - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_capture_buffer(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 data; - PTR32 frames; - PTR32 flags; - PTR32 devpos; - PTR32 qpcpos; - } *params32 = args; - BYTE *data = NULL; - struct get_capture_buffer_params params = - { - .stream = params32->stream, - .data = &data, - .frames = ULongToPtr(params32->frames), - .flags = ULongToPtr(params32->flags), - .devpos = ULongToPtr(params32->devpos), - .qpcpos = ULongToPtr(params32->qpcpos) - }; - oss_get_capture_buffer(¶ms); - params32->result = params.result; - *(unsigned int *)ULongToPtr(params32->data) = PtrToUlong(data); - return STATUS_SUCCESS; -}; - -static NTSTATUS oss_wow64_is_format_supported(void *args) -{ - struct - { - PTR32 device; - EDataFlow flow; - AUDCLNT_SHAREMODE share; - PTR32 fmt_in; - PTR32 fmt_out; - HRESULT result; - } *params32 = args; - struct is_format_supported_params params = - { - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .share = params32->share, - .fmt_in = ULongToPtr(params32->fmt_in), - .fmt_out = ULongToPtr(params32->fmt_out) - }; - oss_is_format_supported(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_mix_format(void *args) -{ - struct - { - PTR32 device; - EDataFlow flow; - PTR32 fmt; - HRESULT result; - } *params32 = args; - struct get_mix_format_params params = - { - .device = ULongToPtr(params32->device), - .flow = params32->flow, - .fmt = ULongToPtr(params32->fmt) - }; - oss_get_mix_format(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_buffer_size(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 frames; - } *params32 = args; - struct get_buffer_size_params params = - { - .stream = params32->stream, - .frames = ULongToPtr(params32->frames) - }; - oss_get_buffer_size(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_latency(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 latency; - } *params32 = args; - struct get_latency_params params = - { - .stream = params32->stream, - .latency = ULongToPtr(params32->latency) - }; - oss_get_latency(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_current_padding(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 padding; - } *params32 = args; - struct get_current_padding_params params = - { - .stream = params32->stream, - .padding = ULongToPtr(params32->padding) - }; - oss_get_current_padding(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_next_packet_size(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 frames; - } *params32 = args; - struct get_next_packet_size_params params = - { - .stream = params32->stream, - .frames = ULongToPtr(params32->frames) - }; - oss_get_next_packet_size(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_frequency(void *args) -{ - struct - { - stream_handle stream; - HRESULT result; - PTR32 freq; - } *params32 = args; - struct get_frequency_params params = - { - .stream = params32->stream, - .freq = ULongToPtr(params32->freq) - }; - oss_get_frequency(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_get_position(void *args) -{ - struct - { - stream_handle stream; - BOOL device; - HRESULT result; - PTR32 pos; - PTR32 qpctime; - } *params32 = args; - struct get_position_params params = - { - .stream = params32->stream, - .device = params32->device, - .pos = ULongToPtr(params32->pos), - .qpctime = ULongToPtr(params32->qpctime) - }; - oss_get_position(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_set_volumes(void *args) -{ - struct - { - stream_handle stream; - float master_volume; - PTR32 volumes; - PTR32 session_volumes; - int channel; - } *params32 = args; - struct set_volumes_params params = - { - .stream = params32->stream, - .master_volume = params32->master_volume, - .volumes = ULongToPtr(params32->volumes), - .session_volumes = ULongToPtr(params32->session_volumes), - .channel = params32->channel - }; - return oss_set_volumes(¶ms); -} - -static NTSTATUS oss_wow64_set_event_handle(void *args) -{ - struct - { - stream_handle stream; - PTR32 event; - HRESULT result; - } *params32 = args; - struct set_event_handle_params params = - { - .stream = params32->stream, - .event = ULongToHandle(params32->event) - }; - - oss_set_event_handle(¶ms); - params32->result = params.result; - return STATUS_SUCCESS; -} - -static NTSTATUS oss_wow64_aux_message(void *args) -{ - struct - { - UINT dev_id; - UINT msg; - UINT user; - UINT param_1; - UINT param_2; - PTR32 err; - } *params32 = args; - struct aux_message_params params = - { - .dev_id = params32->dev_id, - .msg = params32->msg, - .user = params32->user, - .param_1 = params32->param_1, - .param_2 = params32->param_2, - .err = ULongToPtr(params32->err), - }; - return oss_aux_message(¶ms); -} - -unixlib_entry_t __wine_unix_call_wow64_funcs[] = -{ - NULL, - NULL, - NULL, - oss_wow64_get_endpoint_ids, - oss_wow64_create_stream, - oss_wow64_release_stream, - oss_start, - oss_stop, - oss_reset, - oss_timer_loop, - oss_wow64_get_render_buffer, - oss_release_render_buffer, - oss_wow64_get_capture_buffer, - oss_release_capture_buffer, - oss_wow64_is_format_supported, - oss_wow64_get_mix_format, - NULL, - oss_wow64_get_buffer_size, - oss_wow64_get_latency, - oss_wow64_get_current_padding, - oss_wow64_get_next_packet_size, - oss_wow64_get_frequency, - oss_wow64_get_position, - oss_wow64_set_volumes, - oss_wow64_set_event_handle, - oss_wow64_test_connect, - oss_is_started, - NULL, - NULL, - oss_midi_release, - oss_wow64_midi_out_message, - oss_wow64_midi_in_message, - oss_wow64_midi_notify_wait, - oss_wow64_aux_message, -}; - -#endif /* _WIN64 */ diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/ossmidi.c b/pkgs/osu-wine/audio-revert/wineoss.drv/ossmidi.c deleted file mode 100644 index 158132c..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/ossmidi.c +++ /dev/null @@ -1,2177 +0,0 @@ -/* - * MIDI driver for OSS (unixlib) - * - * Copyright 1994 Martin Ayotte - * Copyright 1998 Luiz Otavio L. Zorzella (init procedures) - * Copyright 1998, 1999 Eric POUECH - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#if 0 -#pragma makedep unix -#endif - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "winternl.h" -#include "audioclient.h" -#include "mmddk.h" - -#include "wine/debug.h" -#include "wine/unixlib.h" - -#include "unixlib.h" - -struct midi_dest -{ - BOOL bEnabled; - MIDIOPENDESC midiDesc; - BYTE runningStatus; - WORD wFlags; - MIDIHDR *lpQueueHdr; - void *lpExtra; /* according to port type (MIDI, FM...), extra data when needed */ - MIDIOUTCAPSW caps; - int fd; -}; - -struct midi_src -{ - int state; /* -1 disabled, 0 is no recording started, 1 in recording, bit 2 set if in sys exclusive recording */ - MIDIOPENDESC midiDesc; - WORD wFlags; - MIDIHDR *lpQueueHdr; - unsigned char incoming[3]; - unsigned char incPrev; - char incLen; - UINT startTime; - MIDIINCAPSW caps; - int fd; -}; - -static pthread_mutex_t in_buffer_mutex = PTHREAD_MUTEX_INITIALIZER; - -static unsigned int num_dests, num_srcs, num_synths, seq_refs; -static struct midi_dest dests[MAX_MIDIOUTDRV]; -static struct midi_src srcs[MAX_MIDIINDRV]; -static int load_count; - -static unsigned int num_midi_in_started; -static int rec_cancel_pipe[2]; -static pthread_t rec_thread_id; - -static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t notify_read_cond = PTHREAD_COND_INITIALIZER; -static pthread_cond_t notify_write_cond = PTHREAD_COND_INITIALIZER; -static BOOL notify_quit; -#define NOTIFY_BUFFER_SIZE 64 + 1 /* + 1 for the sentinel */ -static struct notify_context notify_buffer[NOTIFY_BUFFER_SIZE]; -static struct notify_context *notify_read = notify_buffer, *notify_write = notify_buffer; - -typedef struct sVoice -{ - int note; /* 0 means not used */ - int channel; - unsigned cntMark : 30, - status : 2; -#define sVS_UNUSED 0 -#define sVS_PLAYING 1 -#define sVS_SUSTAINED 2 -} sVoice; - -typedef struct sChannel -{ - int program; - - int bender; - int benderRange; - /* controllers */ - int bank; /* CTL_BANK_SELECT */ - int volume; /* CTL_MAIN_VOLUME */ - int balance; /* CTL_BALANCE */ - int expression; /* CTL_EXPRESSION */ - int sustain; /* CTL_SUSTAIN */ - - unsigned char nrgPmtMSB; /* Non register Parameters */ - unsigned char nrgPmtLSB; - unsigned char regPmtMSB; /* Non register Parameters */ - unsigned char regPmtLSB; -} sChannel; - -typedef struct sFMextra -{ - unsigned counter; - int drumSetMask; - sChannel channel[16]; /* MIDI has only 16 channels */ - sVoice voice[1]; /* dyn allocated according to sound card */ - /* do not append fields below voice[1] since the size of this structure - * depends on the number of available voices on the FM synth... - */ -} sFMextra; - -#define IS_DRUM_CHANNEL(_xtra, _chn) ((_xtra)->drumSetMask & (1 << (_chn))) - -WINE_DEFAULT_DEBUG_CHANNEL(midi); - -static int oss_to_win_device_type(int type) -{ - /* MOD_MIDIPORT output port - * MOD_SYNTH generic internal synth - * MOD_SQSYNTH square wave internal synth - * MOD_FMSYNTH FM internal synth - * MOD_MAPPER MIDI mapper - * MOD_WAVETABLE hardware wavetable internal synth - * MOD_SWSYNTH software internal synth - */ - - /* FIXME Is this really the correct equivalence from UNIX to - Windows Sound type */ - - switch (type) - { - case SYNTH_TYPE_FM: return MOD_FMSYNTH; - case SYNTH_TYPE_SAMPLE: return MOD_SYNTH; - case SYNTH_TYPE_MIDI: return MOD_MIDIPORT; - default: - ERR("Cannot determine the type of this midi device. " - "Assuming FM Synth\n"); - return MOD_FMSYNTH; - } -} - -static void in_buffer_lock(void) -{ - pthread_mutex_lock(&in_buffer_mutex); -} - -static void in_buffer_unlock(void) -{ - pthread_mutex_unlock(&in_buffer_mutex); -} - -static uint64_t get_time_msec(void) -{ - struct timespec now = {0, 0}; - -#ifdef CLOCK_MONOTONIC_RAW - if (!clock_gettime(CLOCK_MONOTONIC_RAW, &now)) - return (uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; -#endif - clock_gettime(CLOCK_MONOTONIC, &now); - return (uint64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000; -} - -/* - * notify buffer: The notification ring buffer is implemented so that - * there is always at least one unused sentinel before the current - * read position in order to allow detection of the full vs empty - * state. - */ -static struct notify_context *notify_buffer_next(struct notify_context *notify) -{ - if (++notify >= notify_buffer + ARRAY_SIZE(notify_buffer)) - notify = notify_buffer; - - return notify; -} - -static BOOL notify_buffer_empty(void) -{ - return notify_read == notify_write; -} - -static BOOL notify_buffer_full(void) -{ - return notify_buffer_next(notify_write) == notify_read; -} - -static BOOL notify_buffer_add(struct notify_context *notify) -{ - if (notify_buffer_full()) return FALSE; - - *notify_write = *notify; - notify_write = notify_buffer_next(notify_write); - return TRUE; -} - -static BOOL notify_buffer_remove(struct notify_context *notify) -{ - if (notify_buffer_empty()) return FALSE; - - *notify = *notify_read; - notify_read = notify_buffer_next(notify_read); - return TRUE; -} - -static void notify_post(struct notify_context *notify) -{ - pthread_mutex_lock(¬ify_mutex); - - if (notify) - { - while (notify_buffer_full()) - pthread_cond_wait(¬ify_write_cond, ¬ify_mutex); - - notify_buffer_add(notify); - } - else notify_quit = TRUE; - pthread_cond_signal(¬ify_read_cond); - - pthread_mutex_unlock(¬ify_mutex); -} - -static void set_in_notify(struct notify_context *notify, struct midi_src *src, WORD dev_id, WORD msg, - UINT_PTR param_1, UINT_PTR param_2) -{ - notify->send_notify = TRUE; - notify->dev_id = dev_id; - notify->msg = msg; - notify->param_1 = param_1; - notify->param_2 = param_2; - notify->callback = src->midiDesc.dwCallback; - notify->flags = src->wFlags; - notify->device = src->midiDesc.hMidi; - notify->instance = src->midiDesc.dwInstance; -} - -static int seq_open(void) -{ - static int midi_warn = 1; - static int fd = -1; - - if (seq_refs <= 0) - { - const char* device = getenv("MIDIDEV"); - - if (!device) device = "/dev/sequencer"; - fd = open(device, O_RDWR, 0); - if (fd == -1) - { - if (midi_warn) - { - WARN("Can't open MIDI device '%s' ! (%s). If your program needs this (probably not): %s\n", - device, strerror(errno), - errno == ENOENT ? "create it ! (\"man MAKEDEV\" ?)" : - errno == ENODEV ? "load MIDI sequencer kernel driver !" : - errno == EACCES ? "grant access ! (\"man chmod\")" : ""); - } - midi_warn = 0; - return -1; - } - fcntl(fd, F_SETFD, 1); /* set close on exec flag */ - ioctl(fd, SNDCTL_SEQ_RESET); - } - seq_refs++; - return fd; -} - -static int seq_close(int fd) -{ - if (--seq_refs == 0) - close(fd); - - return 0; -} - -static UINT oss_midi_init(void) -{ - int i, status, synth_devs = 255, midi_devs = 255, fd, len; - struct synth_info sinfo; - struct midi_info minfo; - struct midi_dest *dest; - struct midi_src *src; - - TRACE("(%i)\n", load_count); - - if (load_count++) - return 1; - - /* try to open device */ - fd = seq_open(); - if (fd == -1) - return -1; - - /* find how many Synth devices are there in the system */ - status = ioctl(fd, SNDCTL_SEQ_NRSYNTHS, &synth_devs); - if (status == -1) - { - ERR("ioctl for nr synth failed.\n"); - seq_close(fd); - return -1; - } - - if (synth_devs > MAX_MIDIOUTDRV) - { - ERR("MAX_MIDIOUTDRV (%d) was enough for the number of devices (%d). " - "Some FM devices will not be available.\n", MAX_MIDIOUTDRV, synth_devs); - synth_devs = MAX_MIDIOUTDRV; - } - - for (i = 0, dest = dests; i < synth_devs; i++, dest++) - { - /* Manufac ID. We do not have access to this with soundcard.h - * Does not seem to be a problem, because in mmsystem.h only - * Microsoft's ID is listed. - */ - dest->caps.wMid = 0x00FF; - dest->caps.wPid = 0x0001; /* FIXME Product ID */ - /* Product Version. We simply say "1" */ - dest->caps.vDriverVersion = 0x001; - /* The following are mandatory for MOD_MIDIPORT */ - dest->caps.wChannelMask = 0xFFFF; - dest->caps.wVoices = 0; - dest->caps.wNotes = 0; - dest->caps.dwSupport = 0; - - sinfo.device = i; - status = ioctl(fd, SNDCTL_SYNTH_INFO, &sinfo); - if (status == -1) - { - char buf[255]; - - ERR("ioctl for synth info failed on %d, disabling it.\n", i); - - sprintf(buf, "Wine OSS Midi Out #%d disabled", i); - len = ntdll_umbstowcs(buf, strlen(buf) + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname)); - dest->caps.szPname[len - 1] = '\0'; - dest->caps.wTechnology = MOD_MIDIPORT; - dest->bEnabled = FALSE; - } - else - { - len = ntdll_umbstowcs(sinfo.name, strlen(sinfo.name) + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname)); - dest->caps.szPname[len - 1] = '\0'; - dest->caps.wTechnology = oss_to_win_device_type(sinfo.synth_type); - - if (dest->caps.wTechnology != MOD_MIDIPORT) - { - /* FIXME Do we have this information? - * Assuming the soundcards can handle - * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but - * not MIDICAPS_CACHE. - */ - dest->caps.dwSupport = MIDICAPS_VOLUME | MIDICAPS_LRVOLUME; - dest->caps.wVoices = sinfo.nr_voices; - - /* FIXME Is it possible to know the maximum - * number of simultaneous notes of a soundcard ? - * I believe we don't have this information, but - * it's probably equal or more than wVoices - */ - dest->caps.wNotes = sinfo.nr_voices; - } - dest->bEnabled = TRUE; - - /* We also have the information sinfo.synth_subtype, not used here - */ - if (sinfo.capabilities & SYNTH_CAP_INPUT) - FIXME("Synthesizer supports MIDI in. Not yet supported.\n"); - - TRACE("SynthOut[%d]\tOSS info: synth type=%d/%d capa=%x\n", - i, sinfo.synth_type, sinfo.synth_subtype, (unsigned)sinfo.capabilities); - } - - TRACE("SynthOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n", - i, wine_dbgstr_w(dest->caps.szPname), dest->caps.wTechnology, - dest->caps.wVoices, dest->caps.wNotes, dest->caps.wChannelMask, - (unsigned)dest->caps.dwSupport); - } - - /* find how many MIDI devices are there in the system */ - status = ioctl(fd, SNDCTL_SEQ_NRMIDIS, &midi_devs); - if (status == -1) - { - ERR("ioctl on nr midi failed.\n"); - midi_devs = 0; - goto wrapup; - } - - /* FIXME: the two restrictions below could be loosened in some cases */ - if (synth_devs + midi_devs > MAX_MIDIOUTDRV) - { - ERR("MAX_MIDIOUTDRV was not enough for the number of devices. " - "Some MIDI devices will not be available.\n"); - midi_devs = MAX_MIDIOUTDRV - synth_devs; - } - - if (midi_devs > MAX_MIDIINDRV) - { - ERR("MAX_MIDIINDRV (%d) was not enough for the number of devices (%d). " - "Some MIDI devices will not be available.\n", MAX_MIDIINDRV, midi_devs); - midi_devs = MAX_MIDIINDRV; - } - - dest = dests + synth_devs; - src = srcs; - for (i = 0; i < midi_devs; i++, dest++, src++) - { - minfo.device = i; - status = ioctl(fd, SNDCTL_MIDI_INFO, &minfo); - if (status == -1) WARN("ioctl on midi info for device %d failed.\n", i); - - /* Manufacturer ID. We do not have access to this with soundcard.h - Does not seem to be a problem, because in mmsystem.h only Microsoft's ID is listed - */ - dest->caps.wMid = 0x00FF; - dest->caps.wPid = 0x0001; /* FIXME Product ID */ - /* Product Version. We simply say "1" */ - dest->caps.vDriverVersion = 0x001; - if (status == -1) - { - char buf[255]; - - sprintf(buf, "Wine OSS Midi Out #%d disabled", synth_devs + i); - len = ntdll_umbstowcs(buf, strlen(buf) + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname)); - dest->caps.szPname[len - 1] = '\0'; - dest->bEnabled = FALSE; - } - else - { - len = ntdll_umbstowcs(minfo.name, strlen(minfo.name) + 1, dest->caps.szPname, ARRAY_SIZE(dest->caps.szPname)); - dest->caps.szPname[len - 1] = '\0'; - dest->bEnabled = TRUE; - } - dest->caps.wTechnology = MOD_MIDIPORT; - dest->caps.wVoices = 0; - dest->caps.wNotes = 0; - dest->caps.wChannelMask = 0xFFFF; - dest->caps.dwSupport = 0; - - /* Manufac ID. We do not have access to this with soundcard.h - Does not seem to be a problem, because in mmsystem.h only - Microsoft's ID is listed */ - src->caps.wMid = 0x00FF; - src->caps.wPid = 0x0001; /* FIXME Product ID */ - /* Product Version. We simply say "1" */ - src->caps.vDriverVersion = 0x001; - if (status == -1) - { - char buf[ARRAY_SIZE(dest->caps.szPname)]; - - sprintf(buf, "Wine OSS Midi In #%d disabled", synth_devs + i); - len = ntdll_umbstowcs(buf, strlen(buf) + 1, src->caps.szPname, ARRAY_SIZE(src->caps.szPname)); - src->caps.szPname[len - 1] = '\0'; - src->state = -1; - } - else - { - len = ntdll_umbstowcs(minfo.name, strlen(minfo.name) + 1, src->caps.szPname, ARRAY_SIZE(src->caps.szPname)); - src->caps.szPname[len - 1] = '\0'; - src->state = 0; - } - src->caps.dwSupport = 0; /* mandatory with MIDIINCAPS */ - - TRACE("OSS info: midi[%d] dev-type=%d capa=%x\n" - "\tMidiOut[%d] name='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%d\n" - "\tMidiIn [%d] name='%s' support=%d\n", - i, minfo.dev_type, (unsigned)minfo.capabilities, - synth_devs + i, wine_dbgstr_w(dest->caps.szPname), dest->caps.wTechnology, - dest->caps.wVoices, dest->caps.wNotes, dest->caps.wChannelMask, (unsigned)dest->caps.dwSupport, - i, wine_dbgstr_w(src->caps.szPname), (unsigned)src->caps.dwSupport); - } - -wrapup: - /* windows does not seem to differentiate Synth from MIDI devices */ - num_synths = synth_devs; - num_dests = synth_devs + midi_devs; - num_srcs = midi_devs; - - /* close file and exit */ - seq_close(fd); - - return 0; -} - -static UINT midi_exit(void) -{ - TRACE("(%i)\n", load_count); - - if (--load_count) - return 1; - - return 0; -} - -NTSTATUS oss_midi_release(void *args) -{ - /* stop the notify_wait thread */ - notify_post(NULL); - - return STATUS_SUCCESS; -} - -/* FIXME: this is a bad idea, it's even not static... */ -SEQ_DEFINEBUF(1024); - -/* FIXME: this is not reentrant, not static - because of global variable - * _seqbuf and al. - */ -/************************************************************************** - * seqbuf_dump [internal] - * - * Used by SEQ_DUMPBUF to flush the buffer. - * - */ -void seqbuf_dump(void) -{ - int fd; - - /* The device is already open, but there's no way to pass the - fd to this function. Rather than rely on a global variable - we pretend to open the seq again. */ - fd = seq_open(); - if (_seqbufptr) - { - if (write(fd, _seqbuf, _seqbufptr) == -1) - { - WARN("Can't write data to sequencer %d, errno %d (%s)!\n", - fd, errno, strerror(errno)); - } - /* FIXME: In any case buffer is lost so that if many errors occur the buffer - * will not overrun */ - _seqbufptr = 0; - } - seq_close(fd); -} - -extern const unsigned char midiFMInstrumentPatches[16 * 128]; -extern const unsigned char midiFMDrumsPatches[16 * 128]; - -static int midi_out_fm_load(WORD dev_id, int fd) -{ - struct sbi_instrument sbi; - int i; - - sbi.device = dev_id; - sbi.key = FM_PATCH; - - memset(sbi.operators + 16, 0, 16); - for (i = 0; i < 128; i++) - { - sbi.channel = i; - memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16); - - if (write(fd, &sbi, sizeof(sbi)) == -1) - { - WARN("Couldn't write patch for instrument %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno)); - return -1; - } - } - for (i = 0; i < 128; i++) - { - sbi.channel = 128 + i; - memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16); - - if (write(fd, &sbi, sizeof(sbi)) == -1) - { - WARN("Couldn't write patch for drum %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno)); - return -1; - } - } - return 0; -} - -static void midi_out_fm_reset(WORD dev_id) -{ - struct midi_dest *dest = dests + dev_id; - sFMextra *extra = dest->lpExtra; - sVoice *voice = extra->voice; - sChannel *channel = extra->channel; - int i; - - for (i = 0; i < dest->caps.wVoices; i++) - { - if (voice[i].status != sVS_UNUSED) - SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64); - SEQ_KEY_PRESSURE(dev_id, i, 127, 0); - SEQ_CONTROL(dev_id, i, SEQ_VOLMODE, VOL_METHOD_LINEAR); - voice[i].note = 0; - voice[i].channel = -1; - voice[i].cntMark = 0; - voice[i].status = sVS_UNUSED; - } - for (i = 0; i < 16; i++) - { - channel[i].program = 0; - channel[i].bender = 8192; - channel[i].benderRange = 2; - channel[i].bank = 0; - channel[i].volume = 127; - channel[i].balance = 64; - channel[i].expression = 0; - channel[i].sustain = 0; - } - extra->counter = 0; - extra->drumSetMask = 1 << 9; /* channel 10 is normally drums, sometimes 16 also */ - SEQ_DUMPBUF(); -} - -static void set_out_notify(struct notify_context *notify, struct midi_dest *dest, WORD dev_id, WORD msg, - UINT_PTR param_1, UINT_PTR param_2) -{ - notify->send_notify = TRUE; - notify->dev_id = dev_id; - notify->msg = msg; - notify->param_1 = param_1; - notify->param_2 = param_2; - notify->callback = dest->midiDesc.dwCallback; - notify->flags = dest->wFlags; - notify->device = dest->midiDesc.hMidi; - notify->instance = dest->midiDesc.dwInstance; -} - -static UINT midi_out_open(WORD dev_id, MIDIOPENDESC *midi_desc, UINT flags, struct notify_context *notify) -{ - struct midi_dest *dest; - int fd = -1; - - TRACE("(%04X, %p, %08X);\n", dev_id, midi_desc, flags); - if (midi_desc == NULL) - { - WARN("Invalid Parameter !\n"); - return MMSYSERR_INVALPARAM; - } - if (dev_id >= num_dests) - { - TRACE("MAX_MIDIOUTDRV reached !\n"); - return MMSYSERR_BADDEVICEID; - } - dest = dests + dev_id; - if (dest->midiDesc.hMidi != 0) - { - WARN("device already open !\n"); - return MMSYSERR_ALLOCATED; - } - if (!dest->bEnabled) - { - WARN("device disabled !\n"); - return MIDIERR_NODEVICE; - } - if ((flags & ~CALLBACK_TYPEMASK) != 0) - { - WARN("bad flags\n"); - return MMSYSERR_INVALFLAG; - } - - dest->lpExtra = NULL; - - switch (dest->caps.wTechnology) - { - case MOD_FMSYNTH: - { - void *extra; - - extra = malloc(offsetof(struct sFMextra, voice[dest->caps.wVoices])); - if (!extra) - { - WARN("can't alloc extra data !\n"); - return MMSYSERR_NOMEM; - } - dest->lpExtra = extra; - fd = seq_open(); - if (fd < 0) - { - dest->lpExtra = NULL; - free(extra); - return MMSYSERR_ERROR; - } - if (midi_out_fm_load(dev_id, fd) < 0) - { - seq_close(fd); - dest->lpExtra = NULL; - free(extra); - return MMSYSERR_ERROR; - } - midi_out_fm_reset(dev_id); - break; - } - case MOD_MIDIPORT: - case MOD_SYNTH: - fd = seq_open(); - if (fd < 0) - return MMSYSERR_ALLOCATED; - break; - default: - WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology); - return MMSYSERR_NOTENABLED; - } - - dest->runningStatus = 0; - dest->wFlags = HIWORD(flags & CALLBACK_TYPEMASK); - - dest->lpQueueHdr= NULL; - dest->midiDesc = *midi_desc; - dest->fd = fd; - - set_out_notify(notify, dest, dev_id, MOM_OPEN, 0, 0); - TRACE("Successful !\n"); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_close(WORD dev_id, struct notify_context *notify) -{ - struct midi_dest *dest; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_dests) - { - TRACE("MAX_MIDIOUTDRV reached !\n"); - return MMSYSERR_BADDEVICEID; - } - dest = dests + dev_id; - - if (dest->midiDesc.hMidi == 0) - { - WARN("device not opened !\n"); - return MMSYSERR_ERROR; - } - /* FIXME: should test that no pending buffer is still in the queue for - * playing */ - - if (dest->fd == -1) - { - WARN("can't close !\n"); - return MMSYSERR_ERROR; - } - - switch (dest->caps.wTechnology) - { - case MOD_FMSYNTH: - case MOD_SYNTH: - case MOD_MIDIPORT: - seq_close(dest->fd); - break; - default: - WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology); - return MMSYSERR_NOTENABLED; - } - - free(dest->lpExtra); - dest->lpExtra = NULL; - dest->fd = -1; - - set_out_notify(notify, dest, dev_id, MOM_CLOSE, 0, 0); - dest->midiDesc.hMidi = 0; - return MMSYSERR_NOERROR; -} - -static UINT midi_out_fm_data(WORD dev_id, UINT data) -{ - struct midi_dest *dest = dests + dev_id; - BYTE evt = LOBYTE(LOWORD(data)), d1, d2; - sFMextra *extra = dest->lpExtra; - sVoice *voice = extra->voice; - sChannel *channel = extra->channel; - int chn = (evt & 0x0F), i, nv; - - if (evt & 0x80) - { - d1 = HIBYTE(LOWORD(data)); - d2 = LOBYTE(HIWORD(data)); - if (evt < 0xF0) - dest->runningStatus = evt; - } - else if (dest->runningStatus) - { - evt = dest->runningStatus; - d1 = LOBYTE(LOWORD(data)); - d2 = HIBYTE(LOWORD(data)); - } - else - { - FIXME("ooch %x\n", data); - return MMSYSERR_NOERROR; - } - - /* FIXME: chorus depth controller is not used */ - - switch (evt & 0xF0) - { - case MIDI_NOTEOFF: - for (i = 0; i < dest->caps.wVoices; i++) - { - /* don't stop sustained notes */ - if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) - { - voice[i].status = sVS_UNUSED; - SEQ_STOP_NOTE(dev_id, i, d1, d2); - } - } - break; - case MIDI_NOTEON: - if (d2 == 0) /* note off if velocity == 0 */ - { - for (i = 0; i < dest->caps.wVoices; i++) /* don't stop sustained notes */ - { - if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) - { - voice[i].status = sVS_UNUSED; - SEQ_STOP_NOTE(dev_id, i, d1, 64); - } - } - break; - } - /* finding out in this order : - * - an empty voice - * - if replaying the same note on the same channel - * - the older voice (LRU) - */ - for (i = nv = 0; i < dest->caps.wVoices; i++) - { - if (voice[i].status == sVS_UNUSED || (voice[i].note == d1 && voice[i].channel == chn)) - { - nv = i; - break; - } - if (voice[i].cntMark < voice[0].cntMark) - nv = i; - } - TRACE("playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, bender=0x%02X, note=0x%02X, vel=0x%02X\n", - nv, channel[chn].program, channel[chn].balance, channel[chn].volume, channel[chn].bender, d1, d2); - - SEQ_SET_PATCH(dev_id, nv, IS_DRUM_CHANNEL(extra, chn) ? - (128 + d1) : channel[chn].program); - SEQ_BENDER_RANGE(dev_id, nv, channel[chn].benderRange * 100); - SEQ_BENDER(dev_id, nv, channel[chn].bender); - SEQ_CONTROL(dev_id, nv, CTL_PAN, channel[chn].balance); - SEQ_CONTROL(dev_id, nv, CTL_EXPRESSION, channel[chn].expression); - SEQ_START_NOTE(dev_id, nv, d1, d2); - voice[nv].status = channel[chn].sustain ? sVS_SUSTAINED : sVS_PLAYING; - voice[nv].note = d1; - voice[nv].channel = chn; - voice[nv].cntMark = extra->counter++; - break; - case MIDI_KEY_PRESSURE: - for (i = 0; i < dest->caps.wVoices; i++) - if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1) - SEQ_KEY_PRESSURE(dev_id, i, d1, d2); - break; - case MIDI_CTL_CHANGE: - switch (d1) - { - case CTL_BANK_SELECT: channel[chn].bank = d2; break; - case CTL_MAIN_VOLUME: channel[chn].volume = d2; break; - case CTL_PAN: channel[chn].balance = d2; break; - case CTL_EXPRESSION: channel[chn].expression = d2; break; - case CTL_SUSTAIN: channel[chn].sustain = d2; - if (d2) - { - for (i = 0; i < dest->caps.wVoices; i++) - if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) - voice[i].status = sVS_SUSTAINED; - } - else - { - for (i = 0; i < dest->caps.wVoices; i++) - { - if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn) - { - voice[i].status = sVS_UNUSED; - SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64); - } - } - } - break; - case CTL_NONREG_PARM_NUM_LSB: channel[chn].nrgPmtLSB = d2; break; - case CTL_NONREG_PARM_NUM_MSB: channel[chn].nrgPmtMSB = d2; break; - case CTL_REGIST_PARM_NUM_LSB: channel[chn].regPmtLSB = d2; break; - case CTL_REGIST_PARM_NUM_MSB: channel[chn].regPmtMSB = d2; break; - case CTL_DATA_ENTRY: - switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB) - { - case 0x0000: - if (channel[chn].benderRange != d2) - { - channel[chn].benderRange = d2; - for (i = 0; i < dest->caps.wVoices; i++) - if (voice[i].channel == chn) - SEQ_BENDER_RANGE(dev_id, i, channel[chn].benderRange); - } - break; - - case 0x7F7F: - channel[chn].benderRange = 2; - for (i = 0; i < dest->caps.wVoices; i++) - if (voice[i].channel == chn) - SEQ_BENDER_RANGE(dev_id, i, channel[chn].benderRange); - break; - default: - TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n", - channel[chn].regPmtMSB, channel[chn].regPmtLSB, - channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB, d2); - break; - } - break; - - case 0x78: /* all sounds off */ - /* FIXME: I don't know if I have to take care of the channel for this control? */ - for (i = 0; i < dest->caps.wVoices; i++) - { - if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) - { - voice[i].status = sVS_UNUSED; - SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64); - } - } - break; - case 0x7B: /* all notes off */ - /* FIXME: I don't know if I have to take care of the channel for this control? */ - for (i = 0; i < dest->caps.wVoices; i++) - { - if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) - { - voice[i].status = sVS_UNUSED; - SEQ_STOP_NOTE(dev_id, i, voice[i].note, 64); - } - } - break; - default: - TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n", d1, d2, chn); - break; - } - break; - case MIDI_PGM_CHANGE: - channel[chn].program = d1; - break; - case MIDI_CHN_PRESSURE: - for (i = 0; i < dest->caps.wVoices; i++) - if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) - SEQ_KEY_PRESSURE(dev_id, i, voice[i].note, d1); - - break; - case MIDI_PITCH_BEND: - channel[chn].bender = (d2 << 7) + d1; - for (i = 0; i < dest->caps.wVoices; i++) - if (voice[i].channel == chn) - SEQ_BENDER(dev_id, i, channel[chn].bender); - break; - case MIDI_SYSTEM_PREFIX: - switch (evt & 0x0F) - { - case 0x0F: /* Reset */ - midi_out_fm_reset(dev_id); - dest->runningStatus = 0; - break; - default: - WARN("Unsupported (yet) system event %02x\n", evt & 0x0F); - } - if (evt <= 0xF7) - dest->runningStatus = 0; - break; - default: - WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0); - return MMSYSERR_NOTENABLED; - } - - SEQ_DUMPBUF(); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_port_data(WORD dev_id, UINT data) -{ - struct midi_dest *dest = dests + dev_id; - BYTE evt = LOBYTE(LOWORD(data)), d1, d2; - int dev = dev_id - num_synths; - - if (dev < 0) - { - WARN("Internal error on devID (%u) !\n", dev_id); - return MIDIERR_NODEVICE; - } - - if (evt & 0x80) - { - d1 = HIBYTE(LOWORD(data)); - d2 = LOBYTE(HIWORD(data)); - } - else if (dest->runningStatus) - { - evt = dest->runningStatus; - d1 = LOBYTE(LOWORD(data)); - d2 = HIBYTE(LOWORD(data)); - } - else - { - FIXME("ooch %x\n", data); - return MMSYSERR_NOERROR; - } - - switch (evt & 0xF0) - { - case MIDI_NOTEOFF: - case MIDI_NOTEON: - case MIDI_KEY_PRESSURE: - case MIDI_CTL_CHANGE: - case MIDI_PITCH_BEND: - if (LOBYTE(LOWORD(data)) >= 0x80) - { - SEQ_MIDIOUT(dev, evt); - dest->runningStatus = evt; - } - SEQ_MIDIOUT(dev, d1); - SEQ_MIDIOUT(dev, d2); - break; - case MIDI_PGM_CHANGE: - case MIDI_CHN_PRESSURE: - if (LOBYTE(LOWORD(data)) >= 0x80) - { - SEQ_MIDIOUT(dev, evt); - dest->runningStatus = evt; - } - SEQ_MIDIOUT(dev, d1); - break; - case MIDI_SYSTEM_PREFIX: - switch (evt & 0x0F) - { - case 0x00: /* System Exclusive, don't do it on MODM_DATA, should require MODM_LONGDATA */ - case 0x04: /* Undefined. */ - case 0x05: /* Undefined. */ - case 0x07: /* End of Exclusive. */ - case 0x09: /* Undefined. */ - case 0x0D: /* Undefined. */ - break; - case 0x06: /* Tune Request */ - case 0x08: /* Timing Clock. */ - case 0x0A: /* Start. */ - case 0x0B: /* Continue */ - case 0x0C: /* Stop */ - case 0x0E: /* Active Sensing. */ - SEQ_MIDIOUT(dev, evt); - break; - case 0x0F: /* Reset */ - SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX); - SEQ_MIDIOUT(dev, 0x7e); - SEQ_MIDIOUT(dev, 0x7f); - SEQ_MIDIOUT(dev, 0x09); - SEQ_MIDIOUT(dev, 0x01); - SEQ_MIDIOUT(dev, 0xf7); - dest->runningStatus = 0; - break; - case 0x01: /* MTC Quarter frame */ - case 0x03: /* Song Select. */ - SEQ_MIDIOUT(dev, evt); - SEQ_MIDIOUT(dev, d1); - break; - case 0x02: /* Song Position Pointer. */ - SEQ_MIDIOUT(dev, evt); - SEQ_MIDIOUT(dev, d1); - SEQ_MIDIOUT(dev, d2); - } - if (evt <= 0xF7) /* System Exclusive, System Common Message */ - dest->runningStatus = 0; - break; - } - - SEQ_DUMPBUF(); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_data(WORD dev_id, UINT data) -{ - struct midi_dest *dest; - - TRACE("(%04X, %08X);\n", dev_id, data); - - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - dest = dests + dev_id; - if (!dest->bEnabled) return MIDIERR_NODEVICE; - - if (dest->fd == -1) - { - WARN("can't play !\n"); - return MIDIERR_NODEVICE; - } - switch (dest->caps.wTechnology) - { - case MOD_FMSYNTH: - return midi_out_fm_data(dev_id, data); - case MOD_MIDIPORT: - return midi_out_port_data(dev_id, data); - } - - WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology); - return MMSYSERR_NOTENABLED; -} - -static UINT midi_out_long_data(WORD dev_id, MIDIHDR *hdr, UINT hdr_size, struct notify_context *notify) -{ - struct midi_dest *dest; - BYTE *data; - unsigned int count; - - TRACE("(%04X, %p, %08X);\n", dev_id, hdr, hdr_size); - - /* Note: MS doc does not say much about the dwBytesRecorded member of the MIDIHDR structure - * but it seems to be used only for midi input. - * Taking a look at the WAVEHDR structure (which is quite similar) confirms this assumption. - */ - - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - dest = dests + dev_id; - if (!dest->bEnabled) return MIDIERR_NODEVICE; - - if (dest->fd == -1) - { - WARN("can't play !\n"); - return MIDIERR_NODEVICE; - } - - data = (BYTE *)hdr->lpData; - - if (data == NULL) - return MIDIERR_UNPREPARED; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MIDIERR_UNPREPARED; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - hdr->dwFlags &= ~MHDR_DONE; - hdr->dwFlags |= MHDR_INQUEUE; - - /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive - * data, or can it also contain raw MIDI data, to be split up and sent to - * modShortData() ? - * If the latter is true, then the following WARNing will fire up - */ - if (data[0] != 0xF0 || data[hdr->dwBufferLength - 1] != 0xF7) - WARN("The allegedly system exclusive buffer is not correct\n\tPlease report with MIDI file\n"); - - TRACE("dwBufferLength=%u !\n", (unsigned)hdr->dwBufferLength); - TRACE(" %02X %02X %02X ... %02X %02X %02X\n", - data[0], data[1], data[2], data[hdr->dwBufferLength - 3], - data[hdr->dwBufferLength - 2], data[hdr->dwBufferLength - 1]); - - switch (dest->caps.wTechnology) - { - case MOD_FMSYNTH: - /* FIXME: I don't think there is much to do here */ - break; - case MOD_MIDIPORT: - if (data[0] != 0xF0) - { - /* Send end of System Exclusive */ - SEQ_MIDIOUT(dev_id - num_synths, 0xF0); - WARN("Adding missing 0xF0 marker at the beginning of system exclusive byte stream\n"); - } - for (count = 0; count < hdr->dwBufferLength; count++) - SEQ_MIDIOUT(dev_id - num_synths, data[count]); - if (data[count - 1] != 0xF7) - { - /* Send end of System Exclusive */ - SEQ_MIDIOUT(dev_id - num_synths, 0xF7); - WARN("Adding missing 0xF7 marker at the end of system exclusive byte stream\n"); - } - SEQ_DUMPBUF(); - break; - default: - WARN("Technology not supported (yet) %d !\n", dest->caps.wTechnology); - return MMSYSERR_NOTENABLED; - } - - dest->runningStatus = 0; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - set_out_notify(notify, dest, dev_id, MOM_DONE, (UINT_PTR)hdr, 0); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - return MMSYSERR_NOERROR; -} - -static UINT midi_out_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -static UINT midi_out_get_devcaps(WORD dev_id, MIDIOUTCAPSW *caps, UINT size) -{ - TRACE("(%04X, %p, %08X);\n", dev_id, caps, size); - - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - if (!caps) return MMSYSERR_INVALPARAM; - - memcpy(caps, &dests[dev_id].caps, min(size, sizeof(*caps))); - - return MMSYSERR_NOERROR; -} - -static UINT midi_out_get_volume(WORD dev_id, UINT *volume) -{ - if (!volume) return MMSYSERR_INVALPARAM; - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - - *volume = 0xFFFFFFFF; - return (dests[dev_id].caps.dwSupport & MIDICAPS_VOLUME) ? 0 : MMSYSERR_NOTSUPPORTED; -} - -static UINT midi_out_reset(WORD dev_id) -{ - struct midi_dest *dest; - unsigned chn; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_dests) return MMSYSERR_BADDEVICEID; - dest = dests + dev_id; - if (!dest->bEnabled) return MIDIERR_NODEVICE; - - /* stop all notes */ - for (chn = 0; chn < 16; chn++) - { - /* turn off every note */ - midi_out_data(dev_id, 0x7800 | MIDI_CTL_CHANGE | chn); - /* remove sustain on all channels */ - midi_out_data(dev_id, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn); - } - dest->runningStatus = 0; - /* FIXME: the LongData buffers must also be returned to the app */ - return MMSYSERR_NOERROR; -} - -static void handle_sysex_data(struct midi_src *src, unsigned char value, UINT time) -{ - struct notify_context notify; - MIDIHDR *hdr; - BOOL done = FALSE; - - src->state |= 2; - src->incLen = 0; - - in_buffer_lock(); - - hdr = src->lpQueueHdr; - if (hdr) - { - BYTE *data = (BYTE *)hdr->lpData; - - data[hdr->dwBytesRecorded++] = value; - if (hdr->dwBytesRecorded == hdr->dwBufferLength) - done = TRUE; - } - - if (value == 0xf7) /* end */ - { - src->state &= ~2; - done = TRUE; - } - - if (done && hdr) - { - src->lpQueueHdr = hdr->lpNext; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - set_in_notify(¬ify, src, src - srcs, MIM_LONGDATA, (UINT_PTR)hdr, time); - notify_post(¬ify); - } - - in_buffer_unlock(); -} - -static void handle_regular_data(struct midi_src *src, unsigned char value, UINT time) -{ - struct notify_context notify; - UINT to_send = 0; - -#define IS_CMD(_x) (((_x) & 0x80) == 0x80) -#define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0) - - if (!IS_CMD(value) && src->incLen == 0) /* try to reuse old cmd */ - { - if (IS_CMD(src->incPrev) && !IS_SYS_CMD(src->incPrev)) - { - src->incoming[0] = src->incPrev; - src->incLen = 1; - } - else - { - /* FIXME: should generate MIM_ERROR notification */ - return; - } - } - src->incoming[(int)src->incLen++] = value; - if (src->incLen == 1 && !IS_SYS_CMD(src->incoming[0])) - /* store new cmd, just in case */ - src->incPrev = src->incoming[0]; - -#undef IS_CMD -#undef IS_SYS_CMD - - switch (src->incoming[0] & 0xF0) - { - case MIDI_NOTEOFF: - case MIDI_NOTEON: - case MIDI_KEY_PRESSURE: - case MIDI_CTL_CHANGE: - case MIDI_PITCH_BEND: - if (src->incLen == 3) - to_send = (src->incoming[2] << 16) | (src->incoming[1] << 8) | - src->incoming[0]; - break; - case MIDI_PGM_CHANGE: - case MIDI_CHN_PRESSURE: - if (src->incLen == 2) - to_send = (src->incoming[1] << 8) | src->incoming[0]; - break; - case MIDI_SYSTEM_PREFIX: - if (src->incLen == 1) - to_send = src->incoming[0]; - break; - } - - if (to_send) - { - src->incLen = 0; - set_in_notify(¬ify, src, src - srcs, MIM_DATA, to_send, time); - notify_post(¬ify); - } -} - -static void handle_midi_data(unsigned char *buffer, unsigned int len) -{ - unsigned int time = get_time_msec(), i; - struct midi_src *src; - unsigned char value; - WORD dev_id; - - for (i = 0; i < len; i += (buffer[i] & 0x80) ? 8 : 4) - { - if (buffer[i] != SEQ_MIDIPUTC) continue; - - dev_id = buffer[i + 2]; - value = buffer[i + 1]; - - if (dev_id >= num_srcs) continue; - src = srcs + dev_id; - if (src->state <= 0) continue; - - if (value == 0xf0 || src->state & 2) /* system exclusive */ - handle_sysex_data(src, value, time - src->startTime); - else - handle_regular_data(src, value, time - src->startTime); - } -} - -static void *rec_thread_proc(void *arg) -{ - int fd = PtrToLong(arg); - unsigned char buffer[256]; - int len; - struct pollfd pollfd[2]; - - pollfd[0].fd = rec_cancel_pipe[0]; - pollfd[0].events = POLLIN; - pollfd[1].fd = fd; - pollfd[1].events = POLLIN; - - while (1) - { - /* Check if an event is present */ - if (poll(pollfd, ARRAY_SIZE(pollfd), -1) <= 0) - continue; - - if (pollfd[0].revents & POLLIN) /* cancelled */ - break; - - len = read(fd, buffer, sizeof(buffer)); - - if (len > 0 && len % 4 == 0) - handle_midi_data(buffer, len); - } - return NULL; -} - -static UINT midi_in_open(WORD dev_id, MIDIOPENDESC *desc, UINT flags, struct notify_context *notify) -{ - struct midi_src *src; - int fd; - - TRACE("(%04X, %p, %08X);\n", dev_id, desc, flags); - - if (desc == NULL) - { - WARN("Invalid Parameter !\n"); - return MMSYSERR_INVALPARAM; - } - - /* FIXME : - * how to check that content of lpDesc is correct ? - */ - if (dev_id >= num_srcs) - { - WARN("wDevID too large (%u) !\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - src = srcs + dev_id; - if (src->state == -1) - { - WARN("device disabled\n"); - return MIDIERR_NODEVICE; - } - if (src->midiDesc.hMidi != 0) - { - WARN("device already open !\n"); - return MMSYSERR_ALLOCATED; - } - if ((flags & MIDI_IO_STATUS) != 0) - { - WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n"); - flags &= ~MIDI_IO_STATUS; - } - if ((flags & ~CALLBACK_TYPEMASK) != 0) - { - FIXME("Bad flags\n"); - return MMSYSERR_INVALFLAG; - } - - fd = seq_open(); - if (fd < 0) - return MMSYSERR_ERROR; - - if (num_midi_in_started++ == 0) - { - pipe(rec_cancel_pipe); - if (pthread_create(&rec_thread_id, NULL, rec_thread_proc, LongToPtr(fd))) - { - close(rec_cancel_pipe[0]); - close(rec_cancel_pipe[1]); - num_midi_in_started = 0; - WARN("Couldn't create thread for midi-in\n"); - seq_close(fd); - return MMSYSERR_ERROR; - } - TRACE("Created thread for midi-in\n"); - } - - src->wFlags = HIWORD(flags & CALLBACK_TYPEMASK); - - src->lpQueueHdr = NULL; - src->midiDesc = *desc; - src->state = 0; - src->incLen = 0; - src->startTime = 0; - src->fd = fd; - - set_in_notify(notify, src, dev_id, MIM_OPEN, 0, 0); - return MMSYSERR_NOERROR; -} - -static UINT midi_in_close(WORD dev_id, struct notify_context *notify) -{ - struct midi_src *src; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_srcs) - { - WARN("dev_id too big (%u) !\n", dev_id); - return MMSYSERR_BADDEVICEID; - } - src = srcs + dev_id; - if (src->midiDesc.hMidi == 0) - { - WARN("device not opened !\n"); - return MMSYSERR_ERROR; - } - if (src->lpQueueHdr != 0) - return MIDIERR_STILLPLAYING; - - if (src->fd == -1) - { - WARN("ooops !\n"); - return MMSYSERR_ERROR; - } - if (--num_midi_in_started == 0) - { - TRACE("Stopping thread for midi-in\n"); - write(rec_cancel_pipe[1], "x", 1); - pthread_join(rec_thread_id, NULL); - close(rec_cancel_pipe[0]); - close(rec_cancel_pipe[1]); - TRACE("Stopped thread for midi-in\n"); - } - seq_close(src->fd); - src->fd = -1; - - set_in_notify(notify, src, dev_id, MIM_CLOSE, 0, 0); - src->midiDesc.hMidi = 0; - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_add_buffer(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - struct midi_src *src; - MIDIHDR **next; - - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - src = srcs + dev_id; - if (src->state == -1) return MIDIERR_NODEVICE; - - if (!hdr || hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr->dwBufferLength) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING; - if (!(hdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED; - - in_buffer_lock(); - - hdr->dwFlags &= ~WHDR_DONE; - hdr->dwFlags |= MHDR_INQUEUE; - hdr->dwBytesRecorded = 0; - hdr->lpNext = NULL; - - next = &src->lpQueueHdr; - while (*next) next = &(*next)->lpNext; - *next = hdr; - - in_buffer_unlock(); - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_prepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = NULL; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_unprepare(WORD dev_id, MIDIHDR *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(MIDIHDR, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_get_devcaps(WORD dev_id, MIDIINCAPSW *caps, UINT size) -{ - TRACE("(%04X, %p, %08X);\n", dev_id, caps, size); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - if (!caps) return MMSYSERR_INVALPARAM; - - memcpy(caps, &srcs[dev_id].caps, min(size, sizeof(*caps))); - - return MMSYSERR_NOERROR; -} - -static UINT midi_in_start(WORD dev_id) -{ - struct midi_src *src; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - src = srcs + dev_id; - if (src->state == -1) return MIDIERR_NODEVICE; - - src->state = 1; - src->startTime = get_time_msec(); - return MMSYSERR_NOERROR; -} - -static UINT midi_in_stop(WORD dev_id) -{ - struct midi_src *src; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - src = srcs + dev_id; - if (src->state == -1) return MIDIERR_NODEVICE; - - src->state = 0; - return MMSYSERR_NOERROR; -} - -static UINT midi_in_reset(WORD dev_id, struct notify_context *notify) -{ - UINT cur_time = get_time_msec(); - UINT err = MMSYSERR_NOERROR; - struct midi_src *src; - MIDIHDR *hdr; - - TRACE("(%04X);\n", dev_id); - - if (dev_id >= num_srcs) return MMSYSERR_BADDEVICEID; - src = srcs + dev_id; - if (src->state == -1) return MIDIERR_NODEVICE; - - in_buffer_lock(); - - if (src->lpQueueHdr) - { - hdr = src->lpQueueHdr; - src->lpQueueHdr = hdr->lpNext; - hdr->dwFlags &= ~MHDR_INQUEUE; - hdr->dwFlags |= MHDR_DONE; - set_in_notify(notify, src, dev_id, MIM_LONGDATA, (UINT_PTR)hdr, cur_time - src->startTime); - if (src->lpQueueHdr) err = ERROR_RETRY; /* ask the client to call again */ - } - - in_buffer_unlock(); - - return err; -} - -NTSTATUS oss_midi_out_message(void *args) -{ - struct midi_out_message_params *params = args; - - params->notify->send_notify = FALSE; - - switch (params->msg) - { - case DRVM_INIT: - *params->err = oss_midi_init(); - break; - case DRVM_EXIT: - *params->err = midi_exit(); - break; - case DRVM_ENABLE: - case DRVM_DISABLE: - /* FIXME: Pretend this is supported */ - *params->err = MMSYSERR_NOERROR; - break; - case MODM_OPEN: - *params->err = midi_out_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify); - break; - case MODM_CLOSE: - *params->err = midi_out_close(params->dev_id, params->notify); - break; - case MODM_DATA: - *params->err = midi_out_data(params->dev_id, params->param_1); - break; - case MODM_LONGDATA: - *params->err = midi_out_long_data(params->dev_id, (MIDIHDR *)params->param_1, params->param_2, params->notify); - break; - case MODM_PREPARE: - *params->err = midi_out_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MODM_UNPREPARE: - *params->err = midi_out_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MODM_GETDEVCAPS: - *params->err = midi_out_get_devcaps(params->dev_id, (MIDIOUTCAPSW *)params->param_1, params->param_2); - break; - case MODM_GETNUMDEVS: - *params->err = num_dests; - break; - case MODM_GETVOLUME: - *params->err = midi_out_get_volume(params->dev_id, (UINT *)params->param_1); - break; - case MODM_SETVOLUME: - *params->err = 0; - break; - case MODM_RESET: - *params->err = midi_out_reset(params->dev_id); - break; - default: - TRACE("Unsupported message\n"); - *params->err = MMSYSERR_NOTSUPPORTED; - } - - return STATUS_SUCCESS; -} - -NTSTATUS oss_midi_in_message(void *args) -{ - struct midi_in_message_params *params = args; - - params->notify->send_notify = FALSE; - - switch (params->msg) - { - case DRVM_INIT: - *params->err = oss_midi_init(); - break; - case DRVM_EXIT: - *params->err = midi_exit(); - break; - case DRVM_ENABLE: - case DRVM_DISABLE: - /* FIXME: Pretend this is supported */ - *params->err = MMSYSERR_NOERROR; - break; - case MIDM_OPEN: - *params->err = midi_in_open(params->dev_id, (MIDIOPENDESC *)params->param_1, params->param_2, params->notify); - break; - case MIDM_CLOSE: - *params->err = midi_in_close(params->dev_id, params->notify); - break; - case MIDM_ADDBUFFER: - *params->err = midi_in_add_buffer(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_PREPARE: - *params->err = midi_in_prepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_UNPREPARE: - *params->err = midi_in_unprepare(params->dev_id, (MIDIHDR *)params->param_1, params->param_2); - break; - case MIDM_GETDEVCAPS: - *params->err = midi_in_get_devcaps(params->dev_id, (MIDIINCAPSW *)params->param_1, params->param_2); - break; - case MIDM_GETNUMDEVS: - *params->err = num_srcs; - break; - case MIDM_START: - *params->err = midi_in_start(params->dev_id); - break; - case MIDM_STOP: - *params->err = midi_in_stop(params->dev_id); - break; - case MIDM_RESET: - *params->err = midi_in_reset(params->dev_id, params->notify); - break; - default: - TRACE("Unsupported message\n"); - *params->err = MMSYSERR_NOTSUPPORTED; - } - - return STATUS_SUCCESS; -} - -NTSTATUS oss_midi_notify_wait(void *args) -{ - struct midi_notify_wait_params *params = args; - - pthread_mutex_lock(¬ify_mutex); - - while (!notify_quit && notify_buffer_empty()) - pthread_cond_wait(¬ify_read_cond, ¬ify_mutex); - - *params->quit = notify_quit; - if (!notify_quit) - { - notify_buffer_remove(params->notify); - pthread_cond_signal(¬ify_write_cond); - } - pthread_mutex_unlock(¬ify_mutex); - - return STATUS_SUCCESS; -} - -#ifdef _WIN64 - -typedef UINT PTR32; - -struct notify_context32 -{ - BOOL send_notify; - WORD dev_id; - WORD msg; - UINT param_1; - UINT param_2; - UINT callback; - UINT flags; - PTR32 device; - UINT instance; -}; - -static void notify_to_notify32(struct notify_context32 *notify32, - const struct notify_context *notify) -{ - notify32->send_notify = notify->send_notify; - notify32->dev_id = notify->dev_id; - notify32->msg = notify->msg; - notify32->param_1 = notify->param_1; - notify32->param_2 = notify->param_2; - notify32->callback = notify->callback; - notify32->flags = notify->flags; - notify32->device = PtrToUlong(notify->device); - notify32->instance = notify->instance; -} - -struct midi_open_desc32 -{ - PTR32 hMidi; - UINT dwCallback; - UINT dwInstance; - UINT dnDevNode; - UINT cIds; - MIDIOPENSTRMID rgIds; -}; - -struct midi_hdr32 -{ - PTR32 lpData; - UINT dwBufferLength; - UINT dwBytesRecorded; - UINT dwUser; - UINT dwFlags; - PTR32 lpNext; - UINT reserved; - UINT dwOffset; - UINT dwReserved[8]; -}; - -static UINT wow64_midi_out_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - return MMSYSERR_NOERROR; -} - -static UINT wow64_midi_out_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - return MMSYSERR_NOERROR; -} - -NTSTATUS oss_wow64_midi_out_message(void *args) -{ - struct - { - UINT dev_id; - UINT msg; - UINT user; - UINT param_1; - UINT param_2; - PTR32 err; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_open_desc32 *desc32; - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIOPENDESC open_desc; - MIDIHDR hdr; - struct midi_out_message_params params = - { - .dev_id = params32->dev_id, - .msg = params32->msg, - .user = params32->user, - .param_1 = params32->param_1, - .param_2 = params32->param_2, - .err = ULongToPtr(params32->err), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - switch (params32->msg) - { - case MODM_OPEN: - desc32 = ULongToPtr(params32->param_1); - - open_desc.hMidi = ULongToPtr(desc32->hMidi); - open_desc.dwCallback = desc32->dwCallback; - open_desc.dwInstance = desc32->dwInstance; - open_desc.dnDevNode = desc32->dnDevNode; - open_desc.cIds = desc32->cIds; - open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID; - open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID; - - params.param_1 = (UINT_PTR)&open_desc; - break; - - case MODM_LONGDATA: - hdr32 = ULongToPtr(params32->param_1); - - memset(&hdr, 0, sizeof(hdr)); - hdr.lpData = ULongToPtr(hdr32->lpData); - hdr.dwBufferLength = hdr32->dwBufferLength; - hdr.dwFlags = hdr32->dwFlags; - - params.param_1 = (UINT_PTR)&hdr; - params.param_2 = sizeof(hdr); - break; - - case MODM_PREPARE: /* prepare and unprepare are easier to handle explicitly */ - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_out_prepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - - case MODM_UNPREPARE: - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_out_unprepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - } - - oss_midi_out_message(¶ms); - - switch (params32->msg) - { - case MODM_LONGDATA: - hdr32 = ULongToPtr(params32->param_1); - - hdr32->dwFlags = hdr.dwFlags; - break; - } - - if (notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MOM_DONE) - notify32->param_1 = params32->param_1; /* restore the 32-bit hdr */ - } - return STATUS_SUCCESS; -} - -static UINT wow64_midi_in_prepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (hdr->dwFlags & MHDR_PREPARED) - return MMSYSERR_NOERROR; - - hdr->lpNext = 0; - hdr->dwFlags |= MHDR_PREPARED; - hdr->dwFlags &= ~(MHDR_DONE | MHDR_INQUEUE); - - return MMSYSERR_NOERROR; -} - -static UINT wow64_midi_in_unprepare(WORD dev_id, struct midi_hdr32 *hdr, UINT hdr_size) -{ - TRACE("(%04X, %p, %d);\n", dev_id, hdr, hdr_size); - - if (hdr_size < offsetof(struct midi_hdr32, dwOffset) || !hdr || !hdr->lpData) - return MMSYSERR_INVALPARAM; - if (!(hdr->dwFlags & MHDR_PREPARED)) - return MMSYSERR_NOERROR; - if (hdr->dwFlags & MHDR_INQUEUE) - return MIDIERR_STILLPLAYING; - - hdr->dwFlags &= ~MHDR_PREPARED; - - return MMSYSERR_NOERROR; -} - -NTSTATUS oss_wow64_midi_in_message(void *args) -{ - struct - { - UINT dev_id; - UINT msg; - UINT user; - UINT param_1; - UINT param_2; - PTR32 err; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_open_desc32 *desc32; - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIOPENDESC open_desc; - MIDIHDR *hdr = NULL; - struct midi_in_message_params params = - { - .dev_id = params32->dev_id, - .msg = params32->msg, - .user = params32->user, - .param_1 = params32->param_1, - .param_2 = params32->param_2, - .err = ULongToPtr(params32->err), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - switch (params32->msg) - { - case MIDM_OPEN: - desc32 = ULongToPtr(params32->param_1); - - open_desc.hMidi = ULongToPtr(desc32->hMidi); - open_desc.dwCallback = desc32->dwCallback; - open_desc.dwInstance = desc32->dwInstance; - open_desc.dnDevNode = desc32->dnDevNode; - open_desc.cIds = desc32->cIds; - open_desc.rgIds.dwStreamID = desc32->rgIds.dwStreamID; - open_desc.rgIds.wDeviceID = desc32->rgIds.wDeviceID; - - params.param_1 = (UINT_PTR)&open_desc; - break; - - case MIDM_ADDBUFFER: - hdr32 = ULongToPtr(params32->param_1); - - hdr = calloc(1, sizeof(*hdr)); - hdr->lpData = ULongToPtr(hdr32->lpData); - hdr->dwBufferLength = hdr32->dwBufferLength; - hdr->dwFlags = hdr32->dwFlags; - hdr->dwReserved[7] = params32->param_1; /* keep hdr32 for MIM_LONGDATA notification */ - - params.param_1 = (UINT_PTR)hdr; - params.param_2 = sizeof(*hdr); - break; - - case MIDM_PREPARE: /* prepare and unprepare are easier to handle explicitly */ - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_in_prepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - - case MIDM_UNPREPARE: - hdr32 = ULongToPtr(params32->param_1); - - *params.err = wow64_midi_in_unprepare(params32->dev_id, hdr32, params32->param_2); - return STATUS_SUCCESS; - } - - oss_midi_in_message(¶ms); - - switch (params32->msg) - { - case MIDM_ADDBUFFER: - hdr32 = ULongToPtr(params32->param_1); - - if (!*params.err) - { - hdr32->dwFlags = hdr->dwFlags; - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->lpNext = 0; - } - else - free(hdr); - break; - } - - if (notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MIM_LONGDATA) - { - hdr = (MIDIHDR *)notify.param_1; - notify32->param_1 = hdr->dwReserved[7]; - hdr32 = ULongToPtr(notify32->param_1); - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->dwFlags = hdr->dwFlags; - free(hdr); - } - } - return STATUS_SUCCESS; -} - -NTSTATUS oss_wow64_midi_notify_wait(void *args) -{ - struct - { - PTR32 quit; - PTR32 notify; - } *params32 = args; - struct notify_context32 *notify32 = ULongToPtr(params32->notify); - struct midi_hdr32 *hdr32; - struct notify_context notify; - MIDIHDR *hdr; - struct midi_notify_wait_params params = - { - .quit = ULongToPtr(params32->quit), - .notify = ¬ify - }; - notify32->send_notify = FALSE; - - oss_midi_notify_wait(¶ms); - - if (!*params.quit && notify.send_notify) - { - notify_to_notify32(notify32, ¬ify); - - if (notify.msg == MIM_LONGDATA) - { - hdr = (MIDIHDR *)notify.param_1; - notify32->param_1 = hdr->dwReserved[7]; - hdr32 = ULongToPtr(notify32->param_1); - hdr32->dwBytesRecorded = hdr->dwBytesRecorded; - hdr32->dwFlags = hdr->dwFlags; - free(hdr); - } - } - return STATUS_SUCCESS; -} - -#endif /* _WIN64 */ diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/unixlib.h b/pkgs/osu-wine/audio-revert/wineoss.drv/unixlib.h deleted file mode 100644 index 54482a1..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/unixlib.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2022 Huw Davies - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "../mmdevapi/unixlib.h" - -NTSTATUS oss_midi_release(void *args); -NTSTATUS oss_midi_out_message(void *args); -NTSTATUS oss_midi_in_message(void *args); -NTSTATUS oss_midi_notify_wait(void *args); - -#ifdef _WIN64 -NTSTATUS oss_wow64_midi_out_message(void *args); -NTSTATUS oss_wow64_midi_in_message(void *args); -NTSTATUS oss_wow64_midi_notify_wait(void *args); -#endif - -#define OSS_CALL(func, params) WINE_UNIX_CALL(func, params) diff --git a/pkgs/osu-wine/audio-revert/wineoss.drv/wineoss.drv.spec b/pkgs/osu-wine/audio-revert/wineoss.drv/wineoss.drv.spec deleted file mode 100644 index fe6cc51..0000000 --- a/pkgs/osu-wine/audio-revert/wineoss.drv/wineoss.drv.spec +++ /dev/null @@ -1,11 +0,0 @@ -# WinMM driver functions -@ stdcall -private DriverProc(long long long long long) OSS_DriverProc -@ stdcall -private auxMessage(long long long long long) OSS_auxMessage -@ stdcall -private midMessage(long long long long long) OSS_midMessage -@ stdcall -private modMessage(long long long long long) OSS_modMessage - -# MMDevAPI driver functions -@ stdcall -private GetPriority() AUDDRV_GetPriority -@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs -@ stdcall -private GetAudioEndpoint(ptr ptr ptr) AUDDRV_GetAudioEndpoint -@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager diff --git a/pkgs/osu-wine/audio-revert/winepulse.drv/Makefile.in b/pkgs/osu-wine/audio-revert/winepulse.drv/Makefile.in deleted file mode 100644 index 4a9b417..0000000 --- a/pkgs/osu-wine/audio-revert/winepulse.drv/Makefile.in +++ /dev/null @@ -1,9 +0,0 @@ -MODULE = winepulse.drv -IMPORTS = dxguid uuid winmm user32 advapi32 ole32 -UNIX_LIBS = $(PULSE_LIBS) $(PTHREAD_LIBS) -UNIX_CFLAGS = $(PULSE_CFLAGS) - -EXTRADLLFLAGS = -mcygwin - -SOURCES = \ - mmdevdrv.c diff --git a/pkgs/osu-wine/audio-revert/winepulse.drv/mmdevdrv.c b/pkgs/osu-wine/audio-revert/winepulse.drv/mmdevdrv.c deleted file mode 100644 index 2ca2350..0000000 --- a/pkgs/osu-wine/audio-revert/winepulse.drv/mmdevdrv.c +++ /dev/null @@ -1,5663 +0,0 @@ -/* - * Copyright 2011-2012 Maarten Lankhorst - * Copyright 2010-2011 Maarten Lankhorst for CodeWeavers - * Copyright 2011 Andrew Eikum for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define NONAMELESSUNION -#define COBJMACROS -#undef WINE_UNIX_LIB - -#include "config.h" -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "windef.h" -#include "winbase.h" -#include "winnls.h" -#include "winreg.h" -#include "wine/debug.h" -#include "wine/unicode.h" -#include "wine/list.h" - -#include "ole2.h" -#include "dshow.h" -#include "dsound.h" -#include "propsys.h" -#include "propkey.h" - -#include "initguid.h" -#include "propkeydef.h" -#include "ks.h" -#include "ksmedia.h" -#include "mmdeviceapi.h" -#include "audioclient.h" -#include "endpointvolume.h" -#include "audiopolicy.h" - -WINE_DEFAULT_DEBUG_CHANNEL(pulse); - -#define NULL_PTR_ERR MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, RPC_X_NULL_REF_POINTER) - -/* From */ -enum DriverPriority { - Priority_Unavailable = 0, - Priority_Low, - Priority_Neutral, - Priority_Preferred -}; - -static pa_context *pulse_ctx; -static pa_mainloop *pulse_ml; - -static HANDLE pulse_thread; -static pthread_mutex_t pulse_lock; -static pthread_cond_t pulse_cond = PTHREAD_COND_INITIALIZER; -static struct list g_sessions = LIST_INIT(g_sessions); - -static UINT g_phys_speakers_mask = 0; - -/* Mixer format + period times */ -static WAVEFORMATEXTENSIBLE pulse_fmt[2]; -static REFERENCE_TIME pulse_min_period[2], pulse_def_period[2]; - -static GUID pulse_render_guid = -{ 0xfd47d9cc, 0x4218, 0x4135, { 0x9c, 0xe2, 0x0c, 0x19, 0x5c, 0x87, 0x40, 0x5b } }; -static GUID pulse_capture_guid = -{ 0x25da76d0, 0x033c, 0x4235, { 0x90, 0x02, 0x19, 0xf4, 0x88, 0x94, 0xac, 0x6f } }; - -static UINT8 mult_alaw_sample(UINT8, float); -static UINT8 mult_ulaw_sample(UINT8, float); - -BOOL WINAPI DllMain(HINSTANCE dll, DWORD reason, void *reserved) -{ - if (reason == DLL_PROCESS_ATTACH) { - pthread_mutexattr_t attr; - - DisableThreadLibraryCalls(dll); - - pthread_mutexattr_init(&attr); - pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); - - if (pthread_mutex_init(&pulse_lock, &attr) != 0) - pthread_mutex_init(&pulse_lock, NULL); - } else if (reason == DLL_PROCESS_DETACH) { - if (pulse_thread) - SetThreadPriority(pulse_thread, 0); - if (pulse_ctx) { - pa_context_disconnect(pulse_ctx); - pa_context_unref(pulse_ctx); - } - if (pulse_ml) - pa_mainloop_quit(pulse_ml, 0); - if (pulse_thread) { - WaitForSingleObject(pulse_thread, INFINITE); - CloseHandle(pulse_thread); - } - } - return TRUE; -} - -typedef struct ACImpl ACImpl; - -typedef struct _AudioSession { - GUID guid; - struct list clients; - - IMMDevice *device; - - float master_vol; - UINT32 channel_count; - float *channel_vols; - BOOL mute; - - struct list entry; -} AudioSession; - -typedef struct _AudioSessionWrapper { - IAudioSessionControl2 IAudioSessionControl2_iface; - IChannelAudioVolume IChannelAudioVolume_iface; - ISimpleAudioVolume ISimpleAudioVolume_iface; - - LONG ref; - - ACImpl *client; - AudioSession *session; -} AudioSessionWrapper; - -typedef struct _ACPacket { - struct list entry; - UINT64 qpcpos; - BYTE *data; - UINT32 discont; -} ACPacket; - -struct ACImpl { - IAudioClient IAudioClient_iface; - IAudioRenderClient IAudioRenderClient_iface; - IAudioCaptureClient IAudioCaptureClient_iface; - IAudioClock IAudioClock_iface; - IAudioClock2 IAudioClock2_iface; - IAudioStreamVolume IAudioStreamVolume_iface; - IUnknown *marshal; - IMMDevice *parent; - struct list entry; - float vol[PA_CHANNELS_MAX]; - - LONG ref; - EDataFlow dataflow; - DWORD flags; - AUDCLNT_SHAREMODE share; - HANDLE event; - - INT32 locked; - UINT32 bufsize_frames, bufsize_bytes, capture_period, pad, started, peek_ofs, wri_offs_bytes, lcl_offs_bytes; - UINT32 tmp_buffer_bytes, held_bytes, peek_len, peek_buffer_len; - BYTE *local_buffer, *tmp_buffer, *peek_buffer; - void *locked_ptr; - - pa_stream *stream; - pa_sample_spec ss; - pa_channel_map map; - pa_buffer_attr attr; - - INT64 clock_lastpos, clock_written; - - AudioSession *session; - AudioSessionWrapper *session_wrapper; - struct list packet_free_head; - struct list packet_filled_head; -}; - -static const WCHAR defaultW[] = {'P','u','l','s','e','a','u','d','i','o',0}; - -static const IAudioClientVtbl AudioClient_Vtbl; -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl; -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl; -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl; -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl; -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl; -static const IAudioClockVtbl AudioClock_Vtbl; -static const IAudioClock2Vtbl AudioClock2_Vtbl; -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl; - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client); - -static inline ACImpl *impl_from_IAudioClient(IAudioClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClient_iface); -} - -static inline ACImpl *impl_from_IAudioRenderClient(IAudioRenderClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioRenderClient_iface); -} - -static inline ACImpl *impl_from_IAudioCaptureClient(IAudioCaptureClient *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioCaptureClient_iface); -} - -static inline AudioSessionWrapper *impl_from_IAudioSessionControl2(IAudioSessionControl2 *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IAudioSessionControl2_iface); -} - -static inline AudioSessionWrapper *impl_from_ISimpleAudioVolume(ISimpleAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, ISimpleAudioVolume_iface); -} - -static inline AudioSessionWrapper *impl_from_IChannelAudioVolume(IChannelAudioVolume *iface) -{ - return CONTAINING_RECORD(iface, AudioSessionWrapper, IChannelAudioVolume_iface); -} - -static inline ACImpl *impl_from_IAudioClock(IAudioClock *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock_iface); -} - -static inline ACImpl *impl_from_IAudioClock2(IAudioClock2 *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioClock2_iface); -} - -static inline ACImpl *impl_from_IAudioStreamVolume(IAudioStreamVolume *iface) -{ - return CONTAINING_RECORD(iface, ACImpl, IAudioStreamVolume_iface); -} - -/* Following pulseaudio design here, mainloop has the lock taken whenever - * it is handling something for pulse, and the lock is required whenever - * doing any pa_* call that can affect the state in any way - * - * pa_cond_wait is used when waiting on results, because the mainloop needs - * the same lock taken to affect the state - * - * This is basically the same as the pa_threaded_mainloop implementation, - * but that cannot be used because it uses pthread_create directly - * - * pa_threaded_mainloop_(un)lock -> pthread_mutex_(un)lock - * pa_threaded_mainloop_signal -> pthread_cond_broadcast - * pa_threaded_mainloop_wait -> pthread_cond_wait - */ - -static int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { - int r; - pthread_mutex_unlock(&pulse_lock); - r = poll(ufds, nfds, timeout); - pthread_mutex_lock(&pulse_lock); - return r; -} - -static DWORD CALLBACK pulse_mainloop_thread(void *tmp) { - int ret; - pulse_ml = pa_mainloop_new(); - pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL); - pthread_mutex_lock(&pulse_lock); - pthread_cond_broadcast(&pulse_cond); - pa_mainloop_run(pulse_ml, &ret); - pthread_mutex_unlock(&pulse_lock); - pa_mainloop_free(pulse_ml); - return ret; -} - -static void pulse_contextcallback(pa_context *c, void *userdata) -{ - switch (pa_context_get_state(c)) { - default: - FIXME("Unhandled state: %i\n", pa_context_get_state(c)); - return; - - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_UNCONNECTED: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - case PA_CONTEXT_TERMINATED: - TRACE("State change to %i\n", pa_context_get_state(c)); - return; - - case PA_CONTEXT_READY: - TRACE("Ready\n"); - break; - - case PA_CONTEXT_FAILED: - WARN("Context failed: %s\n", pa_strerror(pa_context_errno(c))); - break; - } - pthread_cond_broadcast(&pulse_cond); -} - -static void pulse_stream_state(pa_stream *s, void *user) -{ - pa_stream_state_t state = pa_stream_get_state(s); - TRACE("Stream state changed to %i\n", state); - pthread_cond_broadcast(&pulse_cond); -} - -static const enum pa_channel_position pulse_pos_from_wfx[] = { - PA_CHANNEL_POSITION_FRONT_LEFT, - PA_CHANNEL_POSITION_FRONT_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER, - PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_REAR_LEFT, - PA_CHANNEL_POSITION_REAR_RIGHT, - PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, - PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, - PA_CHANNEL_POSITION_REAR_CENTER, - PA_CHANNEL_POSITION_SIDE_LEFT, - PA_CHANNEL_POSITION_SIDE_RIGHT, - PA_CHANNEL_POSITION_TOP_CENTER, - PA_CHANNEL_POSITION_TOP_FRONT_LEFT, - PA_CHANNEL_POSITION_TOP_FRONT_CENTER, - PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, - PA_CHANNEL_POSITION_TOP_REAR_LEFT, - PA_CHANNEL_POSITION_TOP_REAR_CENTER, - PA_CHANNEL_POSITION_TOP_REAR_RIGHT -}; - -static DWORD pulse_channel_map_to_channel_mask(const pa_channel_map *map) -{ - int i; - DWORD mask = 0; - - for (i = 0; i < map->channels; ++i) { - switch (map->map[i]) { - default: FIXME("Unhandled channel %s\n", pa_channel_position_to_string(map->map[i])); break; - case PA_CHANNEL_POSITION_FRONT_LEFT: mask |= SPEAKER_FRONT_LEFT; break; - case PA_CHANNEL_POSITION_MONO: - case PA_CHANNEL_POSITION_FRONT_CENTER: mask |= SPEAKER_FRONT_CENTER; break; - case PA_CHANNEL_POSITION_FRONT_RIGHT: mask |= SPEAKER_FRONT_RIGHT; break; - case PA_CHANNEL_POSITION_REAR_LEFT: mask |= SPEAKER_BACK_LEFT; break; - case PA_CHANNEL_POSITION_REAR_CENTER: mask |= SPEAKER_BACK_CENTER; break; - case PA_CHANNEL_POSITION_REAR_RIGHT: mask |= SPEAKER_BACK_RIGHT; break; - case PA_CHANNEL_POSITION_LFE: mask |= SPEAKER_LOW_FREQUENCY; break; - case PA_CHANNEL_POSITION_SIDE_LEFT: mask |= SPEAKER_SIDE_LEFT; break; - case PA_CHANNEL_POSITION_SIDE_RIGHT: mask |= SPEAKER_SIDE_RIGHT; break; - case PA_CHANNEL_POSITION_TOP_CENTER: mask |= SPEAKER_TOP_CENTER; break; - case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: mask |= SPEAKER_TOP_FRONT_LEFT; break; - case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: mask |= SPEAKER_TOP_FRONT_CENTER; break; - case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: mask |= SPEAKER_TOP_FRONT_RIGHT; break; - case PA_CHANNEL_POSITION_TOP_REAR_LEFT: mask |= SPEAKER_TOP_BACK_LEFT; break; - case PA_CHANNEL_POSITION_TOP_REAR_CENTER: mask |= SPEAKER_TOP_BACK_CENTER; break; - case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: mask |= SPEAKER_TOP_BACK_RIGHT; break; - case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: mask |= SPEAKER_FRONT_LEFT_OF_CENTER; break; - case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: mask |= SPEAKER_FRONT_RIGHT_OF_CENTER; break; - } - } - - return mask; -} - -/* For most hardware on Windows, users must choose a configuration with an even - * number of channels (stereo, quad, 5.1, 7.1). Users can then disable - * channels, but those channels are still reported to applications from - * GetMixFormat! Some applications behave badly if given an odd number of - * channels (e.g. 2.1). Here, we find the nearest configuration that Windows - * would report for a given channel layout. */ -static void convert_channel_map(const pa_channel_map *pa_map, WAVEFORMATEXTENSIBLE *fmt) -{ - DWORD pa_mask = pulse_channel_map_to_channel_mask(pa_map); - - TRACE("got mask for PA: 0x%x\n", pa_mask); - - if (pa_map->channels == 1) - { - fmt->Format.nChannels = 1; - fmt->dwChannelMask = pa_mask; - return; - } - - /* compare against known configurations and find smallest configuration - * which is a superset of the given speakers */ - - if (pa_map->channels <= 2 && - (pa_mask & ~KSAUDIO_SPEAKER_STEREO) == 0) - { - fmt->Format.nChannels = 2; - fmt->dwChannelMask = KSAUDIO_SPEAKER_STEREO; - return; - } - - if (pa_map->channels <= 4 && - (pa_mask & ~KSAUDIO_SPEAKER_QUAD) == 0) - { - fmt->Format.nChannels = 4; - fmt->dwChannelMask = KSAUDIO_SPEAKER_QUAD; - return; - } - - if (pa_map->channels <= 4 && - (pa_mask & ~KSAUDIO_SPEAKER_SURROUND) == 0) - { - fmt->Format.nChannels = 4; - fmt->dwChannelMask = KSAUDIO_SPEAKER_SURROUND; - return; - } - - if (pa_map->channels <= 6 && - (pa_mask & ~KSAUDIO_SPEAKER_5POINT1) == 0) - { - fmt->Format.nChannels = 6; - fmt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1; - return; - } - - if (pa_map->channels <= 6 && - (pa_mask & ~KSAUDIO_SPEAKER_5POINT1_SURROUND) == 0) - { - fmt->Format.nChannels = 6; - fmt->dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND; - return; - } - - if (pa_map->channels <= 8 && - (pa_mask & ~KSAUDIO_SPEAKER_7POINT1) == 0) - { - fmt->Format.nChannels = 8; - fmt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1; - return; - } - - if (pa_map->channels <= 8 && - (pa_mask & ~KSAUDIO_SPEAKER_7POINT1_SURROUND) == 0) - { - fmt->Format.nChannels = 8; - fmt->dwChannelMask = KSAUDIO_SPEAKER_7POINT1_SURROUND; - return; - } - - /* oddball format, report truthfully */ - fmt->Format.nChannels = pa_map->channels; - fmt->dwChannelMask = pa_mask; -} - -static void pulse_probe_settings(int render, WAVEFORMATEXTENSIBLE *fmt) { - WAVEFORMATEX *wfx = &fmt->Format; - pa_stream *stream; - pa_channel_map map; - pa_sample_spec ss; - pa_buffer_attr attr; - int ret; - unsigned int length = 0; - - pa_channel_map_init_auto(&map, 2, PA_CHANNEL_MAP_ALSA); - ss.rate = 48000; - ss.format = PA_SAMPLE_FLOAT32LE; - ss.channels = map.channels; - - attr.maxlength = -1; - attr.tlength = -1; - attr.minreq = attr.fragsize = pa_frame_size(&ss); - attr.prebuf = 0; - - stream = pa_stream_new(pulse_ctx, "format test stream", &ss, &map); - if (stream) - pa_stream_set_state_callback(stream, pulse_stream_state, NULL); - if (!stream) - ret = -1; - else if (render) - ret = pa_stream_connect_playback(stream, NULL, &attr, - PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS, NULL, NULL); - else - ret = pa_stream_connect_record(stream, NULL, &attr, PA_STREAM_START_CORKED|PA_STREAM_FIX_RATE|PA_STREAM_FIX_CHANNELS|PA_STREAM_EARLY_REQUESTS); - if (ret >= 0) { - while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 && - pa_stream_get_state(stream) == PA_STREAM_CREATING) - {} - if (pa_stream_get_state(stream) == PA_STREAM_READY) { - ss = *pa_stream_get_sample_spec(stream); - map = *pa_stream_get_channel_map(stream); - if (render) - length = pa_stream_get_buffer_attr(stream)->minreq; - else - length = pa_stream_get_buffer_attr(stream)->fragsize; - pa_stream_disconnect(stream); - while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 && - pa_stream_get_state(stream) == PA_STREAM_READY) - {} - } - } - - if (stream) - pa_stream_unref(stream); - - if (length) - pulse_def_period[!render] = pulse_min_period[!render] = pa_bytes_to_usec(10 * length, &ss); - - const char* penv = getenv("STAGING_AUDIO_PERIOD"); - if (penv) { - int val = atoi(penv); - pulse_def_period[!render] = pulse_min_period[!render] = val; - printf("Staging audio period set to %d.\n", val); - } - - wfx->wFormatTag = WAVE_FORMAT_EXTENSIBLE; - wfx->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - - convert_channel_map(&map, fmt); - - wfx->wBitsPerSample = 8 * pa_sample_size_of_format(ss.format); - wfx->nSamplesPerSec = ss.rate; - wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8; - wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign; - if (ss.format != PA_SAMPLE_S24_32LE) - fmt->Samples.wValidBitsPerSample = wfx->wBitsPerSample; - else - fmt->Samples.wValidBitsPerSample = 24; - if (ss.format == PA_SAMPLE_FLOAT32LE) - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; - else - fmt->SubFormat = KSDATAFORMAT_SUBTYPE_PCM; -} - -static HRESULT pulse_connect(void) -{ - int len; - WCHAR path[MAX_PATH], *name; - char *str; - - if (!pulse_thread) - { - if (!(pulse_thread = CreateThread(NULL, 0, pulse_mainloop_thread, NULL, 0, NULL))) - { - ERR("Failed to create mainloop thread.\n"); - return E_FAIL; - } - SetThreadPriority(pulse_thread, THREAD_PRIORITY_TIME_CRITICAL); - pthread_cond_wait(&pulse_cond, &pulse_lock); - } - - if (pulse_ctx && PA_CONTEXT_IS_GOOD(pa_context_get_state(pulse_ctx))) - return S_OK; - if (pulse_ctx) - pa_context_unref(pulse_ctx); - - GetModuleFileNameW(NULL, path, ARRAY_SIZE(path)); - name = strrchrW(path, '\\'); - if (!name) - name = path; - else - name++; - len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL); - str = pa_xmalloc(len); - WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL); - TRACE("Name: %s\n", str); - pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str); - pa_xfree(str); - if (!pulse_ctx) { - ERR("Failed to create context\n"); - return E_FAIL; - } - - pa_context_set_state_callback(pulse_ctx, pulse_contextcallback, NULL); - - TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx), PA_API_VERSION); - if (pa_context_connect(pulse_ctx, NULL, 0, NULL) < 0) - goto fail; - - /* Wait for connection */ - while (pthread_cond_wait(&pulse_cond, &pulse_lock)) { - pa_context_state_t state = pa_context_get_state(pulse_ctx); - - if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) - goto fail; - - if (state == PA_CONTEXT_READY) - break; - } - - TRACE("Connected to server %s with protocol version: %i.\n", - pa_context_get_server(pulse_ctx), - pa_context_get_server_protocol_version(pulse_ctx)); - return S_OK; - -fail: - pa_context_unref(pulse_ctx); - pulse_ctx = NULL; - return E_FAIL; -} - -/* For default PulseAudio render device, OR together all of the - * PKEY_AudioEndpoint_PhysicalSpeakers values of the sinks. */ -static void pulse_phys_speakers_cb(pa_context *c, const pa_sink_info *i, int eol, void *userdata) -{ - if (i) - g_phys_speakers_mask |= pulse_channel_map_to_channel_mask(&i->channel_map); -} - -/* some poorly-behaved applications call audio functions during DllMain, so we - * have to do as much as possible without creating a new thread. this function - * sets up a synchronous connection to verify the server is running and query - * static data. */ -static HRESULT pulse_test_connect(void) -{ - int len, ret; - WCHAR path[MAX_PATH], *name; - char *str; - pa_operation *o; - - pulse_ml = pa_mainloop_new(); - - pa_mainloop_set_poll_func(pulse_ml, pulse_poll_func, NULL); - - GetModuleFileNameW(NULL, path, ARRAY_SIZE(path)); - name = strrchrW(path, '\\'); - if (!name) - name = path; - else - name++; - len = WideCharToMultiByte(CP_UNIXCP, 0, name, -1, NULL, 0, NULL, NULL); - str = pa_xmalloc(len); - WideCharToMultiByte(CP_UNIXCP, 0, name, -1, str, len, NULL, NULL); - TRACE("Name: %s\n", str); - pulse_ctx = pa_context_new(pa_mainloop_get_api(pulse_ml), str); - pa_xfree(str); - if (!pulse_ctx) { - ERR("Failed to create context\n"); - pa_mainloop_free(pulse_ml); - pulse_ml = NULL; - return E_FAIL; - } - - pa_context_set_state_callback(pulse_ctx, pulse_contextcallback, NULL); - - TRACE("libpulse protocol version: %u. API Version %u\n", pa_context_get_protocol_version(pulse_ctx), PA_API_VERSION); - if (pa_context_connect(pulse_ctx, NULL, 0, NULL) < 0) - goto fail; - - /* Wait for connection */ - while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0) { - pa_context_state_t state = pa_context_get_state(pulse_ctx); - - if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) - goto fail; - - if (state == PA_CONTEXT_READY) - break; - } - - if (pa_context_get_state(pulse_ctx) != PA_CONTEXT_READY) - goto fail; - - TRACE("Test-connected to server %s with protocol version: %i.\n", - pa_context_get_server(pulse_ctx), - pa_context_get_server_protocol_version(pulse_ctx)); - - pulse_probe_settings(1, &pulse_fmt[0]); - pulse_probe_settings(0, &pulse_fmt[1]); - - g_phys_speakers_mask = 0; - o = pa_context_get_sink_info_list(pulse_ctx, &pulse_phys_speakers_cb, NULL); - if (o) { - while (pa_mainloop_iterate(pulse_ml, 1, &ret) >= 0 && - pa_operation_get_state(o) == PA_OPERATION_RUNNING) - {} - pa_operation_unref(o); - } - - pa_context_unref(pulse_ctx); - pulse_ctx = NULL; - pa_mainloop_free(pulse_ml); - pulse_ml = NULL; - - return S_OK; - -fail: - pa_context_unref(pulse_ctx); - pulse_ctx = NULL; - pa_mainloop_free(pulse_ml); - pulse_ml = NULL; - - return E_FAIL; -} - -static HRESULT pulse_stream_valid(ACImpl *This) { - if (!This->stream) - return AUDCLNT_E_NOT_INITIALIZED; - if (pa_stream_get_state(This->stream) != PA_STREAM_READY) - return AUDCLNT_E_DEVICE_INVALIDATED; - return S_OK; -} - -static void silence_buffer(pa_sample_format_t format, BYTE *buffer, UINT32 bytes) -{ - memset(buffer, format == PA_SAMPLE_U8 ? 0x80 : 0, bytes); -} - -static void pulse_free_noop(void *buf) -{ -} - -enum write_buffer_flags -{ - WINEPULSE_WRITE_NOFREE = 0x01, - WINEPULSE_WRITE_SILENT = 0x02 -}; - -static int write_buffer(const ACImpl *This, BYTE *buffer, UINT32 bytes, - enum write_buffer_flags flags) -{ - float vol[PA_CHANNELS_MAX]; - BOOL adjust = FALSE; - UINT32 i, channels; - BYTE *end; - - if (!bytes) return 0; - if (This->session->mute || (flags & WINEPULSE_WRITE_SILENT)) - { - silence_buffer(This->ss.format, buffer, bytes); - goto write; - } - - /* Adjust the buffer based on the volume for each channel */ - channels = This->ss.channels; - for (i = 0; i < channels; i++) - { - vol[i] = This->vol[i] * This->session->master_vol * This->session->channel_vols[i]; - adjust |= vol[i] != 1.0f; - } - if (!adjust) goto write; - - end = buffer + bytes; - switch (This->ss.format) - { -#ifndef WORDS_BIGENDIAN -#define PROCESS_BUFFER(type) do \ -{ \ - type *p = (type*)buffer; \ - do \ - { \ - for (i = 0; i < channels; i++) \ - p[i] = p[i] * vol[i]; \ - p += i; \ - } while ((BYTE*)p != end); \ -} while (0) - case PA_SAMPLE_S16LE: - PROCESS_BUFFER(INT16); - break; - case PA_SAMPLE_S32LE: - PROCESS_BUFFER(INT32); - break; - case PA_SAMPLE_FLOAT32LE: - PROCESS_BUFFER(float); - break; -#undef PROCESS_BUFFER - case PA_SAMPLE_S24_32LE: - { - UINT32 *p = (UINT32*)buffer; - do - { - for (i = 0; i < channels; i++) - { - p[i] = (INT32)((INT32)(p[i] << 8) * vol[i]); - p[i] >>= 8; - } - p += i; - } while ((BYTE*)p != end); - break; - } - case PA_SAMPLE_S24LE: - { - /* do it 12 bytes at a time until it is no longer possible */ - UINT32 *q = (UINT32*)buffer; - BYTE *p; - - i = 0; - while (end - (BYTE*)q >= 12) - { - UINT32 v[4], k; - v[0] = q[0] << 8; - v[1] = q[1] << 16 | (q[0] >> 16 & ~0xff); - v[2] = q[2] << 24 | (q[1] >> 8 & ~0xff); - v[3] = q[2] & ~0xff; - for (k = 0; k < 4; k++) - { - v[k] = (INT32)((INT32)v[k] * vol[i]); - if (++i == channels) i = 0; - } - *q++ = v[0] >> 8 | (v[1] & ~0xff) << 16; - *q++ = v[1] >> 16 | (v[2] & ~0xff) << 8; - *q++ = v[2] >> 24 | (v[3] & ~0xff); - } - p = (BYTE*)q; - while (p != end) - { - UINT32 v = (INT32)((INT32)(p[0] << 8 | p[1] << 16 | p[2] << 24) * vol[i]); - *p++ = v >> 8 & 0xff; - *p++ = v >> 16 & 0xff; - *p++ = v >> 24; - if (++i == channels) i = 0; - } - break; - } -#endif - case PA_SAMPLE_U8: - { - UINT8 *p = (UINT8*)buffer; - do - { - for (i = 0; i < channels; i++) - p[i] = (int)((p[i] - 128) * vol[i]) + 128; - p += i; - } while ((BYTE*)p != end); - break; - } - case PA_SAMPLE_ALAW: - { - UINT8 *p = (UINT8*)buffer; - do - { - for (i = 0; i < channels; i++) - p[i] = mult_alaw_sample(p[i], vol[i]); - p += i; - } while ((BYTE*)p != end); - break; - } - case PA_SAMPLE_ULAW: - { - UINT8 *p = (UINT8*)buffer; - do - { - for (i = 0; i < channels; i++) - p[i] = mult_ulaw_sample(p[i], vol[i]); - p += i; - } while ((BYTE*)p != end); - break; - } - default: - TRACE("Unhandled format %i, not adjusting volume.\n", This->ss.format); - break; - } - -write: - return pa_stream_write(This->stream, buffer, bytes, - (flags & WINEPULSE_WRITE_NOFREE) ? pulse_free_noop : NULL, - 0, PA_SEEK_RELATIVE); -} - -static void dump_attr(const pa_buffer_attr *attr) { - TRACE("maxlength: %u\n", attr->maxlength); - TRACE("minreq: %u\n", attr->minreq); - TRACE("fragsize: %u\n", attr->fragsize); - TRACE("tlength: %u\n", attr->tlength); - TRACE("prebuf: %u\n", attr->prebuf); -} - -static void pulse_op_cb(pa_stream *s, int success, void *user) { - TRACE("Success: %i\n", success); - *(int*)user = success; - pthread_cond_broadcast(&pulse_cond); -} - -static void pulse_attr_update(pa_stream *s, void *user) { - const pa_buffer_attr *attr = pa_stream_get_buffer_attr(s); - TRACE("New attributes or device moved:\n"); - dump_attr(attr); -} - -/* Here's the buffer setup: - * - * vvvvvvvv sent to HW already - * vvvvvvvv in Pulse buffer but rewindable - * [dddddddddddddddd] Pulse buffer - * [dddddddddddddddd--------] mmdevapi buffer - * ^^^^^^^^^^^^^^^^ pad - * ^ lcl_offs_bytes - * ^^^^^^^^^ held_bytes - * ^ wri_offs_bytes - * - * GetCurrentPadding is pad - * - * During pulse_wr_callback, we decrement pad, fill Pulse buffer, and move - * lcl_offs forward - * - * During Stop, we flush the Pulse buffer - */ -static void pulse_wr_callback(pa_stream *s, size_t bytes, void *userdata) -{ - ACImpl *This = userdata; - UINT32 oldpad = This->pad; - - if(This->local_buffer){ - UINT32 to_write; - BYTE *buf = This->local_buffer + This->lcl_offs_bytes; - - if(This->pad > bytes){ - This->clock_written += bytes; - This->pad -= bytes; - }else{ - This->clock_written += This->pad; - This->pad = 0; - } - - bytes = min(bytes, This->held_bytes); - - if(This->lcl_offs_bytes + bytes > This->bufsize_bytes){ - to_write = This->bufsize_bytes - This->lcl_offs_bytes; - TRACE("writing small chunk of %u bytes\n", to_write); - write_buffer(This, buf, to_write, 0); - This->held_bytes -= to_write; - to_write = bytes - to_write; - This->lcl_offs_bytes = 0; - buf = This->local_buffer; - }else - to_write = bytes; - - TRACE("writing main chunk of %u bytes\n", to_write); - write_buffer(This, buf, to_write, 0); - This->lcl_offs_bytes += to_write; - This->lcl_offs_bytes %= This->bufsize_bytes; - This->held_bytes -= to_write; - }else{ - if (bytes < This->bufsize_bytes) - This->pad = This->bufsize_bytes - bytes; - else - This->pad = 0; - - if (oldpad == This->pad) - return; - - assert(oldpad > This->pad); - - This->clock_written += oldpad - This->pad; - TRACE("New pad: %zu (-%zu)\n", This->pad / pa_frame_size(&This->ss), (oldpad - This->pad) / pa_frame_size(&This->ss)); - } - - if (This->event) - SetEvent(This->event); -} - -static void pulse_underflow_callback(pa_stream *s, void *userdata) -{ - WARN("Underflow\n"); -} - -/* Latency is periodically updated even when nothing is played, - * because of PA_STREAM_AUTO_TIMING_UPDATE so use it as timer - * - * Perfect for passing all tests :) - */ -static void pulse_latency_callback(pa_stream *s, void *userdata) -{ - ACImpl *This = userdata; - if (!This->pad && This->event) - SetEvent(This->event); -} - -static void pulse_started_callback(pa_stream *s, void *userdata) -{ - TRACE("(Re)started playing\n"); -} - -static void pulse_rd_loop(ACImpl *This, size_t bytes) -{ - while (bytes >= This->capture_period) { - ACPacket *p, *next; - LARGE_INTEGER stamp, freq; - BYTE *dst, *src; - size_t src_len, copy, rem = This->capture_period; - if (!(p = (ACPacket*)list_head(&This->packet_free_head))) { - p = (ACPacket*)list_head(&This->packet_filled_head); - if (!p->discont) { - next = (ACPacket*)p->entry.next; - next->discont = 1; - } else - p = (ACPacket*)list_tail(&This->packet_filled_head); - assert(This->pad == This->bufsize_bytes); - } else { - assert(This->pad < This->bufsize_bytes); - This->pad += This->capture_period; - assert(This->pad <= This->bufsize_bytes); - } - QueryPerformanceCounter(&stamp); - QueryPerformanceFrequency(&freq); - p->qpcpos = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart; - p->discont = 0; - list_remove(&p->entry); - list_add_tail(&This->packet_filled_head, &p->entry); - - dst = p->data; - while (rem) { - if (This->peek_len) { - copy = min(rem, This->peek_len - This->peek_ofs); - - memcpy(dst, This->peek_buffer + This->peek_ofs, copy); - - rem -= copy; - dst += copy; - This->peek_ofs += copy; - if(This->peek_len == This->peek_ofs) - This->peek_len = 0; - } else { - pa_stream_peek(This->stream, (const void**)&src, &src_len); - - copy = min(rem, src_len); - - memcpy(dst, src, rem); - - dst += copy; - rem -= copy; - - if (copy < src_len) { - if (src_len > This->peek_buffer_len) { - HeapFree(GetProcessHeap(), 0, This->peek_buffer); - This->peek_buffer = HeapAlloc(GetProcessHeap(), 0, src_len); - This->peek_buffer_len = src_len; - } - - memcpy(This->peek_buffer, src + copy, src_len - copy); - This->peek_len = src_len - copy; - This->peek_ofs = 0; - } - - pa_stream_drop(This->stream); - } - } - - bytes -= This->capture_period; - } -} - -static void pulse_rd_drop(ACImpl *This, size_t bytes) -{ - while (bytes >= This->capture_period) { - size_t src_len, copy, rem = This->capture_period; - while (rem) { - const void *src; - pa_stream_peek(This->stream, &src, &src_len); - assert(src_len); - assert(This->peek_ofs < src_len); - src_len -= This->peek_ofs; - assert(src_len <= bytes); - - copy = rem; - if (copy > src_len) - copy = src_len; - - src_len -= copy; - rem -= copy; - - if (!src_len) { - This->peek_ofs = 0; - pa_stream_drop(This->stream); - } else - This->peek_ofs += copy; - bytes -= copy; - } - } -} - -static void pulse_rd_callback(pa_stream *s, size_t bytes, void *userdata) -{ - ACImpl *This = userdata; - - TRACE("Readable total: %zu, fragsize: %u\n", bytes, pa_stream_get_buffer_attr(s)->fragsize); - assert(bytes >= This->peek_ofs); - bytes -= This->peek_ofs; - if (bytes < This->capture_period) - return; - - if (This->started) - pulse_rd_loop(This, bytes); - else - pulse_rd_drop(This, bytes); - - if (This->event) - SetEvent(This->event); -} - -static HRESULT pulse_stream_connect(ACImpl *This, UINT32 period_bytes) { - int ret; - char buffer[64]; - static LONG number; - pa_buffer_attr attr; - if (This->stream) { - pa_stream_disconnect(This->stream); - while (pa_stream_get_state(This->stream) == PA_STREAM_READY) - pthread_cond_wait(&pulse_cond, &pulse_lock); - pa_stream_unref(This->stream); - } - ret = InterlockedIncrement(&number); - sprintf(buffer, "audio stream #%i", ret); - This->stream = pa_stream_new(pulse_ctx, buffer, &This->ss, &This->map); - - if (!This->stream) { - WARN("pa_stream_new returned error %i\n", pa_context_errno(pulse_ctx)); - return AUDCLNT_E_ENDPOINT_CREATE_FAILED; - } - - pa_stream_set_state_callback(This->stream, pulse_stream_state, This); - pa_stream_set_buffer_attr_callback(This->stream, pulse_attr_update, This); - pa_stream_set_moved_callback(This->stream, pulse_attr_update, This); - - /* PulseAudio will fill in correct values */ - attr.minreq = attr.fragsize = period_bytes; - attr.maxlength = attr.tlength = This->bufsize_bytes; - attr.prebuf = pa_frame_size(&This->ss); - dump_attr(&attr); - if (This->dataflow == eRender) - ret = pa_stream_connect_playback(This->stream, NULL, &attr, - PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS, NULL, NULL); - else - ret = pa_stream_connect_record(This->stream, NULL, &attr, - PA_STREAM_START_CORKED|PA_STREAM_START_UNMUTED|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_EARLY_REQUESTS); - if (ret < 0) { - WARN("Returns %i\n", ret); - return AUDCLNT_E_ENDPOINT_CREATE_FAILED; - } - while (pa_stream_get_state(This->stream) == PA_STREAM_CREATING) - pthread_cond_wait(&pulse_cond, &pulse_lock); - if (pa_stream_get_state(This->stream) != PA_STREAM_READY) - return AUDCLNT_E_ENDPOINT_CREATE_FAILED; - - if (This->dataflow == eRender) { - pa_stream_set_write_callback(This->stream, pulse_wr_callback, This); - pa_stream_set_underflow_callback(This->stream, pulse_underflow_callback, This); - pa_stream_set_started_callback(This->stream, pulse_started_callback, This); - } else - pa_stream_set_read_callback(This->stream, pulse_rd_callback, This); - return S_OK; -} - -HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, const WCHAR ***ids, GUID **keys, - UINT *num, UINT *def_index) -{ - WCHAR *id; - - TRACE("%d %p %p %p\n", flow, ids, num, def_index); - - *num = 1; - *def_index = 0; - - *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(**ids)); - *keys = NULL; - if (!*ids) - return E_OUTOFMEMORY; - - (*ids)[0] = id = HeapAlloc(GetProcessHeap(), 0, sizeof(defaultW)); - *keys = HeapAlloc(GetProcessHeap(), 0, sizeof(**keys)); - if (!*keys || !id) { - HeapFree(GetProcessHeap(), 0, id); - HeapFree(GetProcessHeap(), 0, *keys); - HeapFree(GetProcessHeap(), 0, *ids); - *ids = NULL; - *keys = NULL; - return E_OUTOFMEMORY; - } - memcpy(id, defaultW, sizeof(defaultW)); - - if (flow == eRender) - (*keys)[0] = pulse_render_guid; - else - (*keys)[0] = pulse_capture_guid; - - return S_OK; -} - -int WINAPI AUDDRV_GetPriority(void) -{ - HRESULT hr; - pthread_mutex_lock(&pulse_lock); - hr = pulse_test_connect(); - pthread_mutex_unlock(&pulse_lock); - return SUCCEEDED(hr) ? Priority_Preferred : Priority_Unavailable; -} - -HRESULT WINAPI AUDDRV_GetAudioEndpoint(GUID *guid, IMMDevice *dev, IAudioClient **out) -{ - ACImpl *This; - int i; - EDataFlow dataflow; - HRESULT hr; - - TRACE("%s %p %p\n", debugstr_guid(guid), dev, out); - if (IsEqualGUID(guid, &pulse_render_guid)) - dataflow = eRender; - else if (IsEqualGUID(guid, &pulse_capture_guid)) - dataflow = eCapture; - else - return E_UNEXPECTED; - - *out = NULL; - - This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); - if (!This) - return E_OUTOFMEMORY; - - This->IAudioClient_iface.lpVtbl = &AudioClient_Vtbl; - This->IAudioRenderClient_iface.lpVtbl = &AudioRenderClient_Vtbl; - This->IAudioCaptureClient_iface.lpVtbl = &AudioCaptureClient_Vtbl; - This->IAudioClock_iface.lpVtbl = &AudioClock_Vtbl; - This->IAudioClock2_iface.lpVtbl = &AudioClock2_Vtbl; - This->IAudioStreamVolume_iface.lpVtbl = &AudioStreamVolume_Vtbl; - This->dataflow = dataflow; - This->parent = dev; - for (i = 0; i < PA_CHANNELS_MAX; ++i) - This->vol[i] = 1.f; - - hr = CoCreateFreeThreadedMarshaler((IUnknown*)&This->IAudioClient_iface, &This->marshal); - if (hr) { - HeapFree(GetProcessHeap(), 0, This); - return hr; - } - IMMDevice_AddRef(This->parent); - - *out = &This->IAudioClient_iface; - IAudioClient_AddRef(&This->IAudioClient_iface); - - return S_OK; -} - -static HRESULT WINAPI AudioClient_QueryInterface(IAudioClient *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClient(iface); - - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - - *ppv = NULL; - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClient)) - *ppv = iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - if (IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->marshal, riid, ppv); - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClient_AddRef(IAudioClient *iface) -{ - ACImpl *This = impl_from_IAudioClient(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %u\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioClient_Release(IAudioClient *iface) -{ - ACImpl *This = impl_from_IAudioClient(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %u\n", This, ref); - if (!ref) { - if (This->stream) { - pthread_mutex_lock(&pulse_lock); - if (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream))) { - pa_stream_disconnect(This->stream); - while (PA_STREAM_IS_GOOD(pa_stream_get_state(This->stream))) - pthread_cond_wait(&pulse_cond, &pulse_lock); - } - pa_stream_unref(This->stream); - This->stream = NULL; - list_remove(&This->entry); - pthread_mutex_unlock(&pulse_lock); - } - IUnknown_Release(This->marshal); - IMMDevice_Release(This->parent); - HeapFree(GetProcessHeap(), 0, This->tmp_buffer); - HeapFree(GetProcessHeap(), 0, This->peek_buffer); - HeapFree(GetProcessHeap(), 0, This->local_buffer); - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static void dump_fmt(const WAVEFORMATEX *fmt) -{ - TRACE("wFormatTag: 0x%x (", fmt->wFormatTag); - switch(fmt->wFormatTag) { - case WAVE_FORMAT_PCM: - TRACE("WAVE_FORMAT_PCM"); - break; - case WAVE_FORMAT_IEEE_FLOAT: - TRACE("WAVE_FORMAT_IEEE_FLOAT"); - break; - case WAVE_FORMAT_EXTENSIBLE: - TRACE("WAVE_FORMAT_EXTENSIBLE"); - break; - default: - TRACE("Unknown"); - break; - } - TRACE(")\n"); - - TRACE("nChannels: %u\n", fmt->nChannels); - TRACE("nSamplesPerSec: %u\n", fmt->nSamplesPerSec); - TRACE("nAvgBytesPerSec: %u\n", fmt->nAvgBytesPerSec); - TRACE("nBlockAlign: %u\n", fmt->nBlockAlign); - TRACE("wBitsPerSample: %u\n", fmt->wBitsPerSample); - TRACE("cbSize: %u\n", fmt->cbSize); - - if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { - WAVEFORMATEXTENSIBLE *fmtex = (void*)fmt; - TRACE("dwChannelMask: %08x\n", fmtex->dwChannelMask); - TRACE("Samples: %04x\n", fmtex->Samples.wReserved); - TRACE("SubFormat: %s\n", wine_dbgstr_guid(&fmtex->SubFormat)); - } -} - -static WAVEFORMATEX *clone_format(const WAVEFORMATEX *fmt) -{ - WAVEFORMATEX *ret; - size_t size; - - if (fmt->wFormatTag == WAVE_FORMAT_EXTENSIBLE) - size = sizeof(WAVEFORMATEXTENSIBLE); - else - size = sizeof(WAVEFORMATEX); - - ret = CoTaskMemAlloc(size); - if (!ret) - return NULL; - - memcpy(ret, fmt, size); - - ret->cbSize = size - sizeof(WAVEFORMATEX); - - return ret; -} - -static DWORD get_channel_mask(unsigned int channels) -{ - switch(channels) { - case 0: - return 0; - case 1: - return KSAUDIO_SPEAKER_MONO; - case 2: - return KSAUDIO_SPEAKER_STEREO; - case 3: - return KSAUDIO_SPEAKER_STEREO | SPEAKER_LOW_FREQUENCY; - case 4: - return KSAUDIO_SPEAKER_QUAD; /* not _SURROUND */ - case 5: - return KSAUDIO_SPEAKER_QUAD | SPEAKER_LOW_FREQUENCY; - case 6: - return KSAUDIO_SPEAKER_5POINT1; /* not 5POINT1_SURROUND */ - case 7: - return KSAUDIO_SPEAKER_5POINT1 | SPEAKER_BACK_CENTER; - case 8: - return KSAUDIO_SPEAKER_7POINT1_SURROUND; /* Vista deprecates 7POINT1 */ - } - FIXME("Unknown speaker configuration: %u\n", channels); - return 0; -} - -static void session_init_vols(AudioSession *session, UINT channels) -{ - if (session->channel_count < channels) { - UINT i; - - if (session->channel_vols) - session->channel_vols = HeapReAlloc(GetProcessHeap(), 0, - session->channel_vols, sizeof(float) * channels); - else - session->channel_vols = HeapAlloc(GetProcessHeap(), 0, - sizeof(float) * channels); - if (!session->channel_vols) - return; - - for(i = session->channel_count; i < channels; ++i) - session->channel_vols[i] = 1.f; - - session->channel_count = channels; - } -} - -static AudioSession *create_session(const GUID *guid, IMMDevice *device, - UINT num_channels) -{ - AudioSession *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(AudioSession)); - if (!ret) - return NULL; - - memcpy(&ret->guid, guid, sizeof(GUID)); - - ret->device = device; - - list_init(&ret->clients); - - list_add_head(&g_sessions, &ret->entry); - - session_init_vols(ret, num_channels); - - ret->master_vol = 1.f; - - return ret; -} - -/* if channels == 0, then this will return or create a session with - * matching dataflow and GUID. otherwise, channels must also match */ -static HRESULT get_audio_session(const GUID *sessionguid, - IMMDevice *device, UINT channels, AudioSession **out) -{ - AudioSession *session; - - if (!sessionguid || IsEqualGUID(sessionguid, &GUID_NULL)) { - *out = create_session(&GUID_NULL, device, channels); - if (!*out) - return E_OUTOFMEMORY; - - return S_OK; - } - - *out = NULL; - LIST_FOR_EACH_ENTRY(session, &g_sessions, AudioSession, entry) { - if (session->device == device && - IsEqualGUID(sessionguid, &session->guid)) { - session_init_vols(session, channels); - *out = session; - break; - } - } - - if (!*out) { - *out = create_session(sessionguid, device, channels); - if (!*out) - return E_OUTOFMEMORY; - } - - return S_OK; -} - -static HRESULT pulse_spec_from_waveformat(ACImpl *This, const WAVEFORMATEX *fmt) -{ - pa_channel_map_init(&This->map); - This->ss.rate = fmt->nSamplesPerSec; - This->ss.format = PA_SAMPLE_INVALID; - - switch(fmt->wFormatTag) { - case WAVE_FORMAT_IEEE_FLOAT: - if (!fmt->nChannels || fmt->nChannels > 2 || fmt->wBitsPerSample != 32) - break; - This->ss.format = PA_SAMPLE_FLOAT32LE; - pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA); - break; - case WAVE_FORMAT_PCM: - if (!fmt->nChannels || fmt->nChannels > 2) - break; - if (fmt->wBitsPerSample == 8) - This->ss.format = PA_SAMPLE_U8; - else if (fmt->wBitsPerSample == 16) - This->ss.format = PA_SAMPLE_S16LE; - else - return AUDCLNT_E_UNSUPPORTED_FORMAT; - pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA); - break; - case WAVE_FORMAT_EXTENSIBLE: { - WAVEFORMATEXTENSIBLE *wfe = (WAVEFORMATEXTENSIBLE*)fmt; - DWORD mask = wfe->dwChannelMask; - DWORD i = 0, j; - if (fmt->cbSize != (sizeof(*wfe) - sizeof(*fmt)) && fmt->cbSize != sizeof(*wfe)) - break; - if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) && - (!wfe->Samples.wValidBitsPerSample || wfe->Samples.wValidBitsPerSample == 32) && - fmt->wBitsPerSample == 32) - This->ss.format = PA_SAMPLE_FLOAT32LE; - else if (IsEqualGUID(&wfe->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) { - DWORD valid = wfe->Samples.wValidBitsPerSample; - if (!valid) - valid = fmt->wBitsPerSample; - if (!valid || valid > fmt->wBitsPerSample) - break; - switch (fmt->wBitsPerSample) { - case 8: - if (valid == 8) - This->ss.format = PA_SAMPLE_U8; - break; - case 16: - if (valid == 16) - This->ss.format = PA_SAMPLE_S16LE; - break; - case 24: - if (valid == 24) - This->ss.format = PA_SAMPLE_S24LE; - break; - case 32: - if (valid == 24) - This->ss.format = PA_SAMPLE_S24_32LE; - else if (valid == 32) - This->ss.format = PA_SAMPLE_S32LE; - break; - default: - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - } - This->map.channels = fmt->nChannels; - if (!mask || (mask & (SPEAKER_ALL|SPEAKER_RESERVED))) - mask = get_channel_mask(fmt->nChannels); - for (j = 0; j < ARRAY_SIZE(pulse_pos_from_wfx) && i < fmt->nChannels; ++j) { - if (mask & (1 << j)) - This->map.map[i++] = pulse_pos_from_wfx[j]; - } - - /* Special case for mono since pulse appears to map it differently */ - if (mask == SPEAKER_FRONT_CENTER) - This->map.map[0] = PA_CHANNEL_POSITION_MONO; - - if (i < fmt->nChannels || (mask & SPEAKER_RESERVED)) { - This->map.channels = 0; - ERR("Invalid channel mask: %i/%i and %x(%x)\n", i, fmt->nChannels, mask, wfe->dwChannelMask); - break; - } - break; - } - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - if (fmt->wBitsPerSample != 8) { - FIXME("Unsupported bpp %u for LAW\n", fmt->wBitsPerSample); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - if (fmt->nChannels != 1 && fmt->nChannels != 2) { - FIXME("Unsupported channels %u for LAW\n", fmt->nChannels); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - This->ss.format = fmt->wFormatTag == WAVE_FORMAT_MULAW ? PA_SAMPLE_ULAW : PA_SAMPLE_ALAW; - pa_channel_map_init_auto(&This->map, fmt->nChannels, PA_CHANNEL_MAP_ALSA); - break; - default: - WARN("Unhandled tag %x\n", fmt->wFormatTag); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - This->ss.channels = This->map.channels; - if (!pa_channel_map_valid(&This->map) || This->ss.format == PA_SAMPLE_INVALID) { - ERR("Invalid format! Channel spec valid: %i, format: %i\n", pa_channel_map_valid(&This->map), This->ss.format); - return AUDCLNT_E_UNSUPPORTED_FORMAT; - } - return S_OK; -} - -static HRESULT WINAPI AudioClient_Initialize(IAudioClient *iface, - AUDCLNT_SHAREMODE mode, DWORD flags, REFERENCE_TIME duration, - REFERENCE_TIME period, const WAVEFORMATEX *fmt, - const GUID *sessionguid) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr = S_OK; - UINT period_bytes; - - TRACE("(%p)->(%x, %x, %s, %s, %p, %s)\n", This, mode, flags, - wine_dbgstr_longlong(duration), wine_dbgstr_longlong(period), fmt, debugstr_guid(sessionguid)); - - if (!fmt) - return E_POINTER; - - if (mode != AUDCLNT_SHAREMODE_SHARED && mode != AUDCLNT_SHAREMODE_EXCLUSIVE) - return E_INVALIDARG; - if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE) - return AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED; - - if (flags & ~(AUDCLNT_STREAMFLAGS_CROSSPROCESS | - AUDCLNT_STREAMFLAGS_LOOPBACK | - AUDCLNT_STREAMFLAGS_EVENTCALLBACK | - AUDCLNT_STREAMFLAGS_NOPERSIST | - AUDCLNT_STREAMFLAGS_RATEADJUST | - AUDCLNT_SESSIONFLAGS_EXPIREWHENUNOWNED | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDE | - AUDCLNT_SESSIONFLAGS_DISPLAY_HIDEWHENEXPIRED | - AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY | - AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM)) { - FIXME("Unknown flags: %08x\n", flags); - return E_INVALIDARG; - } - - pthread_mutex_lock(&pulse_lock); - - hr = pulse_connect(); - if (FAILED(hr)) { - pthread_mutex_unlock(&pulse_lock); - return hr; - } - - if (This->stream) { - pthread_mutex_unlock(&pulse_lock); - return AUDCLNT_E_ALREADY_INITIALIZED; - } - - hr = pulse_spec_from_waveformat(This, fmt); - TRACE("Obtaining format returns %08x\n", hr); - dump_fmt(fmt); - - if (FAILED(hr)) - goto exit; - - if (mode == AUDCLNT_SHAREMODE_SHARED) { - REFERENCE_TIME def = pulse_def_period[This->dataflow == eCapture]; - REFERENCE_TIME min = pulse_min_period[This->dataflow == eCapture]; - - /* Switch to low latency mode if below 2 default periods, - * which is 20 ms by default, this will increase the amount - * of interrupts but allows very low latency. In dsound I - * managed to get a total latency of ~8ms, which is well below - * default - */ - if (duration < 2 * def) - period = min; - else - period = def; - if (duration < 2 * period) - duration = 2 * period; - - /* Uh oh, really low latency requested.. */ - if (duration <= 2 * period) - period /= 2; - } - - const char* denv = getenv("STAGING_AUDIO_DURATION"); - if (denv) { - int val = atoi(denv); - duration = val; - printf("Staging audio duration set to %d.\n", val); - } - - period_bytes = pa_frame_size(&This->ss) * MulDiv(period, This->ss.rate, 10000000); - - if (duration < 20000000) - This->bufsize_frames = ceil((duration / 10000000.) * fmt->nSamplesPerSec); - else - This->bufsize_frames = 2 * fmt->nSamplesPerSec; - This->bufsize_bytes = This->bufsize_frames * pa_frame_size(&This->ss); - - This->share = mode; - This->flags = flags; - hr = pulse_stream_connect(This, period_bytes); - if (SUCCEEDED(hr)) { - UINT32 unalign; - const pa_buffer_attr *attr = pa_stream_get_buffer_attr(This->stream); - This->attr = *attr; - /* Update frames according to new size */ - dump_attr(attr); - if (This->dataflow == eRender) { - if (attr->tlength < This->bufsize_bytes) { - TRACE("PulseAudio buffer too small (%u < %u), using tmp buffer\n", attr->tlength, This->bufsize_bytes); - - This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_bytes); - if(!This->local_buffer) - hr = E_OUTOFMEMORY; - } - } else { - UINT32 i, capture_packets; - - This->capture_period = period_bytes = attr->fragsize; - if ((unalign = This->bufsize_bytes % period_bytes)) - This->bufsize_bytes += period_bytes - unalign; - This->bufsize_frames = This->bufsize_bytes / pa_frame_size(&This->ss); - - capture_packets = This->bufsize_bytes / This->capture_period; - - This->local_buffer = HeapAlloc(GetProcessHeap(), 0, This->bufsize_bytes + capture_packets * sizeof(ACPacket)); - if (!This->local_buffer) - hr = E_OUTOFMEMORY; - else { - ACPacket *cur_packet = (ACPacket*)((char*)This->local_buffer + This->bufsize_bytes); - BYTE *data = This->local_buffer; - silence_buffer(This->ss.format, This->local_buffer, This->bufsize_bytes); - list_init(&This->packet_free_head); - list_init(&This->packet_filled_head); - for (i = 0; i < capture_packets; ++i, ++cur_packet) { - list_add_tail(&This->packet_free_head, &cur_packet->entry); - cur_packet->data = data; - data += This->capture_period; - } - assert(!This->capture_period || This->bufsize_bytes == This->capture_period * capture_packets); - assert(!capture_packets || data - This->bufsize_bytes == This->local_buffer); - } - } - } - if (SUCCEEDED(hr)) - hr = get_audio_session(sessionguid, This->parent, fmt->nChannels, &This->session); - if (SUCCEEDED(hr)) - list_add_tail(&This->session->clients, &This->entry); - -exit: - if (FAILED(hr)) { - HeapFree(GetProcessHeap(), 0, This->local_buffer); - This->local_buffer = NULL; - if (This->stream) { - pa_stream_disconnect(This->stream); - pa_stream_unref(This->stream); - This->stream = NULL; - } - } - pthread_mutex_unlock(&pulse_lock); - return hr; -} - -static HRESULT WINAPI AudioClient_GetBufferSize(IAudioClient *iface, - UINT32 *out) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr; - - TRACE("(%p)->(%p)\n", This, out); - - if (!out) - return E_POINTER; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (SUCCEEDED(hr)) - *out = This->bufsize_frames; - pthread_mutex_unlock(&pulse_lock); - - return hr; -} - -static HRESULT WINAPI AudioClient_GetStreamLatency(IAudioClient *iface, - REFERENCE_TIME *latency) -{ - ACImpl *This = impl_from_IAudioClient(iface); - const pa_buffer_attr *attr; - REFERENCE_TIME lat; - HRESULT hr; - - TRACE("(%p)->(%p)\n", This, latency); - - if (!latency) - return E_POINTER; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) { - pthread_mutex_unlock(&pulse_lock); - return hr; - } - attr = pa_stream_get_buffer_attr(This->stream); - if (This->dataflow == eRender){ - lat = attr->minreq / pa_frame_size(&This->ss); - lat += pulse_def_period[0]; - }else - lat = attr->fragsize / pa_frame_size(&This->ss); - *latency = 10000000; - *latency *= lat; - *latency /= This->ss.rate; - pthread_mutex_unlock(&pulse_lock); - TRACE("Latency: %u ms\n", (DWORD)(*latency / 10000)); - return S_OK; -} - -static void ACImpl_GetRenderPad(ACImpl *This, UINT32 *out) -{ - *out = This->pad / pa_frame_size(&This->ss); -} - -static void ACImpl_GetCapturePad(ACImpl *This, UINT32 *out) -{ - ACPacket *packet = This->locked_ptr; - if (!packet && !list_empty(&This->packet_filled_head)) { - packet = (ACPacket*)list_head(&This->packet_filled_head); - This->locked_ptr = packet; - list_remove(&packet->entry); - } - if (out) - *out = This->pad / pa_frame_size(&This->ss); -} - -static HRESULT WINAPI AudioClient_GetCurrentPadding(IAudioClient *iface, - UINT32 *out) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr; - - TRACE("(%p)->(%p)\n", This, out); - - if (!out) - return E_POINTER; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) { - pthread_mutex_unlock(&pulse_lock); - return hr; - } - - if (This->dataflow == eRender) - ACImpl_GetRenderPad(This, out); - else - ACImpl_GetCapturePad(This, out); - pthread_mutex_unlock(&pulse_lock); - - TRACE("%p Pad: %u ms (%u)\n", This, MulDiv(*out, 1000, This->ss.rate), *out); - return S_OK; -} - -static HRESULT WINAPI AudioClient_IsFormatSupported(IAudioClient *iface, - AUDCLNT_SHAREMODE mode, const WAVEFORMATEX *fmt, - WAVEFORMATEX **out) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr = S_OK; - WAVEFORMATEX *closest = NULL; - BOOL exclusive; - - TRACE("(%p)->(%x, %p, %p)\n", This, mode, fmt, out); - - if (!fmt) - return E_POINTER; - - if (out) - *out = NULL; - - if (mode == AUDCLNT_SHAREMODE_EXCLUSIVE) { - exclusive = 1; - out = NULL; - } else if (mode == AUDCLNT_SHAREMODE_SHARED) { - exclusive = 0; - if (!out) - return E_POINTER; - } else - return E_INVALIDARG; - - if (fmt->nChannels == 0) - return AUDCLNT_E_UNSUPPORTED_FORMAT; - - closest = clone_format(fmt); - if (!closest) - return E_OUTOFMEMORY; - - dump_fmt(fmt); - - switch (fmt->wFormatTag) { - case WAVE_FORMAT_EXTENSIBLE: { - WAVEFORMATEXTENSIBLE *ext = (WAVEFORMATEXTENSIBLE*)closest; - - if ((fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) && - fmt->cbSize != sizeof(WAVEFORMATEXTENSIBLE)) || - fmt->nBlockAlign != fmt->wBitsPerSample / 8 * fmt->nChannels || - ext->Samples.wValidBitsPerSample > fmt->wBitsPerSample || - fmt->nAvgBytesPerSec != fmt->nBlockAlign * fmt->nSamplesPerSec) { - hr = E_INVALIDARG; - break; - } - - if (exclusive) { - UINT32 mask = 0, i, channels = 0; - - if (!(ext->dwChannelMask & (SPEAKER_ALL | SPEAKER_RESERVED))) { - for (i = 1; !(i & SPEAKER_RESERVED); i <<= 1) { - if (i & ext->dwChannelMask) { - mask |= i; - channels++; - } - } - - if (channels != fmt->nChannels || (ext->dwChannelMask & ~mask)) { - hr = AUDCLNT_E_UNSUPPORTED_FORMAT; - break; - } - } else { - hr = AUDCLNT_E_UNSUPPORTED_FORMAT; - break; - } - } - - if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { - if (fmt->wBitsPerSample != 32) { - hr = E_INVALIDARG; - break; - } - - if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample) { - hr = S_FALSE; - ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample; - } - } else if (IsEqualGUID(&ext->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) { - if (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8) { - hr = E_INVALIDARG; - break; - } - - if (ext->Samples.wValidBitsPerSample != fmt->wBitsPerSample && - !(fmt->wBitsPerSample == 32 && - ext->Samples.wValidBitsPerSample == 24)) { - hr = S_FALSE; - ext->Samples.wValidBitsPerSample = fmt->wBitsPerSample; - break; - } - } else { - hr = AUDCLNT_E_UNSUPPORTED_FORMAT; - break; - } - - break; - } - - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - if (fmt->wBitsPerSample != 8) { - hr = E_INVALIDARG; - break; - } - /* Fall-through */ - case WAVE_FORMAT_IEEE_FLOAT: - if (fmt->wFormatTag == WAVE_FORMAT_IEEE_FLOAT && fmt->wBitsPerSample != 32) { - hr = E_INVALIDARG; - break; - } - /* Fall-through */ - case WAVE_FORMAT_PCM: - if (fmt->wFormatTag == WAVE_FORMAT_PCM && - (!fmt->wBitsPerSample || fmt->wBitsPerSample > 32 || fmt->wBitsPerSample % 8)) { - hr = E_INVALIDARG; - break; - } - - if (fmt->nChannels > 2) { - hr = AUDCLNT_E_UNSUPPORTED_FORMAT; - break; - } - /* - * fmt->cbSize, fmt->nBlockAlign and fmt->nAvgBytesPerSec seem to be - * ignored, invalid values are happily accepted. - */ - break; - default: - hr = AUDCLNT_E_UNSUPPORTED_FORMAT; - break; - } - - if (exclusive && hr != S_OK) { - hr = AUDCLNT_E_UNSUPPORTED_FORMAT; - CoTaskMemFree(closest); - } else if (hr != S_FALSE) - CoTaskMemFree(closest); - else - *out = closest; - - /* Winepulse does not currently support exclusive mode, if you know of an - * application that uses it, I will correct this.. - */ - if (hr == S_OK && exclusive) - return This->dataflow == eCapture ? AUDCLNT_E_UNSUPPORTED_FORMAT : AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED; - - TRACE("returning: %08x %p\n", hr, out ? *out : NULL); - return hr; -} - -static HRESULT WINAPI AudioClient_GetMixFormat(IAudioClient *iface, - WAVEFORMATEX **pwfx) -{ - ACImpl *This = impl_from_IAudioClient(iface); - WAVEFORMATEXTENSIBLE *fmt = &pulse_fmt[This->dataflow == eCapture]; - - TRACE("(%p)->(%p)\n", This, pwfx); - - if (!pwfx) - return E_POINTER; - - *pwfx = clone_format(&fmt->Format); - if (!*pwfx) - return E_OUTOFMEMORY; - dump_fmt(*pwfx); - return S_OK; -} - -static HRESULT WINAPI AudioClient_GetDevicePeriod(IAudioClient *iface, - REFERENCE_TIME *defperiod, REFERENCE_TIME *minperiod) -{ - ACImpl *This = impl_from_IAudioClient(iface); - - TRACE("(%p)->(%p, %p)\n", This, defperiod, minperiod); - - if (!defperiod && !minperiod) - return E_POINTER; - - if (defperiod) - *defperiod = pulse_def_period[This->dataflow == eCapture]; - if (minperiod) - *minperiod = pulse_min_period[This->dataflow == eCapture]; - - return S_OK; -} - -static HRESULT WINAPI AudioClient_Start(IAudioClient *iface) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr = S_OK; - int success; - pa_operation *o; - - TRACE("(%p)\n", This); - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) { - pthread_mutex_unlock(&pulse_lock); - return hr; - } - - if ((This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) && !This->event) { - pthread_mutex_unlock(&pulse_lock); - return AUDCLNT_E_EVENTHANDLE_NOT_SET; - } - - if (This->started) { - pthread_mutex_unlock(&pulse_lock); - return AUDCLNT_E_NOT_STOPPED; - } - - if (pa_stream_is_corked(This->stream)) { - o = pa_stream_cork(This->stream, 0, pulse_op_cb, &success); - if (o) { - while(pa_operation_get_state(o) == PA_OPERATION_RUNNING) - pthread_cond_wait(&pulse_cond, &pulse_lock); - pa_operation_unref(o); - } else - success = 0; - if (!success) - hr = E_FAIL; - } - - if (SUCCEEDED(hr)) { - This->started = TRUE; - if (This->dataflow == eRender && This->event) - pa_stream_set_latency_update_callback(This->stream, pulse_latency_callback, This); - } - pthread_mutex_unlock(&pulse_lock); - return hr; -} - -static HRESULT WINAPI AudioClient_Stop(IAudioClient *iface) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr = S_OK; - pa_operation *o; - int success; - - TRACE("(%p)\n", This); - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) { - pthread_mutex_unlock(&pulse_lock); - return hr; - } - - if (!This->started) { - pthread_mutex_unlock(&pulse_lock); - return S_FALSE; - } - - if (This->dataflow == eRender) { - o = pa_stream_cork(This->stream, 1, pulse_op_cb, &success); - if (o) { - while(pa_operation_get_state(o) == PA_OPERATION_RUNNING) - pthread_cond_wait(&pulse_cond, &pulse_lock); - pa_operation_unref(o); - } else - success = 0; - if (!success) - hr = E_FAIL; - } - if (SUCCEEDED(hr)) { - This->started = FALSE; - } - pthread_mutex_unlock(&pulse_lock); - return hr; -} - -static HRESULT WINAPI AudioClient_Reset(IAudioClient *iface) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr = S_OK; - - TRACE("(%p)\n", This); - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) { - pthread_mutex_unlock(&pulse_lock); - return hr; - } - - if (This->started) { - pthread_mutex_unlock(&pulse_lock); - return AUDCLNT_E_NOT_STOPPED; - } - - if (This->locked) { - pthread_mutex_unlock(&pulse_lock); - return AUDCLNT_E_BUFFER_OPERATION_PENDING; - } - - if (This->dataflow == eRender) { - /* If there is still data in the render buffer it needs to be removed from the server */ - int success = 0; - if (This->pad) { - pa_operation *o = pa_stream_flush(This->stream, pulse_op_cb, &success); - if (o) { - while(pa_operation_get_state(o) == PA_OPERATION_RUNNING) - pthread_cond_wait(&pulse_cond, &pulse_lock); - pa_operation_unref(o); - } - } - if (success || !This->pad){ - This->clock_lastpos = This->clock_written = This->pad = 0; - This->wri_offs_bytes = This->lcl_offs_bytes = This->held_bytes = 0; - } - } else { - ACPacket *p; - This->clock_written += This->pad; - This->pad = 0; - - if ((p = This->locked_ptr)) { - This->locked_ptr = NULL; - list_add_tail(&This->packet_free_head, &p->entry); - } - list_move_tail(&This->packet_free_head, &This->packet_filled_head); - } - pthread_mutex_unlock(&pulse_lock); - - return hr; -} - -static HRESULT WINAPI AudioClient_SetEventHandle(IAudioClient *iface, - HANDLE event) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr; - - TRACE("(%p)->(%p)\n", This, event); - - if (!event) - return E_INVALIDARG; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) { - pthread_mutex_unlock(&pulse_lock); - return hr; - } - - if (!(This->flags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) - hr = AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED; - else if (This->event) - hr = HRESULT_FROM_WIN32(ERROR_INVALID_NAME); - else - This->event = event; - pthread_mutex_unlock(&pulse_lock); - return hr; -} - -static HRESULT WINAPI AudioClient_GetService(IAudioClient *iface, REFIID riid, - void **ppv) -{ - ACImpl *This = impl_from_IAudioClient(iface); - HRESULT hr; - - TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - pthread_mutex_unlock(&pulse_lock); - if (FAILED(hr)) - return hr; - - if (IsEqualIID(riid, &IID_IAudioRenderClient)) { - if (This->dataflow != eRender) - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - *ppv = &This->IAudioRenderClient_iface; - } else if (IsEqualIID(riid, &IID_IAudioCaptureClient)) { - if (This->dataflow != eCapture) - return AUDCLNT_E_WRONG_ENDPOINT_TYPE; - *ppv = &This->IAudioCaptureClient_iface; - } else if (IsEqualIID(riid, &IID_IAudioClock)) { - *ppv = &This->IAudioClock_iface; - } else if (IsEqualIID(riid, &IID_IAudioStreamVolume)) { - *ppv = &This->IAudioStreamVolume_iface; - } else if (IsEqualIID(riid, &IID_IAudioSessionControl) || - IsEqualIID(riid, &IID_IChannelAudioVolume) || - IsEqualIID(riid, &IID_ISimpleAudioVolume)) { - if (!This->session_wrapper) { - This->session_wrapper = AudioSessionWrapper_Create(This); - if (!This->session_wrapper) - return E_OUTOFMEMORY; - } - if (IsEqualIID(riid, &IID_IAudioSessionControl)) - *ppv = &This->session_wrapper->IAudioSessionControl2_iface; - else if (IsEqualIID(riid, &IID_IChannelAudioVolume)) - *ppv = &This->session_wrapper->IChannelAudioVolume_iface; - else if (IsEqualIID(riid, &IID_ISimpleAudioVolume)) - *ppv = &This->session_wrapper->ISimpleAudioVolume_iface; - } - - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - FIXME("stub %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static const IAudioClientVtbl AudioClient_Vtbl = -{ - AudioClient_QueryInterface, - AudioClient_AddRef, - AudioClient_Release, - AudioClient_Initialize, - AudioClient_GetBufferSize, - AudioClient_GetStreamLatency, - AudioClient_GetCurrentPadding, - AudioClient_IsFormatSupported, - AudioClient_GetMixFormat, - AudioClient_GetDevicePeriod, - AudioClient_Start, - AudioClient_Stop, - AudioClient_Reset, - AudioClient_SetEventHandle, - AudioClient_GetService -}; - -static HRESULT WINAPI AudioRenderClient_QueryInterface( - IAudioRenderClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioRenderClient)) - *ppv = iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - if (IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->marshal, riid, ppv); - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioRenderClient_AddRef(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_AddRef(&This->IAudioClient_iface); -} - -static ULONG WINAPI AudioRenderClient_Release(IAudioRenderClient *iface) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - return AudioClient_Release(&This->IAudioClient_iface); -} - -static void alloc_tmp_buffer(ACImpl *This, UINT32 bytes) -{ - if(This->tmp_buffer_bytes >= bytes) - return; - - HeapFree(GetProcessHeap(), 0, This->tmp_buffer); - This->tmp_buffer = HeapAlloc(GetProcessHeap(), 0, bytes); - This->tmp_buffer_bytes = bytes; -} - -static HRESULT WINAPI AudioRenderClient_GetBuffer(IAudioRenderClient *iface, - UINT32 frames, BYTE **data) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - size_t avail, req, bytes = frames * pa_frame_size(&This->ss); - UINT32 pad; - HRESULT hr = S_OK; - int ret = -1; - - TRACE("(%p)->(%u, %p)\n", This, frames, data); - - if (!data) - return E_POINTER; - *data = NULL; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr) || This->locked) { - pthread_mutex_unlock(&pulse_lock); - return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER; - } - if (!frames) { - pthread_mutex_unlock(&pulse_lock); - return S_OK; - } - - ACImpl_GetRenderPad(This, &pad); - avail = This->bufsize_frames - pad; - if (avail < frames || bytes > This->bufsize_bytes) { - pthread_mutex_unlock(&pulse_lock); - WARN("Wanted to write %u, but only %zu available\n", frames, avail); - return AUDCLNT_E_BUFFER_TOO_LARGE; - } - - if(This->local_buffer){ - if(This->wri_offs_bytes + bytes > This->bufsize_bytes){ - alloc_tmp_buffer(This, bytes); - *data = This->tmp_buffer; - This->locked = -frames; - }else{ - *data = This->local_buffer + This->wri_offs_bytes; - This->locked = frames; - } - }else{ - req = bytes; - ret = pa_stream_begin_write(This->stream, &This->locked_ptr, &req); - if (ret < 0 || req < bytes) { - FIXME("%p Not using pulse locked data: %i %zu/%u %u/%u\n", This, ret, req/pa_frame_size(&This->ss), frames, pad, This->bufsize_frames); - if (ret >= 0) - pa_stream_cancel_write(This->stream); - alloc_tmp_buffer(This, bytes); - *data = This->tmp_buffer; - This->locked_ptr = NULL; - } else - *data = This->locked_ptr; - - This->locked = frames; - } - - silence_buffer(This->ss.format, *data, bytes); - - pthread_mutex_unlock(&pulse_lock); - - return hr; -} - -static void pulse_wrap_buffer(ACImpl *This, BYTE *buffer, UINT32 written_bytes) -{ - UINT32 chunk_bytes = This->bufsize_bytes - This->wri_offs_bytes; - - if(written_bytes <= chunk_bytes){ - memcpy(This->local_buffer + This->wri_offs_bytes, buffer, written_bytes); - }else{ - memcpy(This->local_buffer + This->wri_offs_bytes, buffer, chunk_bytes); - memcpy(This->local_buffer, buffer + chunk_bytes, - written_bytes - chunk_bytes); - } -} - -static HRESULT WINAPI AudioRenderClient_ReleaseBuffer( - IAudioRenderClient *iface, UINT32 written_frames, DWORD flags) -{ - ACImpl *This = impl_from_IAudioRenderClient(iface); - UINT32 written_bytes = written_frames * pa_frame_size(&This->ss); - - TRACE("(%p)->(%u, %x)\n", This, written_frames, flags); - - pthread_mutex_lock(&pulse_lock); - if (!This->locked || !written_frames) { - if (This->locked_ptr) - pa_stream_cancel_write(This->stream); - This->locked = 0; - This->locked_ptr = NULL; - pthread_mutex_unlock(&pulse_lock); - return written_frames ? AUDCLNT_E_OUT_OF_ORDER : S_OK; - } - - if (This->locked < written_frames) { - pthread_mutex_unlock(&pulse_lock); - return AUDCLNT_E_INVALID_SIZE; - } - - if(This->local_buffer){ - BYTE *buffer; - - if(This->locked >= 0) - buffer = This->local_buffer + This->wri_offs_bytes; - else - buffer = This->tmp_buffer; - - if(flags & AUDCLNT_BUFFERFLAGS_SILENT) - silence_buffer(This->ss.format, buffer, written_bytes); - - if(This->locked < 0) - pulse_wrap_buffer(This, buffer, written_bytes); - - This->wri_offs_bytes += written_bytes; - This->wri_offs_bytes %= This->bufsize_bytes; - - This->pad += written_bytes; - This->held_bytes += written_bytes; - - if(This->held_bytes == This->pad){ - int e; - UINT32 to_write = min(This->attr.tlength, written_bytes); - - /* nothing in PA, so send data immediately */ - - TRACE("pre-writing %u bytes\n", to_write); - - e = write_buffer(This, buffer, to_write, 0); - if(e) - ERR("pa_stream_write failed: 0x%x\n", e); - - This->lcl_offs_bytes += to_write; - This->lcl_offs_bytes %= This->bufsize_bytes; - This->held_bytes -= to_write; - } - - }else{ - enum write_buffer_flags wr_flags = 0; - - if (flags & AUDCLNT_BUFFERFLAGS_SILENT) wr_flags |= WINEPULSE_WRITE_SILENT; - if (!This->locked_ptr) wr_flags |= WINEPULSE_WRITE_NOFREE; - - write_buffer(This, This->locked_ptr ? This->locked_ptr : This->tmp_buffer, written_bytes, wr_flags); - This->pad += written_bytes; - } - - if (!pa_stream_is_corked(This->stream)) { - int success; - pa_operation *o; - o = pa_stream_trigger(This->stream, pulse_op_cb, &success); - if (o) { - while(pa_operation_get_state(o) == PA_OPERATION_RUNNING) - pthread_cond_wait(&pulse_cond, &pulse_lock); - pa_operation_unref(o); - } - } - - This->locked = 0; - This->locked_ptr = NULL; - TRACE("Released %u, pad %zu\n", written_frames, This->pad / pa_frame_size(&This->ss)); - assert(This->pad <= This->bufsize_bytes); - - pthread_mutex_unlock(&pulse_lock); - return S_OK; -} - -static const IAudioRenderClientVtbl AudioRenderClient_Vtbl = { - AudioRenderClient_QueryInterface, - AudioRenderClient_AddRef, - AudioRenderClient_Release, - AudioRenderClient_GetBuffer, - AudioRenderClient_ReleaseBuffer -}; - -static HRESULT WINAPI AudioCaptureClient_QueryInterface( - IAudioCaptureClient *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioCaptureClient)) - *ppv = iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - if (IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->marshal, riid, ppv); - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioCaptureClient_AddRef(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient_AddRef(&This->IAudioClient_iface); -} - -static ULONG WINAPI AudioCaptureClient_Release(IAudioCaptureClient *iface) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - return IAudioClient_Release(&This->IAudioClient_iface); -} - -static HRESULT WINAPI AudioCaptureClient_GetBuffer(IAudioCaptureClient *iface, - BYTE **data, UINT32 *frames, DWORD *flags, UINT64 *devpos, - UINT64 *qpcpos) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - HRESULT hr; - ACPacket *packet; - - TRACE("(%p)->(%p, %p, %p, %p, %p)\n", This, data, frames, flags, - devpos, qpcpos); - - if (!data) - return E_POINTER; - - *data = NULL; - - if (!frames || !flags) - return E_POINTER; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr) || This->locked) { - pthread_mutex_unlock(&pulse_lock); - return FAILED(hr) ? hr : AUDCLNT_E_OUT_OF_ORDER; - } - - ACImpl_GetCapturePad(This, NULL); - if ((packet = This->locked_ptr)) { - *frames = This->capture_period / pa_frame_size(&This->ss); - *flags = 0; - if (packet->discont) - *flags |= AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY; - if (devpos) { - if (packet->discont) - *devpos = (This->clock_written + This->capture_period) / pa_frame_size(&This->ss); - else - *devpos = This->clock_written / pa_frame_size(&This->ss); - } - if (qpcpos) - *qpcpos = packet->qpcpos; - *data = packet->data; - } - else - *frames = 0; - This->locked = *frames; - pthread_mutex_unlock(&pulse_lock); - return *frames ? S_OK : AUDCLNT_S_BUFFER_EMPTY; -} - -static HRESULT WINAPI AudioCaptureClient_ReleaseBuffer( - IAudioCaptureClient *iface, UINT32 done) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - - TRACE("(%p)->(%u)\n", This, done); - - pthread_mutex_lock(&pulse_lock); - if (!This->locked && done) { - pthread_mutex_unlock(&pulse_lock); - return AUDCLNT_E_OUT_OF_ORDER; - } - if (done && This->locked != done) { - pthread_mutex_unlock(&pulse_lock); - return AUDCLNT_E_INVALID_SIZE; - } - if (done) { - ACPacket *packet = This->locked_ptr; - This->locked_ptr = NULL; - This->pad -= This->capture_period; - if (packet->discont) - This->clock_written += 2 * This->capture_period; - else - This->clock_written += This->capture_period; - list_add_tail(&This->packet_free_head, &packet->entry); - } - This->locked = 0; - pthread_mutex_unlock(&pulse_lock); - return S_OK; -} - -static HRESULT WINAPI AudioCaptureClient_GetNextPacketSize( - IAudioCaptureClient *iface, UINT32 *frames) -{ - ACImpl *This = impl_from_IAudioCaptureClient(iface); - - TRACE("(%p)->(%p)\n", This, frames); - if (!frames) - return E_POINTER; - - pthread_mutex_lock(&pulse_lock); - ACImpl_GetCapturePad(This, NULL); - if (This->locked_ptr) - *frames = This->capture_period / pa_frame_size(&This->ss); - else - *frames = 0; - pthread_mutex_unlock(&pulse_lock); - return S_OK; -} - -static const IAudioCaptureClientVtbl AudioCaptureClient_Vtbl = -{ - AudioCaptureClient_QueryInterface, - AudioCaptureClient_AddRef, - AudioCaptureClient_Release, - AudioCaptureClient_GetBuffer, - AudioCaptureClient_ReleaseBuffer, - AudioCaptureClient_GetNextPacketSize -}; - -static HRESULT WINAPI AudioClock_QueryInterface(IAudioClock *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IAudioClock)) - *ppv = iface; - else if (IsEqualIID(riid, &IID_IAudioClock2)) - *ppv = &This->IAudioClock2_iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - if (IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->marshal, riid, ppv); - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioClock_AddRef(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient_AddRef(&This->IAudioClient_iface); -} - -static ULONG WINAPI AudioClock_Release(IAudioClock *iface) -{ - ACImpl *This = impl_from_IAudioClock(iface); - return IAudioClient_Release(&This->IAudioClient_iface); -} - -static HRESULT WINAPI AudioClock_GetFrequency(IAudioClock *iface, UINT64 *freq) -{ - ACImpl *This = impl_from_IAudioClock(iface); - HRESULT hr; - - TRACE("(%p)->(%p)\n", This, freq); - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (SUCCEEDED(hr)) { - *freq = This->ss.rate; - if (This->share == AUDCLNT_SHAREMODE_SHARED) - *freq *= pa_frame_size(&This->ss); - } - pthread_mutex_unlock(&pulse_lock); - return hr; -} - -static HRESULT WINAPI AudioClock_GetPosition(IAudioClock *iface, UINT64 *pos, - UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock(iface); - HRESULT hr; - - TRACE("(%p)->(%p, %p)\n", This, pos, qpctime); - - if (!pos) - return E_POINTER; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) { - pthread_mutex_unlock(&pulse_lock); - return hr; - } - - *pos = This->clock_written; - - if (This->share == AUDCLNT_SHAREMODE_EXCLUSIVE) - *pos /= pa_frame_size(&This->ss); - - /* Make time never go backwards */ - if (*pos < This->clock_lastpos) - *pos = This->clock_lastpos; - else - This->clock_lastpos = *pos; - pthread_mutex_unlock(&pulse_lock); - - TRACE("%p Position: %u\n", This, (unsigned)*pos); - - if (qpctime) { - LARGE_INTEGER stamp, freq; - QueryPerformanceCounter(&stamp); - QueryPerformanceFrequency(&freq); - *qpctime = (stamp.QuadPart * (INT64)10000000) / freq.QuadPart; - } - - return S_OK; -} - -static HRESULT WINAPI AudioClock_GetCharacteristics(IAudioClock *iface, - DWORD *chars) -{ - ACImpl *This = impl_from_IAudioClock(iface); - - TRACE("(%p)->(%p)\n", This, chars); - - if (!chars) - return E_POINTER; - - *chars = AUDIOCLOCK_CHARACTERISTIC_FIXED_FREQ; - - return S_OK; -} - -static const IAudioClockVtbl AudioClock_Vtbl = -{ - AudioClock_QueryInterface, - AudioClock_AddRef, - AudioClock_Release, - AudioClock_GetFrequency, - AudioClock_GetPosition, - AudioClock_GetCharacteristics -}; - -static HRESULT WINAPI AudioClock2_QueryInterface(IAudioClock2 *iface, - REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClock_QueryInterface(&This->IAudioClock_iface, riid, ppv); -} - -static ULONG WINAPI AudioClock2_AddRef(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient_AddRef(&This->IAudioClient_iface); -} - -static ULONG WINAPI AudioClock2_Release(IAudioClock2 *iface) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - return IAudioClient_Release(&This->IAudioClient_iface); -} - -static HRESULT WINAPI AudioClock2_GetDevicePosition(IAudioClock2 *iface, - UINT64 *pos, UINT64 *qpctime) -{ - ACImpl *This = impl_from_IAudioClock2(iface); - HRESULT hr = AudioClock_GetPosition(&This->IAudioClock_iface, pos, qpctime); - if (SUCCEEDED(hr) && This->share == AUDCLNT_SHAREMODE_SHARED) - *pos /= pa_frame_size(&This->ss); - return hr; -} - -static const IAudioClock2Vtbl AudioClock2_Vtbl = -{ - AudioClock2_QueryInterface, - AudioClock2_AddRef, - AudioClock2_Release, - AudioClock2_GetDevicePosition -}; - -static HRESULT WINAPI AudioStreamVolume_QueryInterface( - IAudioStreamVolume *iface, REFIID riid, void **ppv) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioStreamVolume)) - *ppv = iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - if (IsEqualIID(riid, &IID_IMarshal)) - return IUnknown_QueryInterface(This->marshal, riid, ppv); - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioStreamVolume_AddRef(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient_AddRef(&This->IAudioClient_iface); -} - -static ULONG WINAPI AudioStreamVolume_Release(IAudioStreamVolume *iface) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - return IAudioClient_Release(&This->IAudioClient_iface); -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelCount( - IAudioStreamVolume *iface, UINT32 *out) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - - TRACE("(%p)->(%p)\n", This, out); - - if (!out) - return E_POINTER; - - *out = This->ss.channels; - - return S_OK; -} - -struct pulse_info_cb_data { - UINT32 n; - float *levels; -}; - -static HRESULT WINAPI AudioStreamVolume_SetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, const float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - HRESULT hr; - int i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if (!levels) - return E_POINTER; - - if (count != This->ss.channels) - return E_INVALIDARG; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) - goto out; - - for (i = 0; i < count; ++i) - This->vol[i] = levels[i]; - -out: - pthread_mutex_unlock(&pulse_lock); - return hr; -} - -static HRESULT WINAPI AudioStreamVolume_GetAllVolumes( - IAudioStreamVolume *iface, UINT32 count, float *levels) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - HRESULT hr; - int i; - - TRACE("(%p)->(%d, %p)\n", This, count, levels); - - if (!levels) - return E_POINTER; - - if (count != This->ss.channels) - return E_INVALIDARG; - - pthread_mutex_lock(&pulse_lock); - hr = pulse_stream_valid(This); - if (FAILED(hr)) - goto out; - - for (i = 0; i < count; ++i) - levels[i] = This->vol[i]; - -out: - pthread_mutex_unlock(&pulse_lock); - return hr; -} - -static HRESULT WINAPI AudioStreamVolume_SetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - HRESULT hr; - float volumes[PA_CHANNELS_MAX]; - - TRACE("(%p)->(%d, %f)\n", This, index, level); - - if (level < 0.f || level > 1.f) - return E_INVALIDARG; - - if (index >= This->ss.channels) - return E_INVALIDARG; - - hr = AudioStreamVolume_GetAllVolumes(iface, This->ss.channels, volumes); - volumes[index] = level; - if (SUCCEEDED(hr)) - hr = AudioStreamVolume_SetAllVolumes(iface, This->ss.channels, volumes); - return hr; -} - -static HRESULT WINAPI AudioStreamVolume_GetChannelVolume( - IAudioStreamVolume *iface, UINT32 index, float *level) -{ - ACImpl *This = impl_from_IAudioStreamVolume(iface); - float volumes[PA_CHANNELS_MAX]; - HRESULT hr; - - TRACE("(%p)->(%d, %p)\n", This, index, level); - - if (!level) - return E_POINTER; - - if (index >= This->ss.channels) - return E_INVALIDARG; - - hr = AudioStreamVolume_GetAllVolumes(iface, This->ss.channels, volumes); - if (SUCCEEDED(hr)) - *level = volumes[index]; - return hr; -} - -static const IAudioStreamVolumeVtbl AudioStreamVolume_Vtbl = -{ - AudioStreamVolume_QueryInterface, - AudioStreamVolume_AddRef, - AudioStreamVolume_Release, - AudioStreamVolume_GetChannelCount, - AudioStreamVolume_SetChannelVolume, - AudioStreamVolume_GetChannelVolume, - AudioStreamVolume_SetAllVolumes, - AudioStreamVolume_GetAllVolumes -}; - -static AudioSessionWrapper *AudioSessionWrapper_Create(ACImpl *client) -{ - AudioSessionWrapper *ret; - - ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(AudioSessionWrapper)); - if (!ret) - return NULL; - - ret->IAudioSessionControl2_iface.lpVtbl = &AudioSessionControl2_Vtbl; - ret->ISimpleAudioVolume_iface.lpVtbl = &SimpleAudioVolume_Vtbl; - ret->IChannelAudioVolume_iface.lpVtbl = &ChannelAudioVolume_Vtbl; - - ret->ref = !client; - - ret->client = client; - if (client) { - ret->session = client->session; - AudioClient_AddRef(&client->IAudioClient_iface); - } - - return ret; -} - -static HRESULT WINAPI AudioSessionControl_QueryInterface( - IAudioSessionControl2 *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionControl) || - IsEqualIID(riid, &IID_IAudioSessionControl2)) - *ppv = iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI AudioSessionControl_AddRef(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %u\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionControl_Release(IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %u\n", This, ref); - if (!ref) { - if (This->client) { - This->client->session_wrapper = NULL; - AudioClient_Release(&This->client->IAudioClient_iface); - } - HeapFree(GetProcessHeap(), 0, This); - } - return ref; -} - -static HRESULT WINAPI AudioSessionControl_GetState(IAudioSessionControl2 *iface, - AudioSessionState *state) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - ACImpl *client; - - TRACE("(%p)->(%p)\n", This, state); - - if (!state) - return NULL_PTR_ERR; - - pthread_mutex_lock(&pulse_lock); - if (list_empty(&This->session->clients)) { - *state = AudioSessionStateExpired; - goto out; - } - LIST_FOR_EACH_ENTRY(client, &This->session->clients, ACImpl, entry) { - if (client->started) { - *state = AudioSessionStateActive; - goto out; - } - } - *state = AudioSessionStateInactive; - -out: - pthread_mutex_unlock(&pulse_lock); - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetDisplayName( - IAudioSessionControl2 *iface, WCHAR **name) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, name); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetDisplayName( - IAudioSessionControl2 *iface, const WCHAR *name, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, name, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetIconPath( - IAudioSessionControl2 *iface, WCHAR **path) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, path); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetIconPath( - IAudioSessionControl2 *iface, const WCHAR *path, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p, %s) - stub\n", This, path, debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetGroupingParam( - IAudioSessionControl2 *iface, GUID *group) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, group); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_SetGroupingParam( - IAudioSessionControl2 *iface, const GUID *group, const GUID *session) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%s, %s) - stub\n", This, debugstr_guid(group), - debugstr_guid(session)); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_RegisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_UnregisterAudioSessionNotification( - IAudioSessionControl2 *iface, IAudioSessionEvents *events) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, events); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetSessionInstanceIdentifier( - IAudioSessionControl2 *iface, WCHAR **id) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - FIXME("(%p)->(%p) - stub\n", This, id); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionControl_GetProcessId( - IAudioSessionControl2 *iface, DWORD *pid) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%p)\n", This, pid); - - if (!pid) - return E_POINTER; - - *pid = GetCurrentProcessId(); - - return S_OK; -} - -static HRESULT WINAPI AudioSessionControl_IsSystemSoundsSession( - IAudioSessionControl2 *iface) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)\n", This); - - return S_FALSE; -} - -static HRESULT WINAPI AudioSessionControl_SetDuckingPreference( - IAudioSessionControl2 *iface, BOOL optout) -{ - AudioSessionWrapper *This = impl_from_IAudioSessionControl2(iface); - - TRACE("(%p)->(%d)\n", This, optout); - - return S_OK; -} - -static const IAudioSessionControl2Vtbl AudioSessionControl2_Vtbl = -{ - AudioSessionControl_QueryInterface, - AudioSessionControl_AddRef, - AudioSessionControl_Release, - AudioSessionControl_GetState, - AudioSessionControl_GetDisplayName, - AudioSessionControl_SetDisplayName, - AudioSessionControl_GetIconPath, - AudioSessionControl_SetIconPath, - AudioSessionControl_GetGroupingParam, - AudioSessionControl_SetGroupingParam, - AudioSessionControl_RegisterAudioSessionNotification, - AudioSessionControl_UnregisterAudioSessionNotification, - AudioSessionControl_GetSessionIdentifier, - AudioSessionControl_GetSessionInstanceIdentifier, - AudioSessionControl_GetProcessId, - AudioSessionControl_IsSystemSoundsSession, - AudioSessionControl_SetDuckingPreference -}; - -typedef struct _SessionMgr { - IAudioSessionManager2 IAudioSessionManager2_iface; - - LONG ref; - - IMMDevice *device; -} SessionMgr; - -static HRESULT WINAPI AudioSessionManager_QueryInterface(IAudioSessionManager2 *iface, - REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IAudioSessionManager) || - IsEqualIID(riid, &IID_IAudioSessionManager2)) - *ppv = iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static inline SessionMgr *impl_from_IAudioSessionManager2(IAudioSessionManager2 *iface) -{ - return CONTAINING_RECORD(iface, SessionMgr, IAudioSessionManager2_iface); -} - -static ULONG WINAPI AudioSessionManager_AddRef(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedIncrement(&This->ref); - TRACE("(%p) Refcount now %u\n", This, ref); - return ref; -} - -static ULONG WINAPI AudioSessionManager_Release(IAudioSessionManager2 *iface) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - ULONG ref; - ref = InterlockedDecrement(&This->ref); - TRACE("(%p) Refcount now %u\n", This, ref); - if (!ref) - HeapFree(GetProcessHeap(), 0, This); - return ref; -} - -static HRESULT WINAPI AudioSessionManager_GetAudioSessionControl( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - IAudioSessionControl **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if (FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if (!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = (IAudioSessionControl*)&wrapper->IAudioSessionControl2_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSimpleAudioVolume( - IAudioSessionManager2 *iface, const GUID *session_guid, DWORD flags, - ISimpleAudioVolume **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - AudioSession *session; - AudioSessionWrapper *wrapper; - HRESULT hr; - - TRACE("(%p)->(%s, %x, %p)\n", This, debugstr_guid(session_guid), - flags, out); - - hr = get_audio_session(session_guid, This->device, 0, &session); - if (FAILED(hr)) - return hr; - - wrapper = AudioSessionWrapper_Create(NULL); - if (!wrapper) - return E_OUTOFMEMORY; - - wrapper->session = session; - - *out = &wrapper->ISimpleAudioVolume_iface; - - return S_OK; -} - -static HRESULT WINAPI AudioSessionManager_GetSessionEnumerator( - IAudioSessionManager2 *iface, IAudioSessionEnumerator **out) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, out); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterSessionNotification( - IAudioSessionManager2 *iface, IAudioSessionNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_RegisterDuckNotification( - IAudioSessionManager2 *iface, const WCHAR *session_id, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static HRESULT WINAPI AudioSessionManager_UnregisterDuckNotification( - IAudioSessionManager2 *iface, - IAudioVolumeDuckNotification *notification) -{ - SessionMgr *This = impl_from_IAudioSessionManager2(iface); - FIXME("(%p)->(%p) - stub\n", This, notification); - return E_NOTIMPL; -} - -static const IAudioSessionManager2Vtbl AudioSessionManager2_Vtbl = -{ - AudioSessionManager_QueryInterface, - AudioSessionManager_AddRef, - AudioSessionManager_Release, - AudioSessionManager_GetAudioSessionControl, - AudioSessionManager_GetSimpleAudioVolume, - AudioSessionManager_GetSessionEnumerator, - AudioSessionManager_RegisterSessionNotification, - AudioSessionManager_UnregisterSessionNotification, - AudioSessionManager_RegisterDuckNotification, - AudioSessionManager_UnregisterDuckNotification -}; - -static HRESULT WINAPI SimpleAudioVolume_QueryInterface( - ISimpleAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_ISimpleAudioVolume)) - *ppv = iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI SimpleAudioVolume_AddRef(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI SimpleAudioVolume_Release(ISimpleAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI SimpleAudioVolume_SetMasterVolume( - ISimpleAudioVolume *iface, float level, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%f, %s)\n", session, level, wine_dbgstr_guid(context)); - - if (level < 0.f || level > 1.f) - return E_INVALIDARG; - - if (context) - FIXME("Notifications not supported yet\n"); - - TRACE("PulseAudio does not support session volume control\n"); - - pthread_mutex_lock(&pulse_lock); - session->master_vol = level; - pthread_mutex_unlock(&pulse_lock); - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMasterVolume( - ISimpleAudioVolume *iface, float *level) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, level); - - if (!level) - return NULL_PTR_ERR; - - *level = session->master_vol; - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_SetMute(ISimpleAudioVolume *iface, - BOOL mute, const GUID *context) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%u, %s)\n", session, mute, debugstr_guid(context)); - - if (context) - FIXME("Notifications not supported yet\n"); - - session->mute = mute; - - return S_OK; -} - -static HRESULT WINAPI SimpleAudioVolume_GetMute(ISimpleAudioVolume *iface, - BOOL *mute) -{ - AudioSessionWrapper *This = impl_from_ISimpleAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, mute); - - if (!mute) - return NULL_PTR_ERR; - - *mute = session->mute; - - return S_OK; -} - -static const ISimpleAudioVolumeVtbl SimpleAudioVolume_Vtbl = -{ - SimpleAudioVolume_QueryInterface, - SimpleAudioVolume_AddRef, - SimpleAudioVolume_Release, - SimpleAudioVolume_SetMasterVolume, - SimpleAudioVolume_GetMasterVolume, - SimpleAudioVolume_SetMute, - SimpleAudioVolume_GetMute -}; - -static HRESULT WINAPI ChannelAudioVolume_QueryInterface( - IChannelAudioVolume *iface, REFIID riid, void **ppv) -{ - TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); - - if (!ppv) - return E_POINTER; - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IChannelAudioVolume)) - *ppv = iface; - if (*ppv) { - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; - } - - WARN("Unknown interface %s\n", debugstr_guid(riid)); - return E_NOINTERFACE; -} - -static ULONG WINAPI ChannelAudioVolume_AddRef(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_AddRef(&This->IAudioSessionControl2_iface); -} - -static ULONG WINAPI ChannelAudioVolume_Release(IChannelAudioVolume *iface) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - return AudioSessionControl_Release(&This->IAudioSessionControl2_iface); -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelCount( - IChannelAudioVolume *iface, UINT32 *out) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%p)\n", session, out); - - if (!out) - return NULL_PTR_ERR; - - *out = session->channel_count; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float level, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%d, %f, %s)\n", session, index, level, - wine_dbgstr_guid(context)); - - if (level < 0.f || level > 1.f) - return E_INVALIDARG; - - if (index >= session->channel_count) - return E_INVALIDARG; - - if (context) - FIXME("Notifications not supported yet\n"); - - TRACE("PulseAudio does not support session volume control\n"); - - pthread_mutex_lock(&pulse_lock); - session->channel_vols[index] = level; - pthread_mutex_unlock(&pulse_lock); - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetChannelVolume( - IChannelAudioVolume *iface, UINT32 index, float *level) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - - TRACE("(%p)->(%d, %p)\n", session, index, level); - - if (!level) - return NULL_PTR_ERR; - - if (index >= session->channel_count) - return E_INVALIDARG; - - *level = session->channel_vols[index]; - - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_SetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, const float *levels, - const GUID *context) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - int i; - - TRACE("(%p)->(%d, %p, %s)\n", session, count, levels, - wine_dbgstr_guid(context)); - - if (!levels) - return NULL_PTR_ERR; - - if (count != session->channel_count) - return E_INVALIDARG; - - if (context) - FIXME("Notifications not supported yet\n"); - - TRACE("PulseAudio does not support session volume control\n"); - - pthread_mutex_lock(&pulse_lock); - for(i = 0; i < count; ++i) - session->channel_vols[i] = levels[i]; - pthread_mutex_unlock(&pulse_lock); - return S_OK; -} - -static HRESULT WINAPI ChannelAudioVolume_GetAllVolumes( - IChannelAudioVolume *iface, UINT32 count, float *levels) -{ - AudioSessionWrapper *This = impl_from_IChannelAudioVolume(iface); - AudioSession *session = This->session; - int i; - - TRACE("(%p)->(%d, %p)\n", session, count, levels); - - if (!levels) - return NULL_PTR_ERR; - - if (count != session->channel_count) - return E_INVALIDARG; - - for(i = 0; i < count; ++i) - levels[i] = session->channel_vols[i]; - - return S_OK; -} - -static const IChannelAudioVolumeVtbl ChannelAudioVolume_Vtbl = -{ - ChannelAudioVolume_QueryInterface, - ChannelAudioVolume_AddRef, - ChannelAudioVolume_Release, - ChannelAudioVolume_GetChannelCount, - ChannelAudioVolume_SetChannelVolume, - ChannelAudioVolume_GetChannelVolume, - ChannelAudioVolume_SetAllVolumes, - ChannelAudioVolume_GetAllVolumes -}; - -HRESULT WINAPI AUDDRV_GetAudioSessionManager(IMMDevice *device, - IAudioSessionManager2 **out) -{ - SessionMgr *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SessionMgr)); - *out = NULL; - if (!This) - return E_OUTOFMEMORY; - This->IAudioSessionManager2_iface.lpVtbl = &AudioSessionManager2_Vtbl; - This->device = device; - This->ref = 1; - *out = &This->IAudioSessionManager2_iface; - return S_OK; -} - -HRESULT WINAPI AUDDRV_GetPropValue(GUID *guid, const PROPERTYKEY *prop, PROPVARIANT *out) -{ - TRACE("%s, (%s,%u), %p\n", wine_dbgstr_guid(guid), wine_dbgstr_guid(&prop->fmtid), prop->pid, out); - - if (IsEqualGUID(guid, &pulse_render_guid) && IsEqualPropertyKey(*prop, PKEY_AudioEndpoint_PhysicalSpeakers)) { - out->vt = VT_UI4; - out->ulVal = g_phys_speakers_mask; - - return out->ulVal ? S_OK : E_FAIL; - } - - return E_NOTIMPL; -} - - - -/********************************************************************** - * A-law and u-law sample manipulation functions - * Multiply with the given volume (vol must be between 0...1 inclusive) - * - * These were taken from PulseAudio's sources but adjusted to directly - * fit our usage (since we use floats directly) so they should be exact. - */ -static UINT8 mult_alaw_sample(UINT8 sample, float vol) -{ - static const float decode_to_13bits_float[1 << 8] = - { - -688.0f, -656.0f, -752.0f, -720.0f, -560.0f, -528.0f, -624.0f, -592.0f, - -944.0f, -912.0f, -1008.0f, -976.0f, -816.0f, -784.0f, -880.0f, -848.0f, - -344.0f, -328.0f, -376.0f, -360.0f, -280.0f, -264.0f, -312.0f, -296.0f, - -472.0f, -456.0f, -504.0f, -488.0f, -408.0f, -392.0f, -440.0f, -424.0f, - -2752.0f, -2624.0f, -3008.0f, -2880.0f, -2240.0f, -2112.0f, -2496.0f, -2368.0f, - -3776.0f, -3648.0f, -4032.0f, -3904.0f, -3264.0f, -3136.0f, -3520.0f, -3392.0f, - -1376.0f, -1312.0f, -1504.0f, -1440.0f, -1120.0f, -1056.0f, -1248.0f, -1184.0f, - -1888.0f, -1824.0f, -2016.0f, -1952.0f, -1632.0f, -1568.0f, -1760.0f, -1696.0f, - -43.0f, -41.0f, -47.0f, -45.0f, -35.0f, -33.0f, -39.0f, -37.0f, - -59.0f, -57.0f, -63.0f, -61.0f, -51.0f, -49.0f, -55.0f, -53.0f, - -11.0f, -9.0f, -15.0f, -13.0f, -3.0f, -1.0f, -7.0f, -5.0f, - -27.0f, -25.0f, -31.0f, -29.0f, -19.0f, -17.0f, -23.0f, -21.0f, - -172.0f, -164.0f, -188.0f, -180.0f, -140.0f, -132.0f, -156.0f, -148.0f, - -236.0f, -228.0f, -252.0f, -244.0f, -204.0f, -196.0f, -220.0f, -212.0f, - -86.0f, -82.0f, -94.0f, -90.0f, -70.0f, -66.0f, -78.0f, -74.0f, - -118.0f, -114.0f, -126.0f, -122.0f, -102.0f, -98.0f, -110.0f, -106.0f, - 688.0f, 656.0f, 752.0f, 720.0f, 560.0f, 528.0f, 624.0f, 592.0f, - 944.0f, 912.0f, 1008.0f, 976.0f, 816.0f, 784.0f, 880.0f, 848.0f, - 344.0f, 328.0f, 376.0f, 360.0f, 280.0f, 264.0f, 312.0f, 296.0f, - 472.0f, 456.0f, 504.0f, 488.0f, 408.0f, 392.0f, 440.0f, 424.0f, - 2752.0f, 2624.0f, 3008.0f, 2880.0f, 2240.0f, 2112.0f, 2496.0f, 2368.0f, - 3776.0f, 3648.0f, 4032.0f, 3904.0f, 3264.0f, 3136.0f, 3520.0f, 3392.0f, - 1376.0f, 1312.0f, 1504.0f, 1440.0f, 1120.0f, 1056.0f, 1248.0f, 1184.0f, - 1888.0f, 1824.0f, 2016.0f, 1952.0f, 1632.0f, 1568.0f, 1760.0f, 1696.0f, - 43.0f, 41.0f, 47.0f, 45.0f, 35.0f, 33.0f, 39.0f, 37.0f, - 59.0f, 57.0f, 63.0f, 61.0f, 51.0f, 49.0f, 55.0f, 53.0f, - 11.0f, 9.0f, 15.0f, 13.0f, 3.0f, 1.0f, 7.0f, 5.0f, - 27.0f, 25.0f, 31.0f, 29.0f, 19.0f, 17.0f, 23.0f, 21.0f, - 172.0f, 164.0f, 188.0f, 180.0f, 140.0f, 132.0f, 156.0f, 148.0f, - 236.0f, 228.0f, 252.0f, 244.0f, 204.0f, 196.0f, 220.0f, 212.0f, - 86.0f, 82.0f, 94.0f, 90.0f, 70.0f, 66.0f, 78.0f, 74.0f, - 118.0f, 114.0f, 126.0f, 122.0f, 102.0f, 98.0f, 110.0f, 106.0f - }; - - static const UINT8 encode[1 << 13] = - { - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, - 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, - 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, - 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, - 0x6f, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, - 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, - 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, - 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x65, - 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, - 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, - 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, - 0x73, 0x73, 0x73, 0x73, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, - 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, - 0x75, 0x75, 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, - 0x4f, 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, - 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, 0x58, - 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, 0x52, 0x52, - 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, - 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, 0xd1, 0xd1, 0xd0, 0xd0, - 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, 0xdf, 0xdf, 0xde, 0xde, 0xd9, - 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, - 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, - 0xcc, 0xcf, 0xcf, 0xce, 0xce, 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, - 0xf5, 0xf5, 0xf5, 0xf5, 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, - 0xf6, 0xf6, 0xf6, 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, - 0xf3, 0xf3, 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, - 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, - 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, 0xe5, - 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, 0xe4, - 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, - 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, - 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, - 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, - 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, - 0xec, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, - 0xee, 0xee, 0xee, 0xee, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, - 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, - 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa - }; - - return encode[(int)(vol * decode_to_13bits_float[sample]) + ARRAY_SIZE(encode) / 2]; -} - -static UINT8 mult_ulaw_sample(UINT8 sample, float vol) -{ - static const float decode_to_14bits_float[1 << 8] = - { - -8031.0f, -7775.0f, -7519.0f, -7263.0f, -7007.0f, -6751.0f, -6495.0f, -6239.0f, - -5983.0f, -5727.0f, -5471.0f, -5215.0f, -4959.0f, -4703.0f, -4447.0f, -4191.0f, - -3999.0f, -3871.0f, -3743.0f, -3615.0f, -3487.0f, -3359.0f, -3231.0f, -3103.0f, - -2975.0f, -2847.0f, -2719.0f, -2591.0f, -2463.0f, -2335.0f, -2207.0f, -2079.0f, - -1983.0f, -1919.0f, -1855.0f, -1791.0f, -1727.0f, -1663.0f, -1599.0f, -1535.0f, - -1471.0f, -1407.0f, -1343.0f, -1279.0f, -1215.0f, -1151.0f, -1087.0f, -1023.0f, - -975.0f, -943.0f, -911.0f, -879.0f, -847.0f, -815.0f, -783.0f, -751.0f, - -719.0f, -687.0f, -655.0f, -623.0f, -591.0f, -559.0f, -527.0f, -495.0f, - -471.0f, -455.0f, -439.0f, -423.0f, -407.0f, -391.0f, -375.0f, -359.0f, - -343.0f, -327.0f, -311.0f, -295.0f, -279.0f, -263.0f, -247.0f, -231.0f, - -219.0f, -211.0f, -203.0f, -195.0f, -187.0f, -179.0f, -171.0f, -163.0f, - -155.0f, -147.0f, -139.0f, -131.0f, -123.0f, -115.0f, -107.0f, -99.0f, - -93.0f, -89.0f, -85.0f, -81.0f, -77.0f, -73.0f, -69.0f, -65.0f, - -61.0f, -57.0f, -53.0f, -49.0f, -45.0f, -41.0f, -37.0f, -33.0f, - -30.0f, -28.0f, -26.0f, -24.0f, -22.0f, -20.0f, -18.0f, -16.0f, - -14.0f, -12.0f, -10.0f, -8.0f, -6.0f, -4.0f, -2.0f, 0.0f, - 8031.0f, 7775.0f, 7519.0f, 7263.0f, 7007.0f, 6751.0f, 6495.0f, 6239.0f, - 5983.0f, 5727.0f, 5471.0f, 5215.0f, 4959.0f, 4703.0f, 4447.0f, 4191.0f, - 3999.0f, 3871.0f, 3743.0f, 3615.0f, 3487.0f, 3359.0f, 3231.0f, 3103.0f, - 2975.0f, 2847.0f, 2719.0f, 2591.0f, 2463.0f, 2335.0f, 2207.0f, 2079.0f, - 1983.0f, 1919.0f, 1855.0f, 1791.0f, 1727.0f, 1663.0f, 1599.0f, 1535.0f, - 1471.0f, 1407.0f, 1343.0f, 1279.0f, 1215.0f, 1151.0f, 1087.0f, 1023.0f, - 975.0f, 943.0f, 911.0f, 879.0f, 847.0f, 815.0f, 783.0f, 751.0f, - 719.0f, 687.0f, 655.0f, 623.0f, 591.0f, 559.0f, 527.0f, 495.0f, - 471.0f, 455.0f, 439.0f, 423.0f, 407.0f, 391.0f, 375.0f, 359.0f, - 343.0f, 327.0f, 311.0f, 295.0f, 279.0f, 263.0f, 247.0f, 231.0f, - 219.0f, 211.0f, 203.0f, 195.0f, 187.0f, 179.0f, 171.0f, 163.0f, - 155.0f, 147.0f, 139.0f, 131.0f, 123.0f, 115.0f, 107.0f, 99.0f, - 93.0f, 89.0f, 85.0f, 81.0f, 77.0f, 73.0f, 69.0f, 65.0f, - 61.0f, 57.0f, 53.0f, 49.0f, 45.0f, 41.0f, 37.0f, 33.0f, - 30.0f, 28.0f, 26.0f, 24.0f, 22.0f, 20.0f, 18.0f, 16.0f, - 14.0f, 12.0f, 10.0f, 8.0f, 6.0f, 4.0f, 2.0f, 0.0f - }; - - static const UINT8 encode[1 << 14] = - { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, - 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, - 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, - 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, - 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, - 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, - 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, - 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, - 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, - 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, - 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, - 0x19, 0x19, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, - 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, - 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, - 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, - 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, - 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, - 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, - 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, - 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, - 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, - 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, - 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, - 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, - 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, - 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, - 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, - 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, - 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, - 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, - 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, - 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, - 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, - 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, - 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, - 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, - 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, - 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, - 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, - 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, - 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, - 0x42, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, - 0x43, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, - 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, - 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, - 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, - 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, - 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, - 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, - 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, - 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, - 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, - 0x4b, 0x4b, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, - 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, - 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, - 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, - 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, - 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x51, - 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, - 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, - 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, - 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, - 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, - 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, - 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, - 0x5c, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, - 0x5e, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, - 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, - 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, - 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x69, - 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, - 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x70, 0x70, - 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, - 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, - 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, - 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, - 0xf3, 0xf2, 0xf2, 0xf1, 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, - 0xee, 0xee, 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, - 0xeb, 0xea, 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, - 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, - 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, 0xe1, - 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, - 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, 0xdd, 0xdd, 0xdd, - 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb, - 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, - 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, - 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, - 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, - 0xd5, 0xd5, 0xd5, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, - 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, - 0xd2, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, - 0xd0, 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, - 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, - 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, 0xcd, 0xcd, - 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, - 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, - 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, - 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, - 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, - 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, - 0xc8, 0xc8, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, - 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, - 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, - 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, - 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, - 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, - 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, - 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, - 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, - 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, - 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, - 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, - 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, - 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, - 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, - 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, - 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, - 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, - 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, - 0xb5, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, - 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, - 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, - 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, - 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, - 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, - 0xae, 0xae, 0xae, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, - 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, - 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, - 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, - 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, - 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, - 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, - 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, - 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, - 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, - 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, - 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, - 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, - 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, - 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, - 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, - 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, - 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, - 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, - 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, - 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, - 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, - 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, - 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, - 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, - 0x8e, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, - 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, - 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, - 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, - 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, - 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, - 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, - 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, - 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, - 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, - 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, - 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, - 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80 - }; - - return encode[(int)(vol * decode_to_14bits_float[sample]) + ARRAY_SIZE(encode) / 2]; -} diff --git a/pkgs/osu-wine/audio-revert/winepulse.drv/winepulse.drv.spec b/pkgs/osu-wine/audio-revert/winepulse.drv/winepulse.drv.spec deleted file mode 100644 index 7aeb175..0000000 --- a/pkgs/osu-wine/audio-revert/winepulse.drv/winepulse.drv.spec +++ /dev/null @@ -1,11 +0,0 @@ -# MMDevAPI driver functions -@ stdcall -private GetPriority() AUDDRV_GetPriority -@ stdcall -private GetEndpointIDs(long ptr ptr ptr ptr) AUDDRV_GetEndpointIDs -@ stdcall -private GetAudioEndpoint(ptr ptr ptr) AUDDRV_GetAudioEndpoint -@ stdcall -private GetAudioSessionManager(ptr ptr) AUDDRV_GetAudioSessionManager -@ stdcall -private GetPropValue(ptr ptr ptr) AUDDRV_GetPropValue - -# WinMM driver functions -@ stdcall -private DriverProc(long long long long long) winealsa.drv.DriverProc -@ stdcall -private midMessage(long long long long long) winealsa.drv.midMessage -@ stdcall -private modMessage(long long long long long) winealsa.drv.modMessage diff --git a/pkgs/osu-wine/default.nix b/pkgs/osu-wine/default.nix deleted file mode 100644 index 321dd8a..0000000 --- a/pkgs/osu-wine/default.nix +++ /dev/null @@ -1,64 +0,0 @@ -## Configuration: -# Control you default wine config in nixpkgs-config: -# wine = { -# release = "stable"; # "stable", "unstable", "staging", "wayland" -# build = "wineWow"; # "wine32", "wine64", "wineWow" -# }; -# Make additional configurations on demand: -# wine.override { wineBuild = "wine32"; wineRelease = "staging"; }; -{ lib, stdenv, callPackage, darwin, - wineBuild ? if stdenv.hostPlatform.system == "x86_64-linux" then "wineWow" else "wine32", - gettextSupport ? true, - fontconfigSupport ? stdenv.isLinux, - alsaSupport ? stdenv.isLinux, - gtkSupport ? false, - openglSupport ? true, - tlsSupport ? true, - gstreamerSupport ? false, - cupsSupport ? true, - dbusSupport ? stdenv.isLinux, - openclSupport ? false, - cairoSupport ? stdenv.isLinux, - odbcSupport ? false, - netapiSupport ? false, - cursesSupport ? true, - vaSupport ? false, - pcapSupport ? false, - v4lSupport ? false, - saneSupport ? stdenv.isLinux, - gphoto2Support ? false, - krb5Support ? false, - pulseaudioSupport ? stdenv.isLinux, - udevSupport ? stdenv.isLinux, - xineramaSupport ? stdenv.isLinux, - vulkanSupport ? true, - sdlSupport ? true, - usbSupport ? true, - mingwSupport ? true, - waylandSupport ? stdenv.isLinux, - x11Support ? stdenv.isLinux, - embedInstallers ? false, # The Mono and Gecko MSI installers - moltenvk ? darwin.moltenvk # Allow users to override MoltenVK easily -}: - -let wine-build = build: release: - lib.getAttr build (callPackage ./packages.nix { - wineRelease = release; - supportFlags = { - inherit - alsaSupport cairoSupport cupsSupport cursesSupport dbusSupport - embedInstallers fontconfigSupport gettextSupport gphoto2Support - gstreamerSupport gtkSupport krb5Support mingwSupport netapiSupport - odbcSupport openclSupport openglSupport pcapSupport - pulseaudioSupport saneSupport sdlSupport tlsSupport udevSupport - usbSupport v4lSupport vaSupport vulkanSupport waylandSupport - x11Support xineramaSupport - ; - }; - inherit moltenvk; - }); - -in - callPackage ./osu-wine.nix { - wineUnstable = wine-build wineBuild "unstable"; - } diff --git a/pkgs/osu-wine/osu-wine.nix b/pkgs/osu-wine/osu-wine.nix deleted file mode 100644 index 8765158..0000000 --- a/pkgs/osu-wine/osu-wine.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ lib, callPackage, autoconf, hexdump, perl, python3, wineUnstable, path }: - -with callPackage "${path}/pkgs/applications/emulators/wine/util.nix" {}; - -let patch = (callPackage ./sources.nix {}).staging; - build-inputs = pkgNames: extra: - (mkBuildInputs wineUnstable.pkgArches pkgNames) ++ extra; - patchList = lib.mapAttrsToList (k: v: ./patches/${k}) (builtins.readDir ./patches); -in assert lib.versions.majorMinor wineUnstable.version == lib.versions.majorMinor patch.version; - -(lib.overrideDerivation (wineUnstable.override { wineRelease = "staging"; }) (self: { - buildInputs = build-inputs [ "perl" "util-linux" "autoconf" "gitMinimal" ] self.buildInputs; - nativeBuildInputs = [ autoconf hexdump perl python3 ] ++ self.nativeBuildInputs; - - prePatch = self.prePatch or "" + '' - patchShebangs tools - cp -r ${patch}/patches ${patch}/staging . - chmod +w patches - patchShebangs ./patches/gitapply.sh - python3 ./staging/patchinstall.py DESTDIR="$PWD" --all ${lib.concatMapStringsSep " " (ps: "-W ${ps}") patch.disabledPatchsets} - for dir in $(ls ${./audio-revert}); do - rm -rf dlls/$dir - cp -r ${./audio-revert}/$dir dlls - chmod -R +w dlls/$dir - done - for patch in ${builtins.concatStringsSep " " patchList}; do - echo "Applying $patch" - patch -p1 < "$patch" - done - ''; -})) // { - meta = wineUnstable.meta // { - description = wineUnstable.meta.description + " (with osu-wine patches)"; - }; -} diff --git a/pkgs/osu-wine/packages.nix b/pkgs/osu-wine/packages.nix deleted file mode 100644 index fabc76c..0000000 --- a/pkgs/osu-wine/packages.nix +++ /dev/null @@ -1,57 +0,0 @@ -{ stdenv_32bit, lib, pkgs, pkgsi686Linux, pkgsCross, callPackage, substituteAll, moltenvk, path, - wineRelease ? "stable", - supportFlags -}: - -let - src = lib.getAttr wineRelease (callPackage ./sources.nix {}); -in with src; { - wine32 = pkgsi686Linux.callPackage "${path}/pkgs/applications/emulators/wine/base.nix" { - pname = "wine"; - inherit src version supportFlags patches moltenvk wineRelease; - pkgArches = [ pkgsi686Linux ]; - geckos = [ gecko32 ]; - mingwGccs = with pkgsCross; [ mingw32.buildPackages.gcc ]; - monos = [ mono ]; - platforms = [ "i686-linux" "x86_64-linux" ]; - }; - wine64 = callPackage "${path}/pkgs/applications/emulators/wine/base.nix" { - pname = "wine64"; - inherit src version supportFlags patches moltenvk wineRelease; - pkgArches = [ pkgs ]; - mingwGccs = with pkgsCross; [ mingwW64.buildPackages.gcc ]; - geckos = [ gecko64 ]; - monos = [ mono ]; - configureFlags = [ "--enable-win64" ]; - platforms = [ "x86_64-linux" "x86_64-darwin" ]; - mainProgram = "wine64"; - }; - wineWow = callPackage "${path}/pkgs/applications/emulators/wine/base.nix" { - pname = "wine-wow"; - inherit src version supportFlags patches moltenvk wineRelease; - stdenv = stdenv_32bit; - pkgArches = [ pkgs pkgsi686Linux ]; - geckos = [ gecko32 gecko64 ]; - mingwGccs = with pkgsCross; [ mingw32.buildPackages.gcc mingwW64.buildPackages.gcc ]; - monos = [ mono ]; - buildScript = substituteAll { - src = "${path}/pkgs/applications/emulators/wine/builder-wow.sh"; - # pkgconfig has trouble picking the right architecture - pkgconfig64remove = lib.makeSearchPathOutput "dev" "lib/pkgconfig" [ pkgs.glib pkgs.gst_all_1.gstreamer ]; - }; - platforms = [ "x86_64-linux" ]; - mainProgram = "wine64"; - }; - wineWow64 = callPackage "${path}/pkgs/applications/emulators/wine/base.nix" { - pname = "wine-wow64"; - inherit src version patches moltenvk wineRelease; - supportFlags = supportFlags // { mingwSupport = true; }; # Required because we request "--enable-archs=x86_64" - pkgArches = [ pkgs ]; - mingwGccs = with pkgsCross; [ mingw32.buildPackages.gcc mingwW64.buildPackages.gcc ]; - geckos = [ gecko64 ]; - monos = [ mono ]; - configureFlags = [ "--enable-archs=x86_64,i386" ]; - platforms = [ "x86_64-linux" "x86_64-darwin" ]; - mainProgram = "wine"; - }; -} diff --git a/pkgs/osu-wine/patches/0001-add-wine-unicode-again.patch b/pkgs/osu-wine/patches/0001-add-wine-unicode-again.patch deleted file mode 100644 index 9dcd675..0000000 --- a/pkgs/osu-wine/patches/0001-add-wine-unicode-again.patch +++ /dev/null @@ -1,207 +0,0 @@ ---- a/include/wine/test.h -+++ b/include/wine/test.h -@@ -28,6 +28,13 @@ - #include - #include - -+#ifdef __WINE_CONFIG_H -+#error config.h should not be used in Wine tests -+#endif -+#ifdef __WINE_WINE_UNICODE_H -+#error wine/unicode.h should not be used in Wine tests -+#endif -+ - #ifndef INVALID_FILE_ATTRIBUTES - #define INVALID_FILE_ATTRIBUTES (~0u) - #endif ---- /dev/null -+++ b/include/wine/unicode.h -@@ -0,0 +1,178 @@ -+/* -+ * Wine internal Unicode definitions -+ * -+ * Copyright 2000 Alexandre Julliard -+ * -+ * This library is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -+ */ -+ -+#if 0 -+#pragma makedep install -+#endif -+ -+#ifndef __WINE_WINE_UNICODE_H -+#define __WINE_WINE_UNICODE_H -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#ifdef __WINE_USE_MSVCRT -+#error This file should not be used with msvcrt headers -+#endif -+ -+#ifndef WINE_UNICODE_INLINE -+#define WINE_UNICODE_INLINE static FORCEINLINE -+#endif -+ -+WINE_UNICODE_INLINE WCHAR tolowerW( WCHAR ch ) -+{ -+ return RtlDowncaseUnicodeChar( ch ); -+} -+ -+WINE_UNICODE_INLINE WCHAR toupperW( WCHAR ch ) -+{ -+ return RtlUpcaseUnicodeChar( ch ); -+} -+ -+WINE_UNICODE_INLINE int isspaceW( WCHAR wc ) -+{ -+ unsigned short type; -+ GetStringTypeW( CT_CTYPE1, &wc, 1, &type ); -+ return type & C1_SPACE; -+} -+ -+WINE_UNICODE_INLINE unsigned int strlenW( const WCHAR *str ) -+{ -+ const WCHAR *s = str; -+ while (*s) s++; -+ return s - str; -+} -+ -+WINE_UNICODE_INLINE WCHAR *strcpyW( WCHAR *dst, const WCHAR *src ) -+{ -+ WCHAR *p = dst; -+ while ((*p++ = *src++)); -+ return dst; -+} -+ -+WINE_UNICODE_INLINE WCHAR *strcatW( WCHAR *dst, const WCHAR *src ) -+{ -+ strcpyW( dst + strlenW(dst), src ); -+ return dst; -+} -+ -+WINE_UNICODE_INLINE WCHAR *strrchrW( const WCHAR *str, WCHAR ch ) -+{ -+ WCHAR *ret = NULL; -+ do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++); -+ return ret; -+} -+ -+WINE_UNICODE_INLINE int strcmpiW( const WCHAR *str1, const WCHAR *str2 ) -+{ -+ for (;;) -+ { -+ int ret = tolowerW(*str1) - tolowerW(*str2); -+ if (ret || !*str1) return ret; -+ str1++; -+ str2++; -+ } -+} -+ -+WINE_UNICODE_INLINE int strncmpiW( const WCHAR *str1, const WCHAR *str2, int n ) -+{ -+ int ret = 0; -+ for ( ; n > 0; n--, str1++, str2++) -+ if ((ret = tolowerW(*str1) - tolowerW(*str2)) || !*str1) break; -+ return ret; -+} -+ -+WINE_UNICODE_INLINE LONG strtolW( LPCWSTR s, LPWSTR *end, INT base ) -+{ -+ BOOL negative = FALSE, empty = TRUE; -+ LONG ret = 0; -+ -+ if (base < 0 || base == 1 || base > 36) return 0; -+ if (end) *end = (WCHAR *)s; -+ while (isspaceW(*s)) s++; -+ -+ if (*s == '-') -+ { -+ negative = TRUE; -+ s++; -+ } -+ else if (*s == '+') s++; -+ -+ if ((base == 0 || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) -+ { -+ base = 16; -+ s += 2; -+ } -+ if (base == 0) base = s[0] != '0' ? 10 : 8; -+ -+ while (*s) -+ { -+ int v; -+ -+ if ('0' <= *s && *s <= '9') v = *s - '0'; -+ else if ('A' <= *s && *s <= 'Z') v = *s - 'A' + 10; -+ else if ('a' <= *s && *s <= 'z') v = *s - 'a' + 10; -+ else break; -+ if (v >= base) break; -+ if (negative) v = -v; -+ s++; -+ empty = FALSE; -+ -+ if (!negative && (ret > MAXLONG / base || ret * base > MAXLONG - v)) -+ ret = MAXLONG; -+ else if (negative && (ret < (LONG)MINLONG / base || ret * base < (LONG)(MINLONG - v))) -+ ret = MINLONG; -+ else -+ ret = ret * base + v; -+ } -+ -+ if (end && !empty) *end = (WCHAR *)s; -+ return ret; -+} -+ -+NTSYSAPI int __cdecl _vsnwprintf(WCHAR*,size_t,const WCHAR*,__ms_va_list); -+ -+static inline int WINAPIV snprintfW( WCHAR *str, size_t len, const WCHAR *format, ...) -+{ -+ int retval; -+ __ms_va_list valist; -+ __ms_va_start(valist, format); -+ retval = _vsnwprintf(str, len, format, valist); -+ __ms_va_end(valist); -+ return retval; -+} -+ -+static inline int WINAPIV sprintfW( WCHAR *str, const WCHAR *format, ...) -+{ -+ int retval; -+ __ms_va_list valist; -+ __ms_va_start(valist, format); -+ retval = _vsnwprintf(str, MAXLONG, format, valist); -+ __ms_va_end(valist); -+ return retval; -+} -+ -+#undef WINE_UNICODE_INLINE -+ -+#endif /* __WINE_WINE_UNICODE_H */ ---- a/include/Makefile.in -+++ b/include/Makefile.in -@@ -873,6 +873,7 @@ - wine/strmbase.h \ - wine/svcctl.idl \ - wine/test.h \ -+ wine/unicode.h \ - wine/unixlib.h \ - wine/vulkan.h \ - wine/vulkan_driver.h \ diff --git a/pkgs/osu-wine/patches/0001-libs-libjpeg-Set-default-DCT-algorithm-to-fastest.patch b/pkgs/osu-wine/patches/0001-libs-libjpeg-Set-default-DCT-algorithm-to-fastest.patch deleted file mode 100644 index 0bec693..0000000 --- a/pkgs/osu-wine/patches/0001-libs-libjpeg-Set-default-DCT-algorithm-to-fastest.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 1b5de04e1ae401f2f3d7179da0379191886cdfad Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Tue, 2 May 2023 01:36:12 +0200 -Subject: [PATCH] libs/libjpeg: Set default DCT algorithm to fastest. - ---- - libs/jpeg/jconfig.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/libs/jpeg/jconfig.h b/libs/jpeg/jconfig.h -index 2d05a3b09026..9f18c71751bd 100644 ---- a/libs/jpeg/jconfig.h -+++ b/libs/jpeg/jconfig.h -@@ -17,6 +17,7 @@ - /* #undef NEED_SHORT_EXTERNAL_NAMES */ - /* Define this if you get warnings about undefined structures. */ - /* #undef INCOMPLETE_TYPES_BROKEN */ -+#define JDCT_DEFAULT JDCT_FASTEST - - /* Define "boolean" as unsigned char, not enum, on Windows systems. */ - #ifdef _WIN32 --- -2.40.1 - diff --git a/pkgs/osu-wine/patches/0001-revert-staging-alt-tab.patch b/pkgs/osu-wine/patches/0001-revert-staging-alt-tab.patch deleted file mode 100644 index 9b430bc..0000000 --- a/pkgs/osu-wine/patches/0001-revert-staging-alt-tab.patch +++ /dev/null @@ -1,253 +0,0 @@ ---- b/dlls/winex11.drv/event.c -+++ a/dlls/winex11.drv/event.c -@@ -604,27 +604,16 @@ - */ - static void set_focus( Display *display, HWND hwnd, Time time ) - { -+ HWND focus; -- HWND focus, old_active; - Window win; - GUITHREADINFO threadinfo; - -- old_active = NtUserGetForegroundWindow(); -- - /* prevent recursion */ - x11drv_thread_data()->active_window = hwnd; - - TRACE( "setting foreground window to %p\n", hwnd ); - NtUserSetForegroundWindow( hwnd ); - -- /* Some applications expect that a being deactivated topmost window -- * receives the WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED messages, -- * and perform some specific actions. Chessmaster is one of such apps. -- * Window Manager keeps a topmost window on top in z-oder, so there is -- * no need to actually do anything, just send the messages. -- */ -- if (old_active && (NtUserGetWindowLongW( old_active, GWL_EXSTYLE ) & WS_EX_TOPMOST)) -- NtUserSetWindowPos( old_active, hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER ); -- - threadinfo.cbSize = sizeof(threadinfo); - NtUserGetGUIThreadInfo( 0, &threadinfo ); - focus = threadinfo.hwndFocus; ---- b/dlls/win32u/input.c -+++ a/dlls/win32u/input.c -@@ -1375,9 +1375,6 @@ - send_message( hwnd, WM_ACTIVATE, - MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ), - (LPARAM)previous ); -- -- send_message( hwnd, WM_NCPOINTERUP, 0, 0); -- - if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window()) - NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd ); - ---- b/dlls/win32u/input.c -+++ a/dlls/win32u/input.c -@@ -1633,10 +1633,6 @@ - (LPARAM)previous ); - if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window()) - NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd ); -- -- if (hwnd == NtUserGetForegroundWindow() && !is_iconic( hwnd )) -- NtUserSetActiveWindow( hwnd ); -- - } - - user_driver->pSetActiveWindow( hwnd ); ---- b/dlls/win32u/driver.c -+++ a/dlls/win32u/driver.c -@@ -838,10 +838,6 @@ - hdc, rect.left - dx, rect.top - dy, SRCCOPY, 0, 0 ); - } - --static void nulldrv_SetActiveWindow( HWND hwnd ) --{ --} -- - static void nulldrv_SetCapture( HWND hwnd, UINT flags ) - { - } -@@ -1245,7 +1241,6 @@ - nulldrv_ProcessEvents, - nulldrv_ReleaseDC, - nulldrv_ScrollDC, -- nulldrv_SetActiveWindow, - nulldrv_SetCapture, - loaderdrv_SetDesktopWindow, - nulldrv_SetFocus, -@@ -1325,7 +1320,6 @@ - SET_USER_FUNC(ProcessEvents); - SET_USER_FUNC(ReleaseDC); - SET_USER_FUNC(ScrollDC); -- SET_USER_FUNC(SetActiveWindow); - SET_USER_FUNC(SetCapture); - SET_USER_FUNC(SetDesktopWindow); - SET_USER_FUNC(SetFocus); ---- b/dlls/win32u/input.c -+++ a/dlls/win32u/input.c -@@ -1887,8 +1887,6 @@ - NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd ); - } - -- user_driver->pSetActiveWindow( hwnd ); -- - /* now change focus if necessary */ - if (focus) - { ---- b/dlls/winex11.drv/event.c -+++ a/dlls/winex11.drv/event.c -@@ -576,9 +576,6 @@ - Window win; - GUITHREADINFO threadinfo; - -- /* prevent recursion */ -- x11drv_thread_data()->active_window = hwnd; -- - TRACE( "setting foreground window to %p\n", hwnd ); - NtUserSetForegroundWindow( hwnd ); - -@@ -836,8 +833,6 @@ - - if (!focus_win) - { -- x11drv_thread_data()->active_window = 0; -- - /* Abey : 6-Oct-99. Check again if the focus out window is the - Foreground window, because in most cases the messages sent - above must have already changed the foreground window, in which ---- b/dlls/winex11.drv/init.c -+++ a/dlls/winex11.drv/init.c -@@ -421,7 +421,6 @@ - .pProcessEvents = X11DRV_ProcessEvents, - .pReleaseDC = X11DRV_ReleaseDC, - .pScrollDC = X11DRV_ScrollDC, -- .pSetActiveWindow = X11DRV_SetActiveWindow, - .pSetCapture = X11DRV_SetCapture, - .pSetDesktopWindow = X11DRV_SetDesktopWindow, - .pSetFocus = X11DRV_SetFocus, ---- b/dlls/winex11.drv/window.c -+++ a/dlls/winex11.drv/window.c -@@ -2431,54 +2431,6 @@ - } - - --/*********************************************************************** -- * SetActiveWindow (X11DRV.@) -- */ --void X11DRV_SetActiveWindow( HWND hwnd ) --{ -- struct x11drv_thread_data *thread_data = x11drv_init_thread_data(); -- struct x11drv_win_data *data; -- -- TRACE("%p\n", hwnd); -- -- if (thread_data->active_window == hwnd) -- { -- TRACE("ignoring activation for already active window %p\n", hwnd); -- return; -- } -- -- if (!(data = get_win_data( hwnd ))) return; -- -- if (data->mapped && data->managed && !data->iconic) -- { -- XEvent xev; -- struct x11drv_win_data *active = get_win_data( thread_data->active_window ); -- DWORD timestamp = NtUserGetThreadInfo()->message_time - EVENT_x11_time_to_win32_time( 0 ); -- -- TRACE("setting _NET_ACTIVE_WINDOW to %p/%lx, current active %p/%lx\n", -- data->hwnd, data->whole_window, active ? active->hwnd : NULL, active ? active->whole_window : 0 ); -- -- xev.xclient.type = ClientMessage; -- xev.xclient.window = data->whole_window; -- xev.xclient.message_type = x11drv_atom(_NET_ACTIVE_WINDOW); -- xev.xclient.serial = 0; -- xev.xclient.display = data->display; -- xev.xclient.send_event = True; -- xev.xclient.format = 32; -- -- xev.xclient.data.l[0] = 1; /* source: application */ -- xev.xclient.data.l[1] = timestamp; -- xev.xclient.data.l[2] = active ? active->whole_window : 0; -- xev.xclient.data.l[3] = 0; -- xev.xclient.data.l[4] = 0; -- XSendEvent( data->display, root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev ); -- -- if (active) release_win_data( active ); -- } -- -- release_win_data( data ); --} -- - /*********************************************************************** - * SetCapture (X11DRV.@) - */ ---- b/dlls/winex11.drv/x11drv.h -+++ a/dlls/winex11.drv/x11drv.h -@@ -231,7 +231,6 @@ - const RECT *top_rect, DWORD flags ); - extern void X11DRV_ReleaseDC( HWND hwnd, HDC hdc ); - extern BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update ); --extern void X11DRV_SetActiveWindow( HWND hwnd ); - extern void X11DRV_SetCapture( HWND hwnd, UINT flags ); - extern void X11DRV_SetDesktopWindow( HWND hwnd ); - extern void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, -@@ -383,7 +382,6 @@ - Display *display; - XEvent *current_event; /* event currently being processed */ - HWND grab_hwnd; /* window that currently grabs the mouse */ -- HWND active_window; /* active window */ - HWND last_focus; /* last window that had focus */ - XIM xim; /* input method */ - HWND last_xic_hwnd; /* last xic window */ -@@ -490,7 +488,6 @@ - XATOM__ICC_PROFILE, - XATOM__KDE_NET_WM_STATE_SKIP_SWITCHER, - XATOM__MOTIF_WM_HINTS, -- XATOM__NET_ACTIVE_WINDOW, - XATOM__NET_STARTUP_INFO_BEGIN, - XATOM__NET_STARTUP_INFO, - XATOM__NET_SUPPORTED, ---- b/dlls/winex11.drv/x11drv_main.c -+++ a/dlls/winex11.drv/x11drv_main.c -@@ -154,7 +154,6 @@ - "_ICC_PROFILE", - "_KDE_NET_WM_STATE_SKIP_SWITCHER", - "_MOTIF_WM_HINTS", -- "_NET_ACTIVE_WINDOW", - "_NET_STARTUP_INFO_BEGIN", - "_NET_STARTUP_INFO", - "_NET_SUPPORTED", ---- b/include/wine/gdi_driver.h -+++ a/include/wine/gdi_driver.h -@@ -316,7 +316,6 @@ - BOOL (*pProcessEvents)(DWORD); - void (*pReleaseDC)(HWND,HDC); - BOOL (*pScrollDC)(HDC,INT,INT,HRGN); -- void (*pSetActiveWindow)(HWND); - void (*pSetCapture)(HWND,UINT); - void (*pSetDesktopWindow)(HWND); - void (*pSetFocus)(HWND); ---- b/dlls/winex11.drv/window.c -+++ a/dlls/winex11.drv/window.c -@@ -278,6 +278,9 @@ - if (style & WS_MINIMIZEBOX) ret |= MWM_DECOR_MINIMIZE; - if (style & WS_MAXIMIZEBOX) ret |= MWM_DECOR_MAXIMIZE; - } -+ if (ex_style & WS_EX_DLGMODALFRAME) ret |= MWM_DECOR_BORDER; -+ else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER; -+ else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) ret |= MWM_DECOR_BORDER; - return ret; - } - ---- b/dlls/winex11.drv/window.c -+++ a/dlls/winex11.drv/window.c -@@ -279,7 +279,7 @@ - if (style & WS_MAXIMIZEBOX) ret |= MWM_DECOR_MAXIMIZE; - } - if (ex_style & WS_EX_DLGMODALFRAME) ret |= MWM_DECOR_BORDER; -+ else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH; -- else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER; - else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) ret |= MWM_DECOR_BORDER; - return ret; - } diff --git a/pkgs/osu-wine/patches/0001-server-Implement-thread-priorities-on-Linux.patch b/pkgs/osu-wine/patches/0001-server-Implement-thread-priorities-on-Linux.patch deleted file mode 100644 index c829ac2..0000000 --- a/pkgs/osu-wine/patches/0001-server-Implement-thread-priorities-on-Linux.patch +++ /dev/null @@ -1,292 +0,0 @@ -commit 6a033150c36bea6d704b7537c219e9b13b4387ec -Author: Rémi Bernon -Date: Tue Dec 1 22:49:26 2020 +0100 -Subject: [PATCH 1/3] server: Implement thread priorities on Linux. - -This does not report permission errors in order to avoid any breaking -change, only the parameter checks that were already there are returning -errors. - -Only call setpriority on Linux, as unix_tid is a Mach port on Mac OS. - ---- a/configure.ac -+++ b/configure.ac -@@ -2086,6 +2086,25 @@ - AC_DEFINE(HAVE_SCHED_SETAFFINITY, 1, [Define to 1 if you have the `sched_setaffinity' function.]) - fi - -+AC_CACHE_CHECK([for sched_setscheduler],wine_cv_have_sched_setscheduler, -+ AC_LINK_IFELSE([AC_LANG_PROGRAM( -+[[#define _GNU_SOURCE -+#include ]], [[sched_setscheduler(0, 0, 0);]])],[wine_cv_have_sched_setscheduler=yes],[wine_cv_have_sched_setscheduler=no])) -+if test "$wine_cv_have_sched_setscheduler" = "yes" -+then -+ AC_DEFINE(HAVE_SCHED_SETSCHEDULER, 1, [Define to 1 if you have the `sched_setscheduler' function.]) -+fi -+ -+AC_CACHE_CHECK([for setpriority],wine_cv_have_setpriority, -+ AC_LINK_IFELSE([AC_LANG_PROGRAM( -+[[#define _GNU_SOURCE -+#include -+#include ]], [[setpriority(0, 0, 0);]])],[wine_cv_have_setpriority=yes],[wine_cv_have_setpriority=no])) -+if test "$wine_cv_have_setpriority" = "yes" -+then -+ AC_DEFINE(HAVE_SETPRIORITY, 1, [Define to 1 if you have the `setpriority' function.]) -+fi -+ - dnl **** Check for types **** - - AC_C_INLINE ---- a/server/process.c -+++ b/server/process.c -@@ -1638,6 +1638,24 @@ - release_object( process ); - } - -+static void set_process_priority( struct process *process, int priority ) -+{ -+ struct thread *thread; -+ -+ if (!process->running_threads) -+ { -+ set_error( STATUS_PROCESS_IS_TERMINATING ); -+ return; -+ } -+ -+ LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) -+ { -+ set_thread_priority( thread, priority, thread->priority ); -+ } -+ -+ process->priority = priority; -+} -+ - static void set_process_affinity( struct process *process, affinity_t affinity ) - { - struct thread *thread; -@@ -1663,7 +1681,7 @@ - - if ((process = get_process_from_handle( req->handle, PROCESS_SET_INFORMATION ))) - { -- if (req->mask & SET_PROCESS_INFO_PRIORITY) process->priority = req->priority; -+ if (req->mask & SET_PROCESS_INFO_PRIORITY) set_process_priority( process, req->priority ); - if (req->mask & SET_PROCESS_INFO_AFFINITY) set_process_affinity( process, req->affinity ); - release_object( process ); - } ---- a/server/thread.c -+++ b/server/thread.c -@@ -37,6 +37,12 @@ - #define _WITH_CPU_SET_T - #include - #endif -+#ifdef HAVE_SYS_TIME_H -+#include -+#endif -+#ifdef HAVE_SYS_RESOURCE_H -+#include -+#endif - - #include "ntstatus.h" - #define WIN32_NO_STATUS -@@ -253,6 +259,7 @@ - thread->state = RUNNING; - thread->exit_code = 0; - thread->priority = 0; -+ thread->priority_applied = 0; - thread->suspend = 0; - thread->dbg_hidden = 0; - thread->desktop_users = 0; -@@ -648,31 +655,151 @@ - return mask; - } - -+#if defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SETPRIORITY) -+static int get_unix_priority( int priority_class, int priority ) -+{ -+ switch (priority_class) { -+ case PROCESS_PRIOCLASS_IDLE: -+ switch (priority) { -+ case THREAD_PRIORITY_IDLE: return 15; -+ case THREAD_PRIORITY_LOWEST: return 10; -+ case THREAD_PRIORITY_BELOW_NORMAL: return 8; -+ case THREAD_PRIORITY_NORMAL: return 6; -+ case THREAD_PRIORITY_ABOVE_NORMAL: return 4; -+ case THREAD_PRIORITY_HIGHEST: return 2; -+ case THREAD_PRIORITY_TIME_CRITICAL: return -15; -+ } -+ case PROCESS_PRIOCLASS_BELOW_NORMAL: -+ switch (priority) { -+ case THREAD_PRIORITY_IDLE: return 15; -+ case THREAD_PRIORITY_LOWEST: return 8; -+ case THREAD_PRIORITY_BELOW_NORMAL: return 6; -+ case THREAD_PRIORITY_NORMAL: return 4; -+ case THREAD_PRIORITY_ABOVE_NORMAL: return 2; -+ case THREAD_PRIORITY_HIGHEST: return 0; -+ case THREAD_PRIORITY_TIME_CRITICAL: return -15; -+ } -+ case PROCESS_PRIOCLASS_NORMAL: -+ switch (priority) { -+ case THREAD_PRIORITY_IDLE: return 15; -+ case THREAD_PRIORITY_LOWEST: return 4; -+ case THREAD_PRIORITY_BELOW_NORMAL: return 2; -+ case THREAD_PRIORITY_NORMAL: return 0; -+ case THREAD_PRIORITY_ABOVE_NORMAL: return -2; -+ case THREAD_PRIORITY_HIGHEST: return -4; -+ case THREAD_PRIORITY_TIME_CRITICAL: return -15; -+ } -+ case PROCESS_PRIOCLASS_ABOVE_NORMAL: -+ switch (priority) { -+ case THREAD_PRIORITY_IDLE: return 15; -+ case THREAD_PRIORITY_LOWEST: return 0; -+ case THREAD_PRIORITY_BELOW_NORMAL: return -2; -+ case THREAD_PRIORITY_NORMAL: return -4; -+ case THREAD_PRIORITY_ABOVE_NORMAL: return -6; -+ case THREAD_PRIORITY_HIGHEST: return -8; -+ case THREAD_PRIORITY_TIME_CRITICAL: return -15; -+ } -+ case PROCESS_PRIOCLASS_HIGH: -+ switch (priority) { -+ case THREAD_PRIORITY_IDLE: return 15; -+ case THREAD_PRIORITY_LOWEST: return -2; -+ case THREAD_PRIORITY_BELOW_NORMAL: return -4; -+ case THREAD_PRIORITY_NORMAL: return -6; -+ case THREAD_PRIORITY_ABOVE_NORMAL: return -8; -+ case THREAD_PRIORITY_HIGHEST: return -10; -+ case THREAD_PRIORITY_TIME_CRITICAL: return -15; -+ } -+ case PROCESS_PRIOCLASS_REALTIME: -+ switch (priority) { -+ case THREAD_PRIORITY_IDLE: return 1; -+ case -7: -+ case -6: -+ case -5: -+ case -4: -+ case -3: -+ case THREAD_PRIORITY_LOWEST: -+ case THREAD_PRIORITY_BELOW_NORMAL: -+ case THREAD_PRIORITY_NORMAL: -+ case THREAD_PRIORITY_ABOVE_NORMAL: -+ case THREAD_PRIORITY_HIGHEST: -+ case 3: -+ case 4: -+ case 5: -+ case 6: -+ return priority + 9; -+ case THREAD_PRIORITY_TIME_CRITICAL: -+ return 16; -+ } -+ } -+ return 0; -+} -+#endif -+ - #define THREAD_PRIORITY_REALTIME_HIGHEST 6 - #define THREAD_PRIORITY_REALTIME_LOWEST -7 - -+int set_thread_priority( struct thread* thread, int priority_class, int priority ) -+{ -+ int max = THREAD_PRIORITY_HIGHEST; -+ int min = THREAD_PRIORITY_LOWEST; -+ if (priority_class == PROCESS_PRIOCLASS_REALTIME) -+ { -+ max = THREAD_PRIORITY_REALTIME_HIGHEST; -+ min = THREAD_PRIORITY_REALTIME_LOWEST; -+ } -+ -+ if ((priority < min || priority > max) && -+ priority != THREAD_PRIORITY_IDLE && -+ priority != THREAD_PRIORITY_TIME_CRITICAL) -+ { -+ errno = EINVAL; -+ return -1; -+ } -+ -+ if (thread->process->priority == priority_class && -+ thread->priority == priority && -+ thread->priority_applied) -+ return 0; -+ -+ thread->priority = priority; -+ thread->priority_applied = 0; -+ if (thread->unix_tid == -1) -+ return 0; -+ -+#ifdef __linux__ -+ if (priority_class == PROCESS_PRIOCLASS_REALTIME) -+ { -+#ifdef HAVE_SCHED_SETSCHEDULER -+ struct sched_param param; -+ if (sched_getparam( thread->unix_tid, ¶m ) != 0) -+ return 0; /* ignore errors for now */ -+ -+ param.sched_priority = get_unix_priority( priority_class, priority ); -+ if (sched_setscheduler( thread->unix_tid, SCHED_RR|SCHED_RESET_ON_FORK, ¶m ) == 0) -+ return 0; -+#endif -+ } -+ else -+ { -+#ifdef HAVE_SETPRIORITY -+ if (setpriority( PRIO_PROCESS, thread->unix_tid, -+ get_unix_priority( priority_class, priority ) ) == 0) -+ return 0; -+#endif -+ } -+#endif -+ -+ return 0; /* ignore errors for now */ -+} -+ - /* set all information about a thread */ - static void set_thread_info( struct thread *thread, - const struct set_thread_info_request *req ) - { - if (req->mask & SET_THREAD_INFO_PRIORITY) - { -- int max = THREAD_PRIORITY_HIGHEST; -- int min = THREAD_PRIORITY_LOWEST; -- if (thread->process->priority == PROCESS_PRIOCLASS_REALTIME) -- { -- max = THREAD_PRIORITY_REALTIME_HIGHEST; -- min = THREAD_PRIORITY_REALTIME_LOWEST; -- } -- if ((req->priority >= min && req->priority <= max) || -- req->priority == THREAD_PRIORITY_IDLE || -- req->priority == THREAD_PRIORITY_TIME_CRITICAL) -- { -- thread->priority = req->priority; -- set_scheduler_priority( thread ); -- } -- else -- set_error( STATUS_INVALID_PARAMETER ); -+ if (set_thread_priority( thread, thread->process->priority, req->priority )) -+ file_set_error(); - } - if (req->mask & SET_THREAD_INFO_AFFINITY) - { -@@ -1541,6 +1668,7 @@ - - init_thread_context( current ); - generate_debug_event( current, DbgCreateThreadStateChange, &req->entry ); -+ set_thread_priority( current, current->process->priority, current->priority ); - set_thread_affinity( current, current->affinity ); - - reply->suspend = (current->suspend || current->process->suspend || current->context != NULL); ---- a/server/thread.h -+++ b/server/thread.h -@@ -84,6 +84,7 @@ - client_ptr_t entry_point; /* entry point (in client address space) */ - affinity_t affinity; /* affinity mask */ - int priority; /* priority level */ -+ int priority_applied; /* priority level successfully applied status */ - int suspend; /* suspend count */ - int dbg_hidden; /* hidden from debugger */ - obj_handle_t desktop; /* desktop handle */ -@@ -124,6 +125,7 @@ - extern int thread_add_inflight_fd( struct thread *thread, int client, int server ); - extern int thread_get_inflight_fd( struct thread *thread, int client ); - extern struct token *thread_get_impersonation_token( struct thread *thread ); -+extern int set_thread_priority( struct thread *thread, int priority_class, int priority ); - extern int set_thread_affinity( struct thread *thread, affinity_t affinity ); - extern int suspend_thread( struct thread *thread ); - extern int resume_thread( struct thread *thread ); diff --git a/pkgs/osu-wine/patches/0002-midi-fixed-revert.patch b/pkgs/osu-wine/patches/0002-midi-fixed-revert.patch deleted file mode 100644 index b4d51ff..0000000 --- a/pkgs/osu-wine/patches/0002-midi-fixed-revert.patch +++ /dev/null @@ -1,17 +0,0 @@ ---- b/include/mmddk.h -+++ a/include/mmddk.h -@@ -30,6 +30,14 @@ - extern "C" { - #endif - -+#define MAX_MIDIINDRV (16) -+/* For now I'm making 16 the maximum number of midi devices one can -+ * have. This should be more than enough for everybody. But as a purist, -+ * I intend to make it unbounded in the future, as soon as I figure -+ * a good way to do so. -+ */ -+#define MAX_MIDIOUTDRV (16) -+ - /* ================================== - * Multimedia DDK compatible part - * ================================== */ diff --git a/pkgs/osu-wine/patches/0002-revert-mscvrt-ify-modules.patch b/pkgs/osu-wine/patches/0002-revert-mscvrt-ify-modules.patch deleted file mode 100644 index 8294c7c..0000000 --- a/pkgs/osu-wine/patches/0002-revert-mscvrt-ify-modules.patch +++ /dev/null @@ -1,198 +0,0 @@ ---- a/tools/makedep.c -+++ b/tools/makedep.c -@@ -199,6 +199,7 @@ - const char *staticlib; - const char *importlib; - const char *unixlib; -+ int use_msvcrt; - int data_only; - int is_win16; - int is_exe; -@@ -602,17 +603,6 @@ - - - /******************************************************************* -- * is_using_msvcrt -- * -- * Check if the files of a makefile use msvcrt by default. -- */ --static int is_using_msvcrt( struct makefile *make ) --{ -- return make->module || make->testdll; --} -- -- --/******************************************************************* - * arch_module_name - */ - static char *arch_module_name( const char *module, unsigned int arch ) -@@ -870,7 +860,7 @@ - file->basename = xstrdup( filename ? filename : name ); - file->filename = obj_dir_path( make, file->basename ); - file->file->flags = FLAG_GENERATED; -- file->use_msvcrt = is_using_msvcrt( make ); -+ file->use_msvcrt = make->use_msvcrt; - list_add_tail( &make->sources, &file->entry ); - if (make == include_makefile) - { -@@ -1620,7 +1610,7 @@ - - memset( file, 0, sizeof(*file) ); - file->name = xstrdup(name); -- file->use_msvcrt = is_using_msvcrt( make ); -+ file->use_msvcrt = make->use_msvcrt; - file->is_external = !!make->extlib; - list_add_tail( &make->sources, &file->entry ); - if (make == include_makefile) -@@ -1818,12 +1808,13 @@ - unsigned int i, arch; - struct incl_file *source, *next, *file, *dlldata = NULL; - struct strarray objs = get_expanded_make_var_array( make, "EXTRA_OBJS" ); -+ int multiarch = archs.count > 1 && make->use_msvcrt; - - LIST_FOR_EACH_ENTRY_SAFE( source, next, &make->sources, struct incl_file, entry ) - { - for (arch = 0; arch < archs.count; arch++) - { -- if (!is_multiarch( arch )) continue; -+ if (!arch != !multiarch) continue; - if (source->file->flags & FLAG_IDL_CLIENT) - { - file = add_generated_source( make, replace_extension( source->name, ".idl", "_c.c" ), NULL, arch ); -@@ -1942,7 +1933,7 @@ - { - for (arch = 0; arch < archs.count; arch++) - { -- if (!is_multiarch( arch )) continue; -+ if (!arch != !multiarch) continue; - file = add_generated_source( make, "testlist.o", "testlist.c", arch ); - add_dependency( file->file, "wine/test.h", INCL_NORMAL ); - add_all_includes( make, file, file->file ); -@@ -2196,6 +2187,7 @@ - */ - static const char *get_default_crt( const struct makefile *make ) - { -+ if (!make->use_msvcrt) return NULL; - if (make->module && is_crt_module( make->module )) return NULL; /* don't add crt import to crt dlls */ - return !make->testdll && (!make->staticlib || make->extlib) ? "ucrtbase" : "msvcrt"; - } -@@ -2352,7 +2344,6 @@ - strarray_add( &ret, strmake( "-I%s", root_src_dir_path( "include/msvcrt" ))); - for (i = 0; i < make->include_paths.count; i++) - strarray_add( &ret, strmake( "-I%s", make->include_paths.str[i] )); -- strarray_add( &ret, get_crt_define( make )); - } - strarray_addall( &ret, make->define_args ); - strarray_addall( &ret, get_expanded_file_local_var( make, obj, "EXTRADEFS" )); -@@ -2412,9 +2403,7 @@ - output_filename( tools_path( make, "winebuild" )); - } - output_filenames( target_flags[arch] ); -- if (arch) return; -- output_filename( "-mno-cygwin" ); -- output_filenames( lddll_flags ); -+ if (!arch) output_filenames( lddll_flags ); - } - - -@@ -2816,6 +2805,7 @@ - struct strarray multiarch_targets[MAX_ARCHS] = { empty_strarray }; - const char *dest; - unsigned int i, arch; -+ int multiarch; - - if (find_include_file( make, strmake( "%s.h", obj ))) source->file->flags |= FLAG_IDL_HEADER; - if (!source->file->flags) return; -@@ -2839,9 +2829,10 @@ - for (i = 0; i < ARRAY_SIZE(idl_outputs); i++) - { - if (!(source->file->flags & idl_outputs[i].flag)) continue; -+ multiarch = (make->use_msvcrt && archs.count > 1); - for (arch = 0; arch < archs.count; arch++) - { -- if (!is_multiarch( arch )) continue; -+ if (!arch != !multiarch) continue; - if (make->disabled[arch]) continue; - dest = strmake( "%s%s%s", arch_dirs[arch], obj, idl_outputs[i].ext ); - if (!find_src_file( make, dest )) strarray_add( &make->clean_files, dest ); -@@ -3152,13 +3143,13 @@ - if (arch) - { - if (source->file->flags & FLAG_C_UNIX) return; -- if (!is_using_msvcrt( make ) && !make->staticlib && !(source->file->flags & FLAG_C_IMPLIB)) return; -+ if (!make->use_msvcrt && !make->staticlib && !(source->file->flags & FLAG_C_IMPLIB)) return; - } - else if (source->file->flags & FLAG_C_UNIX) - { - if (!unix_lib_supported) return; - } -- else if (archs.count > 1 && is_using_msvcrt( make )) -+ else if (archs.count > 1 && make->use_msvcrt) - { - if (!so_dll_supported) return; - if (!(source->file->flags & FLAG_C_IMPLIB) && (!make->staticlib || make->extlib)) return; -@@ -3349,6 +3340,12 @@ - strarray_addall( &all_libs, add_import_libs( make, &dep_libs, default_imports, IMPORT_TYPE_DEFAULT, arch ) ); - if (!arch) strarray_addall( &all_libs, libs ); - -+ if (!make->use_msvcrt) -+ { -+ strarray_addall( &all_libs, get_expanded_make_var_array( make, "UNIX_LIBS" )); -+ strarray_addall( &all_libs, libs ); -+ } -+ - if (delay_load_flags[arch]) - { - for (i = 0; i < make->delayimports.count; i++) -@@ -3541,7 +3538,7 @@ - output( ": %s", obj_dir_path( make, testmodule )); - if (parent) - { -- char *parent_module = arch_module_name( make->testdll, arch ); -+ char *parent_module = arch_module_name( make->testdll, parent->use_msvcrt ? arch : 0 ); - output_filename( obj_dir_path( parent, parent_module )); - if (parent->unixlib) output_filename( obj_dir_path( parent, parent->unixlib )); - } -@@ -3792,11 +3789,15 @@ - } - else if (make->module) - { -- for (arch = 0; arch < archs.count; arch++) -+ if (!make->use_msvcrt) output_module( make, 0 ); -+ else - { -- if (is_multiarch( arch )) output_module( make, arch ); -- if (make->importlib && (is_multiarch( arch ) || !is_native_arch_disabled( make ))) -- output_import_lib( make, arch ); -+ for (arch = 0; arch < archs.count; arch++) -+ { -+ if (is_multiarch( arch )) output_module( make, arch ); -+ if (make->importlib && (is_multiarch( arch ) || !is_native_arch_disabled( make ))) -+ output_import_lib( make, arch ); -+ } - } - if (make->unixlib) output_unix_lib( make ); - if (make->is_exe && !make->is_win16 && unix_lib_supported && strendswith( make->module, ".exe" )) -@@ -4236,9 +4237,13 @@ - } - make->is_win16 = strarray_exists( &make->extradllflags, "-m16" ); - make->data_only = strarray_exists( &make->extradllflags, "-Wb,--data-only" ); -+ make->use_msvcrt = (make->module || make->testdll || make->is_win16) && -+ !strarray_exists( &make->extradllflags, "-mcygwin" ); - make->is_exe = strarray_exists( &make->extradllflags, "-mconsole" ) || - strarray_exists( &make->extradllflags, "-mwindows" ); - -+ if (make->use_msvcrt) strarray_add_uniq( &make->extradllflags, "-mno-cygwin" ); -+ - if (make->module) - { - /* add default install rules if nothing was specified */ -@@ -4296,6 +4301,8 @@ - - add_generated_sources( make ); - -+ if (make->use_msvcrt) strarray_add( &make->define_args, get_crt_define( make )); -+ - LIST_FOR_EACH_ENTRY( file, &make->includes, struct incl_file, entry ) parse_file( make, file, 0 ); - LIST_FOR_EACH_ENTRY( file, &make->sources, struct incl_file, entry ) get_dependencies( file, file ); - diff --git a/pkgs/osu-wine/patches/0002-server-Fallback-to-RTKIT-for-thread-priorities.patch b/pkgs/osu-wine/patches/0002-server-Fallback-to-RTKIT-for-thread-priorities.patch deleted file mode 100644 index d62a4ff..0000000 --- a/pkgs/osu-wine/patches/0002-server-Fallback-to-RTKIT-for-thread-priorities.patch +++ /dev/null @@ -1,145 +0,0 @@ -commit ebf411c1e5f20c6db7962cea587d6169246078e0 -Author: Rémi Bernon -Date: Wed Jul 3 10:54:06 2019 +0200 -Subject: [PATCH 2/3] server: Fallback to RTKIT for thread priorities. - -sched_setscheduler and setpriority usually require elevated privileges -to succeed and most Linux distributions ship rtkit daemon with a dbus -interface to enable unprivileged control of some scheduling parameters. - ---- a/configure.ac -+++ b/configure.ac -@@ -1416,7 +1416,7 @@ - if test "x$with_dbus" != "xno" - then - WINE_PACKAGE_FLAGS(DBUS,[dbus-1],,,, -- [AC_CHECK_HEADER([dbus/dbus.h], -+ [AC_CHECK_HEADERS([dbus/dbus.h], - [WINE_CHECK_SONAME(dbus-1, dbus_connection_close,,[DBUS_CFLAGS=""],[$DBUS_LIBS])], - [DBUS_CFLAGS=""])]) - fi ---- a/server/Makefile.in -+++ b/server/Makefile.in -@@ -50,6 +50,7 @@ - wineserver.man.in \ - winstation.c - --UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) -+UNIX_CFLAGS = $(DBUS_CFLAGS) -+UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) $(DBUS_LIBS) - - unicode_EXTRADEFS = -DNLSDIR="\"${nlsdir}\"" -DBIN_TO_NLSDIR=\"`${MAKEDEP} -R ${bindir} ${nlsdir}`\" ---- a/server/thread.c -+++ b/server/thread.c -@@ -59,6 +59,77 @@ - #include "esync.h" - #include "fsync.h" - -+#ifdef HAVE_DBUS_DBUS_H -+#include -+ -+static int rtkit_set_realtime( dbus_uint64_t process, dbus_uint64_t thread, dbus_uint32_t priority ) -+{ -+ DBusConnection* dbus; -+ DBusMessage *msg; -+ int ret = -1; -+ -+ if ((dbus = dbus_bus_get(DBUS_BUS_SYSTEM, NULL))) -+ { -+ dbus_connection_set_exit_on_disconnect(dbus, 0); -+ -+ if ((msg = dbus_message_new_method_call("org.freedesktop.RealtimeKit1", -+ "/org/freedesktop/RealtimeKit1", -+ "org.freedesktop.RealtimeKit1", -+ "MakeThreadRealtimeWithPID"))) -+ { -+ dbus_message_set_no_reply(msg, 1); -+ -+ if (dbus_message_append_args(msg, -+ DBUS_TYPE_UINT64, &process, -+ DBUS_TYPE_UINT64, &thread, -+ DBUS_TYPE_UINT32, &priority, -+ DBUS_TYPE_INVALID) && -+ dbus_connection_send(dbus, msg, NULL)) -+ ret = 0; -+ -+ dbus_message_unref(msg); -+ } -+ -+ dbus_connection_unref(dbus); -+ } -+ -+ return ret; -+} -+ -+static int rtkit_set_niceness( dbus_uint64_t process, dbus_uint64_t thread, dbus_int32_t niceness ) -+{ -+ DBusConnection* dbus; -+ DBusMessage *msg; -+ int ret = -1; -+ -+ if ((dbus = dbus_bus_get(DBUS_BUS_SYSTEM, NULL))) -+ { -+ dbus_connection_set_exit_on_disconnect(dbus, 0); -+ -+ if ((msg = dbus_message_new_method_call("org.freedesktop.RealtimeKit1", -+ "/org/freedesktop/RealtimeKit1", -+ "org.freedesktop.RealtimeKit1", -+ "MakeThreadHighPriorityWithPID"))) -+ { -+ dbus_message_set_no_reply(msg, 1); -+ -+ if (dbus_message_append_args(msg, -+ DBUS_TYPE_UINT64, &process, -+ DBUS_TYPE_UINT64, &thread, -+ DBUS_TYPE_INT32, &niceness, -+ DBUS_TYPE_INVALID) && -+ dbus_connection_send(dbus, msg, NULL)) -+ ret = 0; -+ -+ dbus_message_unref(msg); -+ } -+ -+ dbus_connection_unref(dbus); -+ } -+ -+ return ret; -+} -+#endif - - /* thread queues */ - -@@ -655,7 +726,8 @@ - return mask; - } - --#if defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SETPRIORITY) -+#if defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SETPRIORITY) || \ -+ defined(HAVE_DBUS_DBUS_H) - static int get_unix_priority( int priority_class, int priority ) - { - switch (priority_class) { -@@ -778,6 +850,11 @@ - if (sched_setscheduler( thread->unix_tid, SCHED_RR|SCHED_RESET_ON_FORK, ¶m ) == 0) - return 0; - #endif -+#ifdef HAVE_DBUS_DBUS_H -+ if (rtkit_set_realtime( thread->unix_pid, thread->unix_tid, -+ get_unix_priority( priority_class, priority ) ) == 0) -+ return 0; -+#endif - } - else - { -@@ -786,6 +863,11 @@ - get_unix_priority( priority_class, priority ) ) == 0) - return 0; - #endif -+#ifdef HAVE_DBUS_DBUS_H -+ if (rtkit_set_niceness( thread->unix_pid, thread->unix_tid, -+ get_unix_priority( priority_class, priority ) ) == 0) -+ return 0; -+#endif - } - #endif - diff --git a/pkgs/osu-wine/patches/0003-server-Map-THREAD_PRIORITY_IDLE-to-SCHED_IDLE.patch b/pkgs/osu-wine/patches/0003-server-Map-THREAD_PRIORITY_IDLE-to-SCHED_IDLE.patch deleted file mode 100644 index 28fd788..0000000 --- a/pkgs/osu-wine/patches/0003-server-Map-THREAD_PRIORITY_IDLE-to-SCHED_IDLE.patch +++ /dev/null @@ -1,30 +0,0 @@ -From df72c4d301123c0ea0c33af4bc9d00c47255a664 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Thu, 26 Jan 2023 22:13:55 +0100 -Subject: [PATCH 3/3] server: Map THREAD_PRIORITY_IDLE to SCHED_IDLE. - ---- - server/thread.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - ---- a/server/thread.c -+++ b/server/thread.c -@@ -858,6 +858,18 @@ - } - else - { -+#ifdef HAVE_SCHED_SETSCHEDULER -+ if (priority == THREAD_PRIORITY_IDLE) -+ { -+ struct sched_param param; -+ if (sched_getparam( thread->unix_tid, ¶m ) == 0) -+ { -+ param.sched_priority = 0; -+ if (sched_setscheduler( thread->unix_tid, SCHED_IDLE|SCHED_RESET_ON_FORK, ¶m ) == 0) -+ return 0; -+ } -+ } -+#endif - #ifdef HAVE_SETPRIORITY - if (setpriority( PRIO_PROCESS, thread->unix_tid, - get_unix_priority( priority_class, priority ) ) == 0) diff --git a/pkgs/osu-wine/patches/0003-thread-characteristic-audio-priority-from-oglf-patchset.patch b/pkgs/osu-wine/patches/0003-thread-characteristic-audio-priority-from-oglf-patchset.patch deleted file mode 100644 index cf57848..0000000 --- a/pkgs/osu-wine/patches/0003-thread-characteristic-audio-priority-from-oglf-patchset.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/dlls/avrt/main.c -+++ b/dlls/avrt/main.c -@@ -70,6 +70,9 @@ - return NULL; - } - -+ if (!wcscmp(name, L"Audio") || !wcscmp(name, L"Pro Audio")) -+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); -+ - return (HANDLE)0x12345678; - } - diff --git a/pkgs/osu-wine/patches/9989-misc-ps0126-devenum-Register-IEEE-float-for-Direct-Sound-defau.patch b/pkgs/osu-wine/patches/9989-misc-ps0126-devenum-Register-IEEE-float-for-Direct-Sound-defau.patch deleted file mode 100644 index 792ae47..0000000 --- a/pkgs/osu-wine/patches/9989-misc-ps0126-devenum-Register-IEEE-float-for-Direct-Sound-defau.patch +++ /dev/null @@ -1,36 +0,0 @@ -commit d444330ed7685686f46db7fb8ed1ad0cbec72c7b -Author: Rémi Bernon -Date: Wed Jun 16 17:36:15 2021 +0200 -Subject: [PATCH] devenum: Register IEEE float for Direct Sound default device. - --- -diff --git a/dlls/devenum/createdevenum.c b/dlls/devenum/createdevenum.c -index 8e9cf56eb09..97855b12b81 100644 ---- a/dlls/devenum/createdevenum.c -+++ b/dlls/devenum/createdevenum.c -@@ -481,7 +481,7 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons - static const WCHAR defaultW[] = L"Default DirectSound Device"; - IPropertyBag *prop_bag = NULL; - REGFILTERPINS2 rgpins = {0}; -- REGPINTYPES rgtypes = {0}; -+ REGPINTYPES rgtypes[2] = {}; - REGFILTER2 rgf = {0}; - WCHAR clsid[CHARS_IN_GUID]; - VARIANT var; -@@ -512,10 +512,12 @@ static BOOL CALLBACK register_dsound_devices(GUID *guid, const WCHAR *desc, cons - rgf.rgPins2 = &rgpins; - rgpins.dwFlags = REG_PINFLAG_B_RENDERER; - /* FIXME: native registers many more formats */ -- rgpins.nMediaTypes = 1; -- rgpins.lpMediaType = &rgtypes; -- rgtypes.clsMajorType = &MEDIATYPE_Audio; -- rgtypes.clsMinorType = &MEDIASUBTYPE_PCM; -+ rgpins.nMediaTypes = 2; -+ rgpins.lpMediaType = rgtypes; -+ rgtypes[0].clsMajorType = &MEDIATYPE_Audio; -+ rgtypes[0].clsMinorType = &MEDIASUBTYPE_PCM; -+ rgtypes[1].clsMajorType = &MEDIATYPE_Audio; -+ rgtypes[1].clsMinorType = &MEDIASUBTYPE_IEEE_FLOAT; - - write_filter_data(prop_bag, &rgf); - diff --git a/pkgs/osu-wine/patches/9989-misc-ps0171-server-Don-t-wait-for-low-level-hook-result-when-q.patch b/pkgs/osu-wine/patches/9989-misc-ps0171-server-Don-t-wait-for-low-level-hook-result-when-q.patch deleted file mode 100644 index bb8b614..0000000 --- a/pkgs/osu-wine/patches/9989-misc-ps0171-server-Don-t-wait-for-low-level-hook-result-when-q.patch +++ /dev/null @@ -1,60 +0,0 @@ -From: Piotr Caban -Subject: [PATCH v2] server: Don't wait for low level hook result when queuing hardware message. -Message-Id: -Date: Tue, 21 Sep 2021 15:51:35 +0200 - - -Without the change graphic drivers are blocking until low level hooks -are processed when injecting keyboard and mouse events. Causes 2-seconds -(timeout) freeze in GtaV. - -Signed-off-by: Piotr Caban ---- -v2: - - don't specify sender in send_hook_ll_message to avoid queuing result - - server/queue.c | 16 +++++++++++++--- - 1 file changed, 13 insertions(+), 3 deletions(-) - -diff --git a/server/queue.c b/server/queue.c -index e4903bcb79f..5c19348eeba 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -1839,7 +1839,12 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons - /* specify a sender only when sending the last message */ - if (!(flags & ((1 << ARRAY_SIZE( messages )) - 1))) - { -- if (!(wait = send_hook_ll_message( desktop, msg, input, sender ))) -+ if (origin == IMO_HARDWARE) -+ { -+ if (!send_hook_ll_message( desktop, msg, input, NULL )) -+ queue_hardware_message( desktop, msg, 0 ); -+ } -+ else if (!(wait = send_hook_ll_message( desktop, msg, input, sender ))) - queue_hardware_message( desktop, msg, 0 ); - } - else if (!send_hook_ll_message( desktop, msg, input, NULL )) -@@ -1860,7 +1865,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c - struct thread *foreground; - unsigned char vkey = input->kbd.vkey; - unsigned int message_code, time; -- int wait; -+ int wait = 0; - - if (!(time = input->kbd.time)) time = get_tick_count(); - -@@ -1981,7 +1986,12 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c - msg_data->flags |= (flags & (KF_EXTENDED | KF_ALTDOWN | KF_UP)) >> 8; - } - -- if (!(wait = send_hook_ll_message( desktop, msg, input, sender ))) -+ if (origin == IMO_HARDWARE) -+ { -+ if (!send_hook_ll_message( desktop, msg, input, NULL )) -+ queue_hardware_message( desktop, msg, 1 ); -+ } -+ else if (!(wait = send_hook_ll_message( desktop, msg, input, sender ))) - queue_hardware_message( desktop, msg, 1 ); - - return wait; - diff --git a/pkgs/osu-wine/patches/9999-diffs-8bpp-copy-support.patch b/pkgs/osu-wine/patches/9999-diffs-8bpp-copy-support.patch deleted file mode 100644 index 0c67346..0000000 --- a/pkgs/osu-wine/patches/9999-diffs-8bpp-copy-support.patch +++ /dev/null @@ -1,55 +0,0 @@ -diff --git a/dlls/windowscodecs/converter.c b/dlls/windowscodecs/converter.c -index 11111111111..11111111111 100644 ---- a/dlls/windowscodecs/converter.c -+++ b/dlls/windowscodecs/converter.c -@@ -1034,6 +1034,50 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec - - switch (source_format) - { -+ case format_8bppGray: -+ if (prc) -+ { -+ HRESULT res; -+ INT x, y; -+ BYTE *srcdata; -+ UINT srcstride, srcdatasize; -+ const BYTE *srcrow; -+ const BYTE *srcbyte; -+ BYTE *dstrow; -+ BYTE *dstpixel; -+ -+ srcstride = prc->Width; -+ srcdatasize = srcstride * prc->Height; -+ -+ srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); -+ if (!srcdata) return E_OUTOFMEMORY; -+ -+ res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); -+ -+ if (SUCCEEDED(res)) -+ { -+ srcrow = srcdata; -+ dstrow = pbBuffer; -+ for (y=0; yHeight; y++) { -+ srcbyte = srcrow; -+ dstpixel = dstrow; -+ for (x=0; xWidth; x++) -+ { -+ *dstpixel++ = *srcbyte; -+ *dstpixel++ = *srcbyte; -+ *dstpixel++ = *srcbyte; -+ srcbyte++; -+ } -+ srcrow += srcstride; -+ dstrow += cbStride; -+ } -+ } -+ -+ HeapFree(GetProcessHeap(), 0, srcdata); -+ -+ return res; -+ } -+ return S_OK; - case format_24bppBGR: - case format_24bppRGB: - if (prc) diff --git a/pkgs/osu-wine/patches/9999-diffs-hide-wine-version.patch b/pkgs/osu-wine/patches/9999-diffs-hide-wine-version.patch deleted file mode 100644 index bd2a004..0000000 --- a/pkgs/osu-wine/patches/9999-diffs-hide-wine-version.patch +++ /dev/null @@ -1,54 +0,0 @@ -diff --git a/dlls/kernel32/module.c b/dlls/kernel32/module.c -index 11111111111..11111111111 100644 ---- a/dlls/kernel32/module.c -+++ b/dlls/kernel32/module.c -@@ -262,6 +262,34 @@ BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ) - return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType); - } - -+static BOOL block_wine_get_version = FALSE; -+ -+BOOL CALLBACK init_block_wine_get_version( INIT_ONCE* init_once, PVOID param, PVOID *ctx ) -+{ -+ WCHAR *buffer; -+ DWORD size; -+ -+ if ((size = GetEnvironmentVariableW( L"WINE_BLOCK_GET_VERSION", NULL, 0 ))) -+ { -+ if (!(buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(*buffer) * size ))) -+ { -+ ERR("No memory.\n"); -+ return FALSE; -+ } -+ -+ if (GetEnvironmentVariableW( L"WINE_BLOCK_GET_VERSION", buffer, size ) != size - 1) -+ { -+ ERR("Error getting WINE_BLOCK_GET_VERSION env variable.\n"); -+ return FALSE; -+ } -+ -+ block_wine_get_version = *buffer && !!wcsncmp( buffer, L"0", 1 ); -+ -+ HeapFree( GetProcessHeap(), 0, buffer ); -+ } -+ return TRUE; -+} -+ - /*********************************************************************** - * GetProcAddress (KERNEL32.@) - * -@@ -279,6 +307,14 @@ FARPROC get_proc_address( HMODULE hModule, LPCSTR function ) - { - FARPROC fp; - -+ if ((ULONG_PTR)function >> 16) -+ { -+ static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; -+ InitOnceExecuteOnce( &init_once, init_block_wine_get_version, NULL, NULL ); -+ if (block_wine_get_version && !strncmp( function, "wine_get_version", 16 )) -+ return NULL; -+ } -+ - if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress; - - if ((ULONG_PTR)function >> 16) diff --git a/pkgs/osu-wine/patches/9999-diffs-use-clock_nanosleep-for-delay.patch b/pkgs/osu-wine/patches/9999-diffs-use-clock_nanosleep-for-delay.patch deleted file mode 100644 index d138fae..0000000 --- a/pkgs/osu-wine/patches/9999-diffs-use-clock_nanosleep-for-delay.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index e303367c29f..3723d21f885 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -2788,10 +2788,39 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou - } - else - { -+ LONGLONG ticks = timeout->QuadPart; - LARGE_INTEGER now; -- timeout_t when, diff; -+ timeout_t when = ticks, diff; - -- if ((when = timeout->QuadPart) < 0) -+#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_NANOSLEEP) -+ static BOOL disable_clock_nanosleep = FALSE; -+ if (!disable_clock_nanosleep && ticks != 0) -+ { -+ struct timespec when; -+ int err; -+ -+ if (ticks < 0) -+ { -+ clock_gettime( CLOCK_REALTIME, &when ); -+ when.tv_sec += (time_t)(-ticks / TICKSPERSEC); -+ when.tv_nsec += (long)((-ticks % TICKSPERSEC) * 100); -+ } -+ else -+ { -+ when.tv_sec = (time_t)((ticks / TICKSPERSEC) - SECS_1601_TO_1970); -+ when.tv_nsec = (long)((ticks % TICKSPERSEC) * 100); -+ } -+ -+ usleep(0); -+ while ((err = clock_nanosleep( CLOCK_REALTIME, TIMER_ABSTIME, &when, NULL )) == EINTR); -+ if (!err) -+ return STATUS_SUCCESS; -+ else -+ disable_clock_nanosleep = TRUE; -+ } -+#endif -+ -+ if (when < 0) - { - NtQuerySystemTime( &now ); - when = now.QuadPart - when; diff --git a/pkgs/osu-wine/patches/9999-map-import-crash-fix.patch b/pkgs/osu-wine/patches/9999-map-import-crash-fix.patch deleted file mode 100644 index 0c16605..0000000 --- a/pkgs/osu-wine/patches/9999-map-import-crash-fix.patch +++ /dev/null @@ -1,13 +0,0 @@ -## osu! fix: disables assertion causing game to crash when importing maps -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index 9e84ec3cc96..dfa2a2781bc 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -1783,7 +1783,6 @@ NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT ma - */ - void ntdll_set_exception_jmp_buf( __wine_jmp_buf *jmp ) - { -- assert( !jmp || !ntdll_get_thread_data()->jmp_buf ); - ntdll_get_thread_data()->jmp_buf = jmp; - } - diff --git a/pkgs/osu-wine/patches/display-cache-less-frequent-update.patch b/pkgs/osu-wine/patches/display-cache-less-frequent-update.patch deleted file mode 100644 index 741914d..0000000 --- a/pkgs/osu-wine/patches/display-cache-less-frequent-update.patch +++ /dev/null @@ -1,82 +0,0 @@ -diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c -index 11111111111..11111111111 100644 ---- a/dlls/win32u/sysparams.c -+++ b/dlls/win32u/sysparams.c -@@ -26,9 +26,14 @@ - - #include - #include -+#include - - #include "ntstatus.h" - #define WIN32_NO_STATUS -+#include "windef.h" -+#include "winbase.h" -+#include "winternl.h" -+#include "ddk/wdm.h" - #include "ntgdi_private.h" - #include "ntuser_private.h" - #include "devpropdef.h" -@@ -1679,12 +1684,31 @@ static void clear_display_devices(void) - } - } - -+static ULONGLONG last_update = 0; -+ -+#define user_shared_data ((volatile const struct _KUSER_SHARED_DATA *)0x7ffe0000) -+ -+static ULONGLONG get_tick_count(void) -+{ -+ ULONG high, low; -+ -+ do -+ { -+ high = user_shared_data->TickCount.High1Time; -+ low = user_shared_data->TickCount.LowPart; -+ } -+ while (high != user_shared_data->TickCount.High2Time); -+ /* note: we ignore TickCountMultiplier */ -+ return (ULONGLONG)high << 32 | low; -+} -+ - static BOOL update_display_cache_from_registry(void) - { - DWORD adapter_id, monitor_id, monitor_count = 0, size; - KEY_BASIC_INFORMATION key; - struct adapter *adapter; - struct monitor *monitor, *monitor2; -+ ULONGLONG tick_count; - HANDLE mutex = NULL; - NTSTATUS status; - BOOL ret; -@@ -1694,12 +1718,18 @@ static BOOL update_display_cache_from_registry(void) - sizeof(devicemap_video_keyW) ))) - return FALSE; - -+ if ((tick_count = get_tick_count()) - last_update < 1000) return TRUE; -+ - status = NtQueryKey( video_key, KeyBasicInformation, &key, - offsetof(KEY_BASIC_INFORMATION, Name), &size ); - if (status && status != STATUS_BUFFER_OVERFLOW) - return FALSE; - -- if (key.LastWriteTime.QuadPart <= last_query_display_time) return TRUE; -+ if (key.LastWriteTime.QuadPart <= last_query_display_time) -+ { -+ last_update = tick_count; -+ return TRUE; -+ } - - mutex = get_display_device_init_mutex(); - pthread_mutex_lock( &display_lock ); -@@ -1746,7 +1776,10 @@ static BOOL update_display_cache_from_registry(void) - } - - if ((ret = !list_empty( &adapters ) && !list_empty( &monitors ))) -+ { - last_query_display_time = key.LastWriteTime.QuadPart; -+ last_update = tick_count; -+ } - pthread_mutex_unlock( &display_lock ); - release_display_device_init_mutex( mutex ); - return ret; diff --git a/pkgs/osu-wine/patches/ps0071-p0002-winex11.drv-Bypass-compositor-in-fullscreen-.patch b/pkgs/osu-wine/patches/ps0071-p0002-winex11.drv-Bypass-compositor-in-fullscreen-.patch deleted file mode 100644 index 8ef831b..0000000 --- a/pkgs/osu-wine/patches/ps0071-p0002-winex11.drv-Bypass-compositor-in-fullscreen-.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 138916577787bbdf19cf9523b15603f73b4f4472 Mon Sep 17 00:00:00 2001 -From: Kai Krakow -Date: Thu, 4 Oct 2018 05:51:20 +0200 -Subject: [PATCH 2/2] winex11.drv: Bypass compositor in fullscreen mode. - -Bypass the compositor in fullscreen mode. This reduces stutter -introduced by window updates in the background and also allows for maybe -a few more FPS. To not change the visual appearance of the desktop for -windowed games, this hack only enables itself when the game was switched -to fullscreen mode, and returns to default WM setting when the game -leaves fullscreen mode. - -Compositors tend to cause severe stutter if the game is GPU-bound. ---- - dlls/winex11.drv/window.c | 7 +++++++ - dlls/winex11.drv/x11drv.h | 1 + - dlls/winex11.drv/x11drv_main.c | 1 + - 3 files changed, 9 insertions(+) - ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1036,6 +1036,7 @@ - void update_net_wm_states( struct x11drv_win_data *data ) - { - UINT i, style, ex_style, new_state = 0; -+ unsigned long net_wm_bypass_compositor = 0; - - if (!data->managed) return; - if (data->whole_window == root_window) return; -@@ -1048,7 +1049,10 @@ - if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) - new_state |= (1 << NET_WM_STATE_MAXIMIZED); - else if (!(style & WS_MINIMIZE)) -+ { -+ net_wm_bypass_compositor = 1; - new_state |= (1 << NET_WM_STATE_FULLSCREEN); -+ } - } - else if (style & WS_MAXIMIZE) - new_state |= (1 << NET_WM_STATE_MAXIMIZED); -@@ -1112,6 +1116,9 @@ - } - data->net_wm_state = new_state; - update_net_wm_fullscreen_monitors( data ); -+ -+ XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_BYPASS_COMPOSITOR), XA_CARDINAL, -+ 32, PropModeReplace, (unsigned char *)&net_wm_bypass_compositor, 1 ); - } - - /*********************************************************************** ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -501,6 +501,7 @@ - XATOM__NET_SYSTEM_TRAY_OPCODE, - XATOM__NET_SYSTEM_TRAY_S0, - XATOM__NET_SYSTEM_TRAY_VISUAL, -+ XATOM__NET_WM_BYPASS_COMPOSITOR, - XATOM__NET_WM_FULLSCREEN_MONITORS, - XATOM__NET_WM_ICON, - XATOM__NET_WM_MOVERESIZE, ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -159,6 +159,7 @@ - "_NET_SYSTEM_TRAY_OPCODE", - "_NET_SYSTEM_TRAY_S0", - "_NET_SYSTEM_TRAY_VISUAL", -+ "_NET_WM_BYPASS_COMPOSITOR", - "_NET_WM_FULLSCREEN_MONITORS", - "_NET_WM_ICON", - "_NET_WM_MOVERESIZE", diff --git a/pkgs/osu-wine/patches/ps0128-HACK-Fix-osu-alt-tab-on-certain-window-managers.patch b/pkgs/osu-wine/patches/ps0128-HACK-Fix-osu-alt-tab-on-certain-window-managers.patch deleted file mode 100644 index 8f36250..0000000 --- a/pkgs/osu-wine/patches/ps0128-HACK-Fix-osu-alt-tab-on-certain-window-managers.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 5c8c060fc9d1d20eebe12da2e6dacddd88c07d82 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Sun, 26 Nov 2023 18:29:53 +0100 -Subject: [PATCH] HACK: Fix osu! alt-tab. - ---- - dlls/win32u/window.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c -index 11111111111..11111111111 100644 ---- a/dlls/win32u/window.c -+++ b/dlls/win32u/window.c -@@ -3514,6 +3514,11 @@ BOOL set_window_pos( WINDOWPOS *winpos, int parent_x, int parent_y ) - - orig_flags = winpos->flags; - -+ /* HACK: fix osu! taking back focus immediately when it is unfocused. */ -+ if (winpos->hwndInsertAfter == HWND_NOTOPMOST && -+ (get_window_long( winpos->hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST)) -+ winpos->flags |= SWP_NOACTIVATE | SWP_NOZORDER; -+ - /* First, check z-order arguments. */ - if (!(winpos->flags & SWP_NOZORDER)) - { --- -0.0.0 - diff --git a/pkgs/osu-wine/patches/ps0417-p0002-winex11.drv-Add-OpenGL-latency-reduction-cod.patch b/pkgs/osu-wine/patches/ps0417-p0002-winex11.drv-Add-OpenGL-latency-reduction-cod.patch deleted file mode 100644 index e20dcce..0000000 --- a/pkgs/osu-wine/patches/ps0417-p0002-winex11.drv-Add-OpenGL-latency-reduction-cod.patch +++ /dev/null @@ -1,324 +0,0 @@ -From ec87cc3742130c138e4caa37084c92c46b9cb9ad Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Sun, 3 Jul 2022 15:54:01 +0200 -Subject: [PATCH 2/2] winex11.drv: Add OpenGL latency reduction code. - ---- - dlls/winex11.drv/opengl.c | 255 +++++++++++++++++++++++++++++++++++++- - 1 file changed, 252 insertions(+), 3 deletions(-) - -diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c -index 11111111111..11111111111 100644 ---- a/dlls/winex11.drv/opengl.c -+++ b/dlls/winex11.drv/opengl.c -@@ -42,6 +42,8 @@ - #include "xcomposite.h" - #include "winternl.h" - #include "wine/debug.h" -+#include "wine/server.h" -+#include "../win32u/ntuser_private.h" - - #ifdef SONAME_LIBGL - - -@@ -225,6 +229,8 @@ enum dc_gl_layered_type - DC_GL_LAYERED_ATTRIBUTES, - }; - -+typedef LONGLONG rtime_t; -+ - struct gl_drawable - { - LONG ref; /* reference count */ - -@@ -3443,6 +3454,130 @@ static void X11DRV_WineGL_LoadExtensions(void) - } - } - -+static inline BOOL allow_latency_reduction( void ) -+{ -+ static int status = -1; -+ if (status == -1) -+ { -+ const char *env = getenv( "WINE_OPENGL_LATENCY_REDUCTION" ); -+ status = !!(env && atoi(env)); -+ } -+ return status == 1; -+} -+ -+#define TICKSPERSEC 10000000 -+ -+typedef struct ftime_t { -+ LONGLONG time; -+ ULONGLONG freq; -+} ftime_t; -+ -+static inline ftime_t current_ftime( void ) -+{ -+ LARGE_INTEGER counter, freq; -+ ftime_t ret; -+ NtQueryPerformanceCounter( &counter, &freq ); -+ ret.time = counter.QuadPart; -+ ret.freq = (ULONGLONG)freq.QuadPart; -+ return ret; -+} -+ -+static inline rtime_t ftime_to_rtime( ftime_t ftime, BOOL round_up ) -+{ -+ ftime.time *= TICKSPERSEC; -+ if (round_up) -+ ftime.time += ftime.freq - 1; -+ return ftime.time / ftime.freq; -+} -+ -+static inline rtime_t current_rtime( BOOL round_up ) -+{ -+ return ftime_to_rtime( current_ftime(), round_up ); -+} -+ -+static rtime_t get_vblank_interval( HWND hwnd ) -+{ -+ HMONITOR monitor; -+ UNICODE_STRING device_name; -+ MONITORINFOEXW moninfo = { sizeof(MONITORINFOEXW) }; -+ DEVMODEW devmode = { {0}, 0, 0, sizeof(DEVMODEW) }; -+ -+ monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ); -+ if (!monitor || !NtUserGetMonitorInfo( monitor, (MONITORINFO*)&moninfo )) -+ return 0; -+ -+ RtlInitUnicodeString( &device_name, moninfo.szDevice ); -+ if (!NtUserEnumDisplaySettings( &device_name, ENUM_CURRENT_SETTINGS, &devmode, 0 ) -+ || devmode.dmDisplayFrequency <= 1) -+ return 0; -+ MESSAGE("detected display frequency: %u\n", devmode.dmDisplayFrequency); -+ return TICKSPERSEC / devmode.dmDisplayFrequency; -+} -+ -+#define FRAMETIME_MARGIN_SHIFT 2 -+ -+static inline rtime_t frame_time_with_margin( rtime_t frame_time ) -+{ -+ return frame_time + (frame_time >> FRAMETIME_MARGIN_SHIFT) + 3500; -+} -+ -+static void get_swap_interval(GLXDrawable drawable, int *interval) -+{ -+ /* HACK: does not work correctly with __GL_SYNC_TO_VBLANK */ -+ /*pglXQueryDrawable(gdi_display, gl->drawable, GLX_SWAP_INTERVAL_EXT, (unsigned int*)interval);*/ -+ *interval = 0; -+} -+ -+#define WAIT_MASK (QS_MOUSEBUTTON | QS_KEY | QS_SENDMESSAGE | QS_TIMER | QS_HOTKEY) -+ -+static void msg_wait( const LARGE_INTEGER *timeout ) -+{ -+ LARGE_INTEGER to = *timeout, to2 = to; -+ rtime_t start, end; -+ DWORD ret; -+ -+ /* HACK: __wine_msg_wait_objects likes to wait for about 1 ms too long */ -+ -+ if (to2.QuadPart < 0) -+ { -+ to2.QuadPart += 10000; -+ if (to2.QuadPart >= 0) -+ { -+ end = current_rtime( TRUE ); -+ goto busy_loop; -+ } -+ } -+ else if (to2.QuadPart >= 10000) -+ to2.QuadPart -= 10000; -+ -+ if (to2.QuadPart >= 0) -+ { -+ __wine_msg_wait_objects( 0, NULL, &to2, WAIT_MASK, MWMO_INPUTAVAILABLE ); -+ return; -+ } -+ -+again: -+ start = current_rtime( FALSE ); -+ ret = __wine_msg_wait_objects( 0, NULL, &to2, WAIT_MASK, MWMO_INPUTAVAILABLE ); -+ if (ret == WAIT_OBJECT_0) -+ return; -+ end = current_rtime( TRUE ); -+ -+ to.QuadPart += end - start; -+ if (to.QuadPart < -11000) -+ { -+ to2.QuadPart = to.QuadPart + 10000; -+ goto again; -+ } -+ -+busy_loop: -+ if (to.QuadPart < -1000) -+ { -+ end = end - to.QuadPart - 1000; -+ while (current_rtime( TRUE ) < end) -+ YieldProcessor(); -+ } -+} - - /** - * glxdrv_SwapBuffers -@@ -3457,6 +3592,11 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) - INT64 ust, msc, sbc, target_sbc = 0; - HWND hwnd; - -+ BOOL enable_latency_reduction = FALSE; -+ BOOL synchronize_to_vblank = FALSE; -+ rtime_t frame_end_time; -+ rtime_t next_vblank_time = 0; -+ - TRACE("(%p)\n", hdc); - - escape.code = X11DRV_PRESENT_DRAWABLE; -@@ -3469,18 +3609,78 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) - return FALSE; - } - -+ if (allow_latency_reduction()) -+ enable_latency_reduction = gl->type == DC_GL_WINDOW -+ || gl->type == DC_GL_CHILD_WIN || gl->type == DC_GL_PIXMAP_WIN; -+ -+ if (enable_latency_reduction) -+ { -+ if (ctx && (gl->type == DC_GL_WINDOW || gl->type == DC_GL_CHILD_WIN -+ || gl->type == DC_GL_PIXMAP_WIN)) -+ sync_context( ctx ); -+ pglFinish(); -+ frame_end_time = current_rtime( TRUE ); -+ } -+ - pthread_mutex_lock( &context_mutex ); -- if (gl->refresh_swap_interval) -+ -+ if (enable_latency_reduction) -+ { -+ if (!gl->vblank_interval) -+ { -+ HWND hwnd = 0; -+ assert(!XFindContext( gdi_display, gl->window, winContext, (char **)&hwnd )); -+ assert(hwnd); -+ gl->vblank_interval = get_vblank_interval( hwnd ); -+ assert(gl->vblank_interval); -+ } -+ -+ if (gl->last_vblank_time) -+ { -+ next_vblank_time = gl->last_vblank_time + gl->vblank_interval; -+ while (next_vblank_time < frame_end_time) -+ next_vblank_time += gl->vblank_interval; -+ } -+ -+ if (gl->last_swap_time) -+ { -+ rtime_t new_frame_time = frame_end_time - gl->last_swap_time; -+ if (new_frame_time >= gl->frame_time) -+ gl->frame_time = new_frame_time; -+ else if (gl->frame_time > new_frame_time * 3) -+ gl->frame_time = frame_time_with_margin( new_frame_time ); -+ else -+ gl->frame_time = (gl->frame_time * 20 + new_frame_time) / 21; -+ } -+ -+ if (frame_end_time - gl->last_vblank_time >= TICKSPERSEC -+ || (!gl->refresh_swap_interval && next_vblank_time - frame_end_time <= frame_time_with_margin( gl->frame_time ))) -+ synchronize_to_vblank = TRUE; -+ } -+ -+ if (synchronize_to_vblank) -+ { -+ if (!gl->previous_frame_synchronized) -+ { -+ get_swap_interval(gl->drawable, &gl->swap_interval); -+ if (!set_swap_interval(gl->drawable, 1)) -+ synchronize_to_vblank = FALSE; -+ gl->previous_frame_synchronized = TRUE; -+ } -+ } -+ else if (gl->refresh_swap_interval || gl->previous_frame_synchronized) - { - set_swap_interval(gl->drawable, gl->swap_interval); - gl->refresh_swap_interval = FALSE; -+ gl->previous_frame_synchronized = FALSE; - } -+ - pthread_mutex_unlock( &context_mutex ); - - switch (gl->type) - { - case DC_GL_PIXMAP_WIN: -- if (ctx) sync_context( ctx ); -+ if (!enable_latency_reduction && ctx) sync_context( ctx ); - escape.drawable = gl->pixmap; - if (pglXCopySubBufferMESA) { - /* (glX)SwapBuffers has an implicit glFlush effect, however -@@ -3501,7 +3701,7 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) - break; - case DC_GL_WINDOW: - case DC_GL_CHILD_WIN: -- if (ctx) sync_context( ctx ); -+ if (!enable_latency_reduction && ctx) sync_context( ctx ); - if (gl->type == DC_GL_CHILD_WIN) escape.drawable = gl->window; - /* fall through */ - default: -@@ -3519,5 +3719,54 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) - pglXWaitForSbcOML( gdi_display, gl->drawable, target_sbc, &ust, &msc, &sbc ); - -+ -+ if (enable_latency_reduction) -+ { -+ rtime_t current_time = current_rtime( FALSE ); -+ -+ if (!synchronize_to_vblank && gl->last_vblank_time && gl->frame_time) -+ { -+ LARGE_INTEGER timeout; -+ -+ next_vblank_time = gl->last_vblank_time + gl->vblank_interval; -+ while (next_vblank_time < current_time + frame_time_with_margin( gl->frame_time )) -+ next_vblank_time += gl->vblank_interval; -+ -+ timeout.QuadPart = -(next_vblank_time - frame_time_with_margin( gl->frame_time ) - current_time); -+ if (timeout.QuadPart < 0 && -timeout.QuadPart < TICKSPERSEC) -+ msg_wait( &timeout ); -+ -+ current_time = current_rtime( FALSE ); -+ } -+ -+ pthread_mutex_lock( &context_mutex ); -+ -+ gl->last_swap_time = current_time; -+ if (synchronize_to_vblank) -+ gl->last_vblank_time = current_time; -+ -+ pthread_mutex_unlock( &context_mutex ); -+ -+ if (synchronize_to_vblank && gl->frame_time) -+ { -+ LARGE_INTEGER timeout; -+ -+ next_vblank_time = gl->last_vblank_time + gl->vblank_interval; -+ while (next_vblank_time < current_time + frame_time_with_margin( gl->frame_time )) -+ next_vblank_time += gl->vblank_interval; -+ -+ timeout.QuadPart = -(next_vblank_time - frame_time_with_margin( gl->frame_time ) - current_time); -+ if (timeout.QuadPart < 0 && -timeout.QuadPart < TICKSPERSEC) -+ { -+ msg_wait( &timeout ); -+ -+ current_time = current_rtime( FALSE ); -+ pthread_mutex_lock( &context_mutex ); -+ gl->last_swap_time = current_time; -+ pthread_mutex_unlock( &context_mutex ); -+ } -+ } -+ } -+ - release_gl_drawable( gl ); - - if (ctx && escape.drawable) --- -2.40.0 - diff --git a/pkgs/osu-wine/patches/ps0741-ntdll-Implement-NtFlushProcessWriteBuffers.patch b/pkgs/osu-wine/patches/ps0741-ntdll-Implement-NtFlushProcessWriteBuffers.patch deleted file mode 100644 index 6fa6123..0000000 --- a/pkgs/osu-wine/patches/ps0741-ntdll-Implement-NtFlushProcessWriteBuffers.patch +++ /dev/null @@ -1,319 +0,0 @@ -From a21d85ace24116af87b83738909001c1e7cf87c2 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Wed, 23 Nov 2022 15:47:49 +0100 -Subject: [PATCH 1/3] ntdll: Add MADV_DONTNEED-based implementation of - NtFlushProcessWriteBuffers. - -Credits to Avi Kivity (scylladb) and Aliaksei Kandratsenka (gperftools) for this trick, see [1]. - -[1] https://github.com/scylladb/seastar/commit/77a58e4dc020233f66fccb8d9e8f7a8b7f9210c4 ---- - dlls/ntdll/unix/virtual.c | 52 +++++++++++++++++++++++++++++++++++++- - tools/winapi/nativeapi.dat | 1 + - 2 files changed, 52 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index 8087a12785c..de8f8b6ebc1 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -215,6 +215,11 @@ struct range_entry - static struct range_entry *free_ranges; - static struct range_entry *free_ranges_end; - -+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) -+static void *dontneed_page; -+static pthread_mutex_t dontneed_page_mutex = PTHREAD_MUTEX_INITIALIZER; -+#endif -+ - - static inline BOOL is_beyond_limit( const void *addr, size_t size, const void *limit ) - { -@@ -5174,14 +5179,58 @@ NTSTATUS WINAPI NtFlushInstructionCache( HANDLE handle, const void *addr, SIZE_T - } - - -+static BOOL try_madvise( void ) -+{ -+ BOOL success = FALSE; -+ char *mem; -+ -+ pthread_mutex_lock(&dontneed_page_mutex); -+ /* Credits to Avi Kivity (scylladb) and Aliaksei Kandratsenka (gperftools) for this trick, -+ see https://github.com/scylladb/seastar/commit/77a58e4dc020233f66fccb8d9e8f7a8b7f9210c4 */ -+ mem = dontneed_page; -+ if (!mem) -+ { -+ int ret; -+ /* Allocate one page of memory that we can call madvise() on */ -+ mem = anon_mmap_alloc( page_size, PROT_READ | PROT_WRITE ); -+ if (mem == MAP_FAILED) -+ goto failed; -+ /* If the memory is locked, e.g. by a call to mlockall(MCL_FUTURE), the madvise() call below -+ will fail with error EINVAL, so unlock it here */ -+ ret = munlock( mem, page_size ); -+ /* munlock() may fail on old kernels if we don't have sufficient permissions, but that is not -+ a problem since in that case we didn't have permission to lock the memory either */ -+ if (ret && errno != EPERM) -+ goto failed; -+ dontneed_page = mem; -+ } -+ /* Force the page into memory to make madvise() have real work to do */ -+ *mem = 3; -+ /* Evict the page from memory to force the kernel to send an IPI to all threads of this process, -+ which has the side effect of executing a memory barrier in those threads */ -+ success = !madvise( mem, page_size, MADV_DONTNEED ); -+failed: -+ pthread_mutex_unlock(&dontneed_page_mutex); -+ return success; -+} -+ -+ - /********************************************************************** - * NtFlushProcessWriteBuffers (NTDLL.@) - */ - NTSTATUS WINAPI NtFlushProcessWriteBuffers(void) - { - static int once = 0; -- if (!once++) FIXME( "stub\n" ); -- return STATUS_SUCCESS; -+ if (try_madvise()) -+ { -+#ifdef __aarch64__ -+ /* Some ARMv8 processors can broadcast TLB invalidations using the TLBI instruction, -+ the madvise trick does not work on those */ -+ if (!once++) FIXME( "memory barrier may not work on this platform\n" ); -+#endif -+ return; -+ } -+ if (!once++) FIXME( "no implementation available on this platform\n" ); - } - - -diff --git a/tools/winapi/nativeapi.dat b/tools/winapi/nativeapi.dat -index ade20b5ee68..5512c4f1833 100644 ---- a/tools/winapi/nativeapi.dat -+++ b/tools/winapi/nativeapi.dat -@@ -134,6 +134,7 @@ log10 - logb - longjmp - lseek -+madvise - malloc - mblen - memccpy --- -GitLab - - -From d3afd6ff2ffe7942d6e0846dea52a3884111a06a Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Wed, 23 Nov 2022 15:47:50 +0100 -Subject: [PATCH 2/3] ntdll: Add sys_membarrier-based implementation of - NtFlushProcessWriteBuffers. - -Uses the MEMBARRIER_CMD_PRIVATE_EXPEDITED membarrier command introduced in Linux 4.14. ---- - dlls/ntdll/unix/virtual.c | 49 ++++++++++++++++++++++++++++++++++++++- - 1 file changed, 48 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index de8f8b6ebc1..e90bdb3abfb 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -39,6 +39,9 @@ - #ifdef HAVE_SYS_SYSINFO_H - # include - #endif -+#ifdef HAVE_SYS_SYSCALL_H -+# include -+#endif - #ifdef HAVE_SYS_SYSCTL_H - # include - #endif -@@ -215,10 +218,16 @@ struct range_entry - static struct range_entry *free_ranges; - static struct range_entry *free_ranges_end; - --#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) -+#ifdef __linux__ -+#ifdef __NR_membarrier -+static BOOL membarrier_exp_available; -+static pthread_once_t membarrier_init_once = PTHREAD_ONCE_INIT; -+#endif -+#if defined(__i386__) || defined(__x86_64__) - static void *dontneed_page; - static pthread_mutex_t dontneed_page_mutex = PTHREAD_MUTEX_INITIALIZER; - #endif -+#endif - - - static inline BOOL is_beyond_limit( const void *addr, size_t size, const void *limit ) -@@ -5179,6 +5188,42 @@ NTSTATUS WINAPI NtFlushInstructionCache( HANDLE handle, const void *addr, SIZE_T - } - - -+#if defined(__linux__) && defined(__NR_membarrier) -+#define MEMBARRIER_CMD_QUERY 0x00 -+#define MEMBARRIER_CMD_PRIVATE_EXPEDITED 0x08 -+#define MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED 0x10 -+ -+ -+static int membarrier( int cmd, unsigned int flags, int cpu_id ) -+{ -+ return syscall( __NR_membarrier, cmd, flags, cpu_id ); -+} -+ -+ -+static void membarrier_init( void ) -+{ -+ static const int exp_required_cmds = -+ MEMBARRIER_CMD_PRIVATE_EXPEDITED | MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED; -+ int available_cmds = membarrier( MEMBARRIER_CMD_QUERY, 0, 0 ); -+ if (available_cmds == -1) -+ return; -+ if ((available_cmds & exp_required_cmds) == exp_required_cmds) -+ membarrier_exp_available = !membarrier( MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0, 0 ); -+} -+ -+ -+static BOOL try_exp_membarrier( void ) -+{ -+ pthread_once(&membarrier_init_once, membarrier_init); -+ if (!membarrier_exp_available) -+ return FALSE; -+ return !membarrier( MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0, 0 ); -+} -+#else -+static BOOL try_exp_membarrier( void ) { return 0; } -+#endif -+ -+ - static BOOL try_madvise( void ) - { - BOOL success = FALSE; -@@ -5221,6 +5266,8 @@ failed: - void WINAPI NtFlushProcessWriteBuffers(void) - { - static int once = 0; -+ if (try_exp_membarrier()) -+ return; - if (try_madvise()) - { - #ifdef __aarch64__ --- -GitLab - - -From 48f1d7cad78235c5c9e64c419235289608294440 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Wed, 23 Nov 2022 15:47:50 +0100 -Subject: [PATCH 3/3] ntdll: Add thread_get_register_pointer_values-based - implementation of NtFlushProcessWriteBuffers. - ---- - dlls/ntdll/unix/virtual.c | 68 +++++++++++++++++++++++++++++++++++++++ - 1 file changed, 68 insertions(+) - -diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c -index e90bdb3abfb..c5a2f878e3b 100644 ---- a/dlls/ntdll/unix/virtual.c -+++ b/dlls/ntdll/unix/virtual.c -@@ -65,6 +65,9 @@ - #if defined(__APPLE__) - # include - # include -+# include -+# include -+# include - #endif - - #include "ntstatus.h" -@@ -218,6 +221,11 @@ struct range_entry - static struct range_entry *free_ranges; - static struct range_entry *free_ranges_end; - -+#ifdef __APPLE__ -+static kern_return_t (*p_thread_get_register_pointer_values)( thread_t, uintptr_t*, size_t*, uintptr_t* ); -+static pthread_once_t tgrpvs_init_once = PTHREAD_ONCE_INIT; -+#endif -+ - #ifdef __linux__ - #ifdef __NR_membarrier - static BOOL membarrier_exp_available; -@@ -5188,6 +5196,64 @@ NTSTATUS WINAPI NtFlushInstructionCache( HANDLE handle, const void *addr, SIZE_T - } - - -+#ifdef __APPLE__ -+ -+static void tgrpvs_init( void ) -+{ -+ p_thread_get_register_pointer_values = dlsym( RTLD_DEFAULT, "thread_get_register_pointer_values" ); -+} -+ -+static BOOL try_mach_tgrpvs( void ) -+{ -+ /* Taken from https://github.com/dotnet/runtime/blob/7be37908e5a1cbb83b1062768c1649827eeaceaa/src/coreclr/pal/src/thread/process.cpp#L2799 */ -+ mach_msg_type_number_t count, i = 0; -+ thread_act_array_t threads; -+ kern_return_t kret; -+ BOOL success = FALSE; -+ -+ pthread_once(&tgrpvs_init_once, tgrpvs_init); -+ if (!p_thread_get_register_pointer_values) -+ return FALSE; -+ -+ /* Get references to all threads of this process */ -+ kret = task_threads( mach_task_self(), &threads, &count ); -+ if (kret) -+ return FALSE; -+ -+ /* Iterate through the threads in the list */ -+ while (i < count) -+ { -+ uintptr_t reg_values[128]; -+ size_t reg_count = ARRAY_SIZE( reg_values ); -+ uintptr_t sp; -+ -+ /* Request the thread's register pointer values to force the thread to go through a memory barrier */ -+ kret = p_thread_get_register_pointer_values( threads[i], &sp, ®_count, reg_values ); -+ /* This function always fails when querying Rosetta's exception handling thread, so we only treat -+ KERN_INSUFFICIENT_BUFFER_SIZE as an error, like .NET core does. */ -+ if (kret == KERN_INSUFFICIENT_BUFFER_SIZE) -+ goto fail; -+ -+ /* Deallocate thread reference once we're done with it */ -+ kret = mach_port_deallocate( mach_task_self(), threads[i++] ); -+ if (kret) -+ goto fail; -+ } -+ success = TRUE; -+fail: -+ /* Deallocate remaining thread references */ -+ while (i < count) -+ mach_port_deallocate( mach_task_self(), threads[i++] ); -+ /* Deallocate thread list */ -+ vm_deallocate( mach_task_self(), (vm_address_t)threads, count * sizeof(threads[0]) ); -+ return success; -+} -+ -+#else -+static BOOL try_mach_tgrpvs( void ) { return 0; } -+#endif -+ -+ - #if defined(__linux__) && defined(__NR_membarrier) - #define MEMBARRIER_CMD_QUERY 0x00 - #define MEMBARRIER_CMD_PRIVATE_EXPEDITED 0x08 -@@ -5266,6 +5332,8 @@ failed: - void WINAPI NtFlushProcessWriteBuffers(void) - { - static int once = 0; -+ if (try_mach_tgrpvs()) -+ return; - if (try_exp_membarrier()) - return; - if (try_madvise()) --- -GitLab - diff --git a/pkgs/osu-wine/patches/revert-x11-gnome-fix.patch b/pkgs/osu-wine/patches/revert-x11-gnome-fix.patch deleted file mode 100644 index 21d2806..0000000 --- a/pkgs/osu-wine/patches/revert-x11-gnome-fix.patch +++ /dev/null @@ -1,27 +0,0 @@ -## Patch to revert commit 35193586 which supposedly broke osu! -## on GNOME on X11 due to compositor not turning off even with fullscreen enabled - ---- b/dlls/winex11.drv/window.c -+++ a/dlls/winex11.drv/window.c -@@ -1542,21 +1542,9 @@ - attrib.border_pixel = 0; - attrib.colormap = default_colormap; - --#ifdef HAVE_LIBXSHAPE -- { -- static XRectangle empty_rect; -- dummy_parent = XCreateWindow( gdi_display, root_window, 0, 0, 1, 1, 0, -- default_visual.depth, InputOutput, default_visual.visual, -- CWColormap | CWBorderPixel | CWOverrideRedirect, &attrib ); -- XShapeCombineRectangles( gdi_display, dummy_parent, ShapeBounding, 0, 0, &empty_rect, 1, -- ShapeSet, YXBanded ); -- } --#else - dummy_parent = XCreateWindow( gdi_display, root_window, -1, -1, 1, 1, 0, default_visual.depth, - InputOutput, default_visual.visual, - CWColormap | CWBorderPixel | CWOverrideRedirect, &attrib ); -- WARN("Xshape support is not compiled in. Applications under XWayland may have poor performance.\n"); --#endif - XMapWindow( gdi_display, dummy_parent ); - } - return dummy_parent; diff --git a/pkgs/osu-wine/sources.nix b/pkgs/osu-wine/sources.nix deleted file mode 100644 index 84948d5..0000000 --- a/pkgs/osu-wine/sources.nix +++ /dev/null @@ -1,177 +0,0 @@ -{ pkgs ? import {}, path ? pkgs.path }: -## we default to importing here, so that you can use -## a simple shell command to insert new hashes into this file -## e.g. with emacs C-u M-x shell-command -## -## nix-prefetch-url sources.nix -A {stable{,.mono,.gecko64,.gecko32}, unstable, staging, winetricks} - -# here we wrap fetchurl and fetchFromGitHub, in order to be able to pass additional args around it -let fetchurl = args@{url, hash, ...}: - pkgs.fetchurl { inherit url hash; } // args; - fetchFromGitHub = args@{owner, repo, rev, hash, ...}: - pkgs.fetchFromGitHub { inherit owner repo rev hash; } // args; - fetchFromGitLab = args@{domain, owner, repo, rev, hash, ...}: - pkgs.fetchFromGitLab { inherit domain owner repo rev hash; } // args; - - updateScriptPreamble = '' - set -eou pipefail - PATH=${with pkgs; lib.makeBinPath [ common-updater-scripts coreutils curl gnugrep gnused jq nix ]} - sources_file=${__curPos.file} - source ${./update-lib.sh} - ''; - - inherit (pkgs) writeShellScript; -in rec { - - stable = fetchurl rec { - version = "9.0"; - url = "https://dl.winehq.org/wine/source/9.0/wine-${version}.tar.xz"; - hash = "sha256-fP0JClOV9bdtlbtd76yKMSyN5MBwwRY7i1jaODMMpu4="; - - ## see http://wiki.winehq.org/Gecko - gecko32 = fetchurl rec { - version = "2.47.4"; - url = "https://dl.winehq.org/wine/wine-gecko/${version}/wine-gecko-${version}-x86.msi"; - hash = "sha256-Js7MR3BrCRkI9/gUvdsHTGG+uAYzGOnvxaf3iYV3k9Y="; - }; - gecko64 = fetchurl rec { - version = "2.47.4"; - url = "https://dl.winehq.org/wine/wine-gecko/${version}/wine-gecko-${version}-x86_64.msi"; - hash = "sha256-5ZC32YijLWqkzx2Ko6o9M3Zv3Uz0yJwtzCCV7LKNBm8="; - }; - - ## see http://wiki.winehq.org/Mono - mono = fetchurl rec { - version = "8.1.0"; - url = "https://dl.winehq.org/wine/wine-mono/${version}/wine-mono-${version}-x86.msi"; - hash = "sha256-DtPsUzrvebLzEhVZMc97EIAAmsDFtMK8/rZ4rJSOCBA="; - }; - - patches = [ - # Also look for root certificates at $NIX_SSL_CERT_FILE - "${path}/pkgs/applications/emulators/wine/cert-path.patch" - ]; - - updateScript = writeShellScript "update-wine-stable" ('' - ${updateScriptPreamble} - major=''${UPDATE_NIX_OLD_VERSION%%.*} - latest_stable=$(get_latest_wine_version "$major.0") - - # Can't use autobump on stable because we don't want the path - # to become . - if [[ "$UPDATE_NIX_OLD_VERSION" != "$latest_stable" ]]; then - set_version_and_hash stable "$latest_stable" "$(nix-prefetch-url "$wine_url_base/source/$major.0/wine-$latest_stable.tar.xz")" - fi - - do_update - ''); - }; - - unstable = fetchurl rec { - # NOTE: Don't forget to change the hash for staging as well. - version = "9.0"; - url = "https://dl.winehq.org/wine/source/9.0/wine-${version}.tar.xz"; - hash = "sha256-fP0JClOV9bdtlbtd76yKMSyN5MBwwRY7i1jaODMMpu4="; - inherit (stable) patches; - - ## see http://wiki.winehq.org/Gecko - gecko32 = fetchurl rec { - version = "2.47.4"; - url = "https://dl.winehq.org/wine/wine-gecko/${version}/wine-gecko-${version}-x86.msi"; - hash = "sha256-Js7MR3BrCRkI9/gUvdsHTGG+uAYzGOnvxaf3iYV3k9Y="; - }; - gecko64 = fetchurl rec { - version = "2.47.4"; - url = "https://dl.winehq.org/wine/wine-gecko/${version}/wine-gecko-${version}-x86_64.msi"; - hash = "sha256-5ZC32YijLWqkzx2Ko6o9M3Zv3Uz0yJwtzCCV7LKNBm8="; - }; - - ## see http://wiki.winehq.org/Mono - mono = fetchurl rec { - version = "8.1.0"; - url = "https://dl.winehq.org/wine/wine-mono/${version}/wine-mono-${version}-x86.msi"; - hash = "sha256-DtPsUzrvebLzEhVZMc97EIAAmsDFtMK8/rZ4rJSOCBA="; - }; - - updateScript = writeShellScript "update-wine-unstable" '' - ${updateScriptPreamble} - major=''${UPDATE_NIX_OLD_VERSION%%.*} - latest_unstable=$(get_latest_wine_version "$major.x") - latest_gecko=$(get_latest_lib_version wine-gecko) - latest_mono=$(get_latest_lib_version wine-mono) - - update_staging() { - staging_url=$(get_source_attr staging.url) - set_source_attr staging hash "\"$(to_sri "$(nix-prefetch-url --unpack "''${staging_url//$1/$2}")")\"" - } - - autobump unstable "$latest_unstable" "" update_staging - autobump unstable.gecko32 "$latest_gecko" - autobump unstable.gecko64 "$latest_gecko" - autobump unstable.mono "$latest_mono" - - do_update - ''; - }; - - staging = fetchFromGitHub rec { - # https://github.com/wine-staging/wine-staging/releases - inherit (unstable) version; - hash = "sha256-lE/95OZigifreaRRCPkvA+Z0FqsBmm018jD6leSysXU="; - owner = "wine-staging"; - repo = "wine-staging"; - rev = "v${version}"; - - disabledPatchsets = [ ]; - }; - - wayland = fetchFromGitLab { - # https://gitlab.collabora.com/alf/wine/-/tree/wayland - version = "8.2"; - hash = "sha256-Eb2SFBIeQQ3cVZkUQcwNT5mcYe0ShFxBdMc3BlqkwTo="; - domain = "gitlab.collabora.com"; - owner = "alf"; - repo = "wine"; - rev = "b2547ddf9e08cafce98cf7734d5c4ec926ef3536"; - - inherit (unstable) gecko32 gecko64; - - inherit (unstable) mono; - - updateScript = writeShellScript "update-wine-wayland" '' - ${updateScriptPreamble} - wayland_rev=$(get_source_attr wayland.rev) - - latest_wayland_rev=$(curl -s 'https://gitlab.collabora.com/api/v4/projects/2847/repository/branches/wayland' | jq -r .commit.id) - - if [[ "$wayland_rev" != "$latest_wayland_rev" ]]; then - latest_wayland=$(curl -s 'https://gitlab.collabora.com/alf/wine/-/raw/wayland/VERSION' | cut -f3 -d' ') - wayland_url=$(get_source_attr wayland.url) - set_version_and_hash wayland "$latest_wayland" "$(nix-prefetch-url --unpack "''${wayland_url/$wayland_rev/$latest_wayland_rev}")" - set_source_attr wayland rev "\"$latest_wayland_rev\"" - fi - - do_update - ''; - }; - - winetricks = fetchFromGitHub rec { - # https://github.com/Winetricks/winetricks/releases - version = "20240105"; - hash = "sha256-YTEgb19aoM54KK8/IjrspoChzVnWAEItDlTxpfpS52w="; - owner = "Winetricks"; - repo = "winetricks"; - rev = version; - - updateScript = writeShellScript "update-winetricks" '' - ${updateScriptPreamble} - winetricks_repourl=$(get_source_attr winetricks.gitRepoUrl) - - latest_winetricks=$(list-git-tags --url="$winetricks_repourl" | grep -E '^[0-9]{8}$' | sort --reverse --numeric-sort | head -n 1) - - autobump winetricks "$latest_winetricks" 'nix-prefetch-url --unpack' - - do_update - ''; - }; -}