Compare commits
2 commits
0a3c76e695
...
0cc911f974
Author | SHA1 | Date | |
---|---|---|---|
chayleaf | 0cc911f974 | ||
chayleaf | 0c58b2b87a |
467
flake.lock
467
flake.lock
|
@ -1,5 +1,38 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"agenix": {
|
||||||
|
"inputs": {
|
||||||
|
"darwin": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nix-darwin"
|
||||||
|
],
|
||||||
|
"home-manager": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"empty"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1718371084,
|
||||||
|
"narHash": "sha256-abpBi61mg0g+lFFU0zY4C6oP6fBwPzbHPKBGw676xsA=",
|
||||||
|
"owner": "ryantm",
|
||||||
|
"repo": "agenix",
|
||||||
|
"rev": "3a56735779db467538fb2e577eda28a9daacaca6",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ryantm",
|
||||||
|
"repo": "agenix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"blobs": {
|
"blobs": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
|
@ -16,6 +49,57 @@
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"buildbot-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-parts": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"flake-parts"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"treefmt-nix": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"treefmt-nix"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719797756,
|
||||||
|
"narHash": "sha256-TGZthxgxLdT8boadFm6+MK7HZlIxN1u1V+x3hu+Fd8I=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "buildbot-nix",
|
||||||
|
"rev": "0b56574a5c823097771487d1bac952c3549fe9fb",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "buildbot-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"comin": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1714766748,
|
||||||
|
"narHash": "sha256-//fP25eh1f9eA+0TEgWqusWjv9SuKh8rIF1ZJQNL1jo=",
|
||||||
|
"owner": "nlewo",
|
||||||
|
"repo": "comin",
|
||||||
|
"rev": "d3658c452024824235de2355ac3e156b10c3eaaf",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nlewo",
|
||||||
|
"repo": "comin",
|
||||||
|
"rev": "d3658c452024824235de2355ac3e156b10c3eaaf",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"coop-fd": {
|
"coop-fd": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"crane": "crane",
|
"crane": "crane",
|
||||||
|
@ -59,6 +143,42 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"disko": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719733833,
|
||||||
|
"narHash": "sha256-6h2EqZU9bL9rHlXE+2LCBgnDImejzbS+4dYsNDDFlkY=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"rev": "d185770ea261fb5cf81aa5ad1791b93a7834d12c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1708697125,
|
||||||
|
"narHash": "sha256-JeMK8G1oabQTSpqXhYaYtPRak4m6z1xxyRKf8CvHy14=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "empty",
|
||||||
|
"rev": "23d743284b73ae69caf0cb7874edf05c0c631a1f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "empty",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
|
@ -92,6 +212,21 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat_3": {
|
"flake-compat_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1717312683,
|
||||||
|
"narHash": "sha256-FrlieJH50AuvagamEvWMIE6D2OAnERuDboFDYAED/dE=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "38fd3954cf65ce6faf3d0d45cd26059e059f07ea",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat_4": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1696426674,
|
"lastModified": 1696426674,
|
||||||
|
@ -108,6 +243,27 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-parts": {
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719745305,
|
||||||
|
"narHash": "sha256-xwgjVUpqSviudEkpQnioeez1Uo2wzrsMaJKJClh+Bls=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "c3c5ecc05edc7dafba779c6c1a61cd08ac6583e9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts_2": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
},
|
},
|
||||||
|
@ -127,7 +283,25 @@
|
||||||
},
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems_2"
|
"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": {
|
"locked": {
|
||||||
"lastModified": 1705309234,
|
"lastModified": 1705309234,
|
||||||
|
@ -196,9 +370,63 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix-community-infra": {
|
||||||
|
"inputs": {
|
||||||
|
"agenix": "agenix",
|
||||||
|
"buildbot-nix": "buildbot-nix",
|
||||||
|
"comin": "comin",
|
||||||
|
"disko": "disko",
|
||||||
|
"empty": "empty",
|
||||||
|
"flake-compat": "flake-compat_3",
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"nix-darwin": "nix-darwin",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"nixpkgs-update": "nixpkgs-update",
|
||||||
|
"nixpkgs-update-github-releases": "nixpkgs-update-github-releases",
|
||||||
|
"nur-update": "nur-update",
|
||||||
|
"sops-nix": "sops-nix",
|
||||||
|
"srvos": "srvos",
|
||||||
|
"systems": "systems",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719876004,
|
||||||
|
"narHash": "sha256-YIGAUeEVgJ/Qpn+YUoyR9HjV6j01W+5vOKRYpqsx+gw=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "infra",
|
||||||
|
"rev": "766a23a468858d2413f12bec828860158abaadf1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "infra",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nix-darwin": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719128254,
|
||||||
|
"narHash": "sha256-I7jMpq0CAOZA/i70+HDQO/ulLttyQu/K70cSESiMX7A=",
|
||||||
|
"owner": "LnL7",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"rev": "50581970f37f06a4719001735828519925ef8310",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "LnL7",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nix-gaming": {
|
"nix-gaming": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts_2",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
|
@ -255,7 +483,7 @@
|
||||||
"nixos-mailserver": {
|
"nixos-mailserver": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"blobs": "blobs",
|
"blobs": "blobs",
|
||||||
"flake-compat": "flake-compat_3",
|
"flake-compat": "flake-compat_4",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
],
|
||||||
|
@ -297,15 +525,16 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1717922286,
|
"lastModified": 1719824438,
|
||||||
"narHash": "sha256-RsV7rNWYceglPDVgVukwYfoYK2fuAgyvyvSE/Gyah+Y=",
|
"narHash": "sha256-pY0wosAgcr9W4vmGML0T3BVhQiGuKoozCbs2t+Je1zc=",
|
||||||
"owner": "chayleaf",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "47c40a60d0952cd6b86c171898870142b0747602",
|
"rev": "7f993cdf26ccef564eabf31fdb40d140821e12bc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "chayleaf",
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable-small",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
@ -338,6 +567,81 @@
|
||||||
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
|
"url": "https://github.com/NixOS/nixpkgs/archive/eb9ceca17df2ea50a250b6b27f7bf6ab0186f198.tar.gz"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs-update": {
|
||||||
|
"inputs": {
|
||||||
|
"mmdoc": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"empty"
|
||||||
|
],
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"runtimeDeps": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"treefmt-nix": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"treefmt-nix"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719362107,
|
||||||
|
"narHash": "sha256-Vrd+Y3odIIXjlUwSDOjyrhf6V4svB5njtGH9i0NJIxc=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs-update",
|
||||||
|
"rev": "d49fec1752e0bcb69f156a86ba5b93e14aaca2c3",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs-update",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-update-github-releases": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1713252683,
|
||||||
|
"narHash": "sha256-/hWsx6qCMHIRgdGkEIHaI40eVUg5gQGxpfp6GG7moSU=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs-update-github-releases",
|
||||||
|
"rev": "e1a72b5848a3a08168917dee85a6b4b64eca6b24",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs-update-github-releases",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1672428209,
|
||||||
|
"narHash": "sha256-eejhqkDz2cb2vc5VeaWphJz8UXNuoNoM8/Op8eWv2tQ=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "293a28df6d7ff3dec1e61e37cc4ee6e6c0fb0847",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"id": "nixpkgs",
|
||||||
|
"type": "indirect"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1717922286,
|
||||||
|
"narHash": "sha256-RsV7rNWYceglPDVgVukwYfoYK2fuAgyvyvSE/Gyah+Y=",
|
||||||
|
"owner": "chayleaf",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "47c40a60d0952cd6b86c171898870142b0747602",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "chayleaf",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"notlua": {
|
"notlua": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
@ -393,6 +697,48 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nur-update": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1716222588,
|
||||||
|
"narHash": "sha256-gbyIIHsJpk3V8tnsGP8RZpgc0NM/R9QT4zk4SObRDas=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nur-update",
|
||||||
|
"rev": "a54c4c1b0ec643ff36b3c9deecb5fefce57dcabc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nur-update",
|
||||||
|
"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": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"coop-fd": "coop-fd",
|
"coop-fd": "coop-fd",
|
||||||
|
@ -400,22 +746,24 @@
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"impermanence": "impermanence",
|
"impermanence": "impermanence",
|
||||||
"mobile-nixos": "mobile-nixos",
|
"mobile-nixos": "mobile-nixos",
|
||||||
|
"nix-community-infra": "nix-community-infra",
|
||||||
"nix-gaming": "nix-gaming",
|
"nix-gaming": "nix-gaming",
|
||||||
"nix-index-database": "nix-index-database",
|
"nix-index-database": "nix-index-database",
|
||||||
"nixos-hardware": "nixos-hardware",
|
"nixos-hardware": "nixos-hardware",
|
||||||
"nixos-mailserver": "nixos-mailserver",
|
"nixos-mailserver": "nixos-mailserver",
|
||||||
"nixos-router": "nixos-router",
|
"nixos-router": "nixos-router",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs_3",
|
||||||
"nixpkgs-kernel": "nixpkgs-kernel",
|
"nixpkgs-kernel": "nixpkgs-kernel",
|
||||||
"notlua": "notlua",
|
"notlua": "notlua",
|
||||||
"notnft": "notnft",
|
"notnft": "notnft",
|
||||||
"nur": "nur",
|
"nur": "nur",
|
||||||
|
"osu-wine": "osu-wine",
|
||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
"rust-overlay": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils_2",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
|
@ -434,6 +782,52 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sops-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"nixpkgs-stable": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"empty"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719716556,
|
||||||
|
"narHash": "sha256-KA9gy2Wkv76s4A8eLnOcdKVTygewbw3xsB8+awNMyqs=",
|
||||||
|
"owner": "Mic92",
|
||||||
|
"repo": "sops-nix",
|
||||||
|
"rev": "b5974d4331fb6c893e808977a2e1a6d34b3162d6",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "Mic92",
|
||||||
|
"repo": "sops-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"srvos": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719835186,
|
||||||
|
"narHash": "sha256-o0FB8SQVLOnbsYTk2Bt6gXwsfqEv4ZHsGP50/kM/gR0=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "srvos",
|
||||||
|
"rev": "14b3b0aa48fa291f1be26ab8948d5b9eadaed0b8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "srvos",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
|
@ -464,9 +858,60 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"systems_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"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": [
|
||||||
|
"nix-community-infra",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719749022,
|
||||||
|
"narHash": "sha256-ddPKHcqaKCIFSFc/cvxS14goUhCOAwsM1PbMr0ZtHMg=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "8df5ff62195d4e67e2264df0b7f5e8c9995fd0bd",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"utils": {
|
"utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1709126324,
|
"lastModified": 1709126324,
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
inputs = {
|
inputs = {
|
||||||
#nixpkgs.url = "github:NixOS/nixpkgs/3dc2b4f8166f744c3b3e9ff8224e7c5d74a5424f";
|
#nixpkgs.url = "github:NixOS/nixpkgs/3dc2b4f8166f744c3b3e9ff8224e7c5d74a5424f";
|
||||||
# nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
# nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
nix-community-infra.url = "github:nix-community/infra";
|
||||||
nixpkgs-kernel.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs-kernel.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
nixpkgs.url = "github:chayleaf/nixpkgs";
|
nixpkgs.url = "github:chayleaf/nixpkgs";
|
||||||
nixos-hardware.url = "github:NixOS/nixos-hardware";
|
nixos-hardware.url = "github:NixOS/nixos-hardware";
|
||||||
|
@ -16,6 +17,10 @@
|
||||||
url = "github:chayleaf/mobile-nixos/fix-op6-modem";
|
url = "github:chayleaf/mobile-nixos/fix-op6-modem";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
osu-wine = {
|
||||||
|
url = "github:chayleaf/osu-wine.nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
impermanence.url = "github:nix-community/impermanence";
|
impermanence.url = "github:nix-community/impermanence";
|
||||||
nur.url = "github:nix-community/NUR";
|
nur.url = "github:nix-community/NUR";
|
||||||
rust-overlay = {
|
rust-overlay = {
|
||||||
|
|
|
@ -19,6 +19,7 @@ in
|
||||||
|
|
||||||
{
|
{
|
||||||
inherit (inputs.nix-gaming.packages.${pkgs.system}) faf-client osu-lazer-bin;
|
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; };
|
matrix-appservice-discord = pkgs.callPackage ./matrix-appservice-discord { inherit (pkgs) matrix-appservice-discord; };
|
||||||
|
|
||||||
openssh = pkgs.openssh.overrideAttrs (old: rec {
|
openssh = pkgs.openssh.overrideAttrs (old: rec {
|
||||||
|
@ -54,7 +55,6 @@ in
|
||||||
patches = [ ./looking-glass.patch ];
|
patches = [ ./looking-glass.patch ];
|
||||||
});
|
});
|
||||||
mobile-config-firefox = callPackage ./mobile-config-firefox { };
|
mobile-config-firefox = callPackage ./mobile-config-firefox { };
|
||||||
osu-wine = callPackage ./osu-wine { };
|
|
||||||
ping-exporter = callPackage ./ping-exporter { };
|
ping-exporter = callPackage ./ping-exporter { };
|
||||||
proton-ge = pkgs.stdenvNoCC.mkDerivation {
|
proton-ge = pkgs.stdenvNoCC.mkDerivation {
|
||||||
inherit (sources.proton-ge) pname version src;
|
inherit (sources.proton-ge) pname version src;
|
||||||
|
|
|
@ -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
|
|
|
@ -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 <stdarg.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 <stdarg.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -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 <wine/unixlib.h>
|
|
||||||
#include <wine/list.h>
|
|
||||||
|
|
||||||
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[];
|
|
|
@ -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()
|
|
|
@ -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; }
|
|
|
@ -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 <stdarg.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
|
@ -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
|
|
File diff suppressed because it is too large
Load diff
|
@ -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();
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#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);
|
|
||||||
}
|
|
|
@ -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,
|
|
||||||
};
|
|
|
@ -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
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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 <stdarg.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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)
|
|
|
@ -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
|
|
|
@ -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
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 */
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#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);
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 )
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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 <stdarg.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
};
|
|
|
@ -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 <stdarg.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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)
|
|
|
@ -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
|
|
|
@ -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
|
|
File diff suppressed because it is too large
Load diff
|
@ -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
|
|
|
@ -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";
|
|
||||||
}
|
|
|
@ -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)";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -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";
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,207 +0,0 @@
|
||||||
--- a/include/wine/test.h
|
|
||||||
+++ b/include/wine/test.h
|
|
||||||
@@ -28,6 +28,13 @@
|
|
||||||
#include <winbase.h>
|
|
||||||
#include <wine/debug.h>
|
|
||||||
|
|
||||||
+#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 <stdarg.h>
|
|
||||||
+
|
|
||||||
+#include <windef.h>
|
|
||||||
+#include <winbase.h>
|
|
||||||
+#include <winnls.h>
|
|
||||||
+#include <winternl.h>
|
|
||||||
+
|
|
||||||
+#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 \
|
|
|
@ -1,24 +0,0 @@
|
||||||
From 1b5de04e1ae401f2f3d7179da0379191886cdfad Mon Sep 17 00:00:00 2001
|
|
||||||
From: Torge Matthies <tmatthies@codeweavers.com>
|
|
||||||
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
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,292 +0,0 @@
|
||||||
commit 6a033150c36bea6d704b7537c219e9b13b4387ec
|
|
||||||
Author: Rémi Bernon <rbernon@codeweavers.com>
|
|
||||||
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.h>]], [[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 <sys/resource.h>
|
|
||||||
+#include <sys/time.h>]], [[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 <sched.h>
|
|
||||||
#endif
|
|
||||||
+#ifdef HAVE_SYS_TIME_H
|
|
||||||
+#include <sys/time.h>
|
|
||||||
+#endif
|
|
||||||
+#ifdef HAVE_SYS_RESOURCE_H
|
|
||||||
+#include <sys/resource.h>
|
|
||||||
+#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 );
|
|
|
@ -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
|
|
||||||
* ================================== */
|
|
|
@ -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 );
|
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
commit ebf411c1e5f20c6db7962cea587d6169246078e0
|
|
||||||
Author: Rémi Bernon <rbernon@codeweavers.com>
|
|
||||||
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 <dbus/dbus.h>
|
|
||||||
+
|
|
||||||
+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
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
From df72c4d301123c0ea0c33af4bc9d00c47255a664 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Torge Matthies <openglfreak@googlemail.com>
|
|
||||||
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)
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
commit d444330ed7685686f46db7fb8ed1ad0cbec72c7b
|
|
||||||
Author: Rémi Bernon <rbernon@codeweavers.com>
|
|
||||||
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);
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
From: Piotr Caban <piotr@codeweavers.com>
|
|
||||||
Subject: [PATCH v2] server: Don't wait for low level hook result when queuing hardware message.
|
|
||||||
Message-Id: <daf382d3-924e-7c33-c876-5b8d6298c137@codeweavers.com>
|
|
||||||
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 <piotr@codeweavers.com>
|
|
||||||
---
|
|
||||||
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;
|
|
||||||
|
|
|
@ -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; y<prc->Height; y++) {
|
|
||||||
+ srcbyte = srcrow;
|
|
||||||
+ dstpixel = dstrow;
|
|
||||||
+ for (x=0; x<prc->Width; 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)
|
|
|
@ -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)
|
|
|
@ -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;
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 <pthread.h>
|
|
||||||
#include <assert.h>
|
|
||||||
+#include <stdarg.h>
|
|
||||||
|
|
||||||
#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;
|
|
|
@ -1,70 +0,0 @@
|
||||||
From 138916577787bbdf19cf9523b15603f73b4f4472 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Kai Krakow <kai@kaishome.de>
|
|
||||||
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",
|
|
|
@ -1,28 +0,0 @@
|
||||||
From 5c8c060fc9d1d20eebe12da2e6dacddd88c07d82 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Torge Matthies <tmatthies@codeweavers.com>
|
|
||||||
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
|
|
||||||
|
|
|
@ -1,324 +0,0 @@
|
||||||
From ec87cc3742130c138e4caa37084c92c46b9cb9ad Mon Sep 17 00:00:00 2001
|
|
||||||
From: Torge Matthies <openglfreak@googlemail.com>
|
|
||||||
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
|
|
||||||
|
|
|
@ -1,319 +0,0 @@
|
||||||
From a21d85ace24116af87b83738909001c1e7cf87c2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Torge Matthies <tmatthies@codeweavers.com>
|
|
||||||
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 <tmatthies@codeweavers.com>
|
|
||||||
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 <sys/sysinfo.h>
|
|
||||||
#endif
|
|
||||||
+#ifdef HAVE_SYS_SYSCALL_H
|
|
||||||
+# include <sys/syscall.h>
|
|
||||||
+#endif
|
|
||||||
#ifdef HAVE_SYS_SYSCTL_H
|
|
||||||
# include <sys/sysctl.h>
|
|
||||||
#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 <tmatthies@codeweavers.com>
|
|
||||||
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 <mach/mach_init.h>
|
|
||||||
# include <mach/mach_vm.h>
|
|
||||||
+# include <mach/task.h>
|
|
||||||
+# include <mach/thread_state.h>
|
|
||||||
+# include <mach/vm_map.h>
|
|
||||||
#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
|
|
||||||
|
|
|
@ -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;
|
|
|
@ -1,177 +0,0 @@
|
||||||
{ pkgs ? import <nixpkgs> {}, path ? pkgs.path }:
|
|
||||||
## we default to importing <nixpkgs> 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
|
|
||||||
# <source/7.0/wine-7.0.tar.xz> to become <source/7.0.1/wine-7.0.1.tar.xz>.
|
|
||||||
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
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -167,6 +167,17 @@
|
||||||
"nixpkgs-wayland.cachix.org-1:3lwxaILxMRkVhehr5StQprHdEo4IrE8sRho9R9HOLYA="
|
"nixpkgs-wayland.cachix.org-1:3lwxaILxMRkVhehr5StQprHdEo4IrE8sRho9R9HOLYA="
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
nix.buildMachines = [
|
||||||
|
{
|
||||||
|
hostName = "darwin-build-box.nix-community.org";
|
||||||
|
protocol = "ssh-ng";
|
||||||
|
systems = [ "aarch64-darwin" "x86_64-darwin" ];
|
||||||
|
supportedFeatures = inputs.nix-community-infra.darwinConfigurations.darwin01.config.nix.settings.system-features;
|
||||||
|
sshKey = "/secrets/community-builder-key";
|
||||||
|
sshUser = "chayleaf";
|
||||||
|
publicHostKey = "c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUZ6OEZYU1ZFZGY4RnZETWZib3hoQjVWalNlN3kyV2dTYTA5cTFMNHQwOTkgCg==";
|
||||||
|
}
|
||||||
|
];
|
||||||
services.udev.packages = [
|
services.udev.packages = [
|
||||||
pkgs.android-udev-rules
|
pkgs.android-udev-rules
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in a new issue