summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compile.bat4
-rw-r--r--src/nomute.c108
2 files changed, 111 insertions, 1 deletions
diff --git a/compile.bat b/compile.bat
index f48453e..c275cb0 100644
--- a/compile.bat
+++ b/compile.bat
@@ -73,6 +73,7 @@ setlocal DisableDelayedExpansion
:+ hook.c
:+ kv.c
:+ l4dwarp.c
+:+ nomute.c
:+ nosleep.c
:+ portalcolours.c
:+ rinput.c
@@ -102,7 +103,8 @@ if "%dbg%"=="1" (
set clibs=-lmsvcrt -lvcruntime -lucrt
)
%CC% -shared -flto %ldflags% -Wl,/IMPLIB:.build/sst.lib,/Brepro,/nodefaultlib ^
--L.build %clibs% -lkernel32 -luser32 -ladvapi32 -lshlwapi -ld3d9 -ltier0 -lvstdlib -o sst.dll%objs% .build/dll.res || exit /b
+-L.build %clibs% -lkernel32 -luser32 -ladvapi32 -lshlwapi -ld3d9 -ldsound ^
+-ltier0 -lvstdlib -o sst.dll%objs% .build/dll.res || exit /b
:: get rid of another useless file (can we just not create this???)
del .build\sst.lib
diff --git a/src/nomute.c b/src/nomute.c
new file mode 100644
index 0000000..861062a
--- /dev/null
+++ b/src/nomute.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2023 Willian Henrique <wsimanbrazil@yahoo.com.br>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+// TODO(linux): this is currently only built on Windows, but a linux
+// implementation would be also useful for some games e.g. L4D2
+
+#include "con_.h"
+#include "errmsg.h"
+#include "feature.h"
+#include "hook.h"
+#include "intdefs.h"
+#include "mem.h"
+#include "os.h"
+#include "sst.h"
+#include "x86.h"
+#include "x86util.h"
+
+// these have to come after Windows.h (via os.h) and in this order
+#include <mmeapi.h>
+#include <dsound.h>
+
+FEATURE("inactive window audio control")
+
+DEF_CVAR_UNREG(snd_mute_losefocus,
+ "Keep playing audio while tabbed out (SST reimplementation)", 1,
+ CON_ARCHIVE | CON_HIDDEN)
+
+static IDirectSoundVtbl *ds_vt = 0;
+static typeof(ds_vt->CreateSoundBuffer) orig_CreateSoundBuffer;
+static con_cmdcbv1 snd_restart_cb = 0;
+
+// early init (via VDF) happens before config is loaded, and audio is set up
+// after that, so we don't want to run snd_restart the first time the cvar is
+// set, unless we were loaded later with plugin_load, in which case audio is
+// already up and running and we'll want to restart it every time
+bool skiprestart;
+static void losefocuscb(struct con_var *v) {
+ if (!skiprestart) snd_restart_cb();
+ skiprestart = false;
+}
+
+static long __stdcall hook_CreateSoundBuffer(IDirectSound *this,
+ const DSBUFFERDESC *desc, IDirectSoundBuffer **buff, IUnknown *unk) {
+ if (!con_getvari(snd_mute_losefocus)) {
+ ((DSBUFFERDESC *)desc)->dwFlags |= DSBCAPS_GLOBALFOCUS;
+ }
+ return orig_CreateSoundBuffer(this, desc, buff, unk);
+}
+
+PREINIT {
+ if (con_findvar("snd_mute_losefocus")) return false;
+ con_reg(snd_mute_losefocus);
+ return true;
+}
+
+INIT {
+ skiprestart = sst_earlyloaded; // see above
+ IDirectSound *ds_obj = 0;
+ if (DirectSoundCreate(NULL, &ds_obj, NULL) != DS_OK) {
+ errmsg_errorx("couldn't create IDirectSound instance");
+ return false;
+ }
+
+ ds_vt = ds_obj->lpVtbl;
+ if (!os_mprot(&ds_vt->CreateSoundBuffer, sizeof(void *), PAGE_READWRITE)) {
+ errmsg_errorx("couldn't make virtual table writable");
+ return false;
+ }
+
+ ds_obj->lpVtbl->Release(ds_obj);
+
+ orig_CreateSoundBuffer = ds_vt->CreateSoundBuffer;
+ ds_vt->CreateSoundBuffer = &hook_CreateSoundBuffer;
+ snd_mute_losefocus->base.flags &= ~CON_HIDDEN;
+
+ struct con_cmd *snd_restart = con_findcmd("snd_restart");
+ if (snd_restart) {
+ snd_restart_cb = con_getcmdcbv1(snd_restart);
+ snd_mute_losefocus->cb = &losefocuscb;
+ }
+ else {
+ errmsg_warnx("couldn't find snd_restart");
+ errmsg_note("changing snd_mute_losefocus will require changing other "
+ "audio settings or restarting the game with SST autoloaded in "
+ "order to have an effect");
+ }
+
+ return true;
+}
+
+END {
+ ds_vt->CreateSoundBuffer = orig_CreateSoundBuffer;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80