Commit Graph
147 Commits
Author SHA1 Message Date
MarcZX10 2bdcad1490 Merge upstream/main into fix/host-device-changes 2026-10-30 23:52:24 +00:00
MarcZX10 1c4cfe546e test(libSceAudioOut): keep the queue target check in the default open harness
The default open harness counted SDL_QueueAudio calls by target and no
longer required the device id, so a queue to the wrong device passed in
every mode. Keep the requirement; it is lifted only while the disconnect
mode has removed the default output, where the counts check the target.
No existing mode queues audio, so their results are unchanged.
2026-10-30 23:49:32 +00:00
MarcZX10 9b6c28b8bd Merge upstream/main into fix/host-device-changes
Bring the branch up to the current upstream main. The only conflict was the
AudioOut debt doc, where both sides added a Functional entry; both are kept.
2026-10-30 19:52:07 +00:00
MarcZX10 4e06acd31a test(libSceAudioOut): answer the device status query in two harnesses
The output path now asks SDL for the status of a port's device. The port
lock and resampling harnesses link the shared library with fake device
IDs, and without a stub the status query reaches the real SDL, which
reports an unknown ID as stopped. The port then reopened its device and
the harnesses' expectations about the calls they see broke.

Both harnesses answer the query as playing, as the other AudioOut
harnesses that stub the device functions do.
2026-10-30 19:45:35 +00:00
MarcZX10 14b0b4b5f2 refactor(libScePad): move the host volume headers from libSceAudioOut
libSceVideoOut reads and changes the shared host volume state, and linking libSceAudioOut for it puts a second shared library with its own static SDL2 into libSceVideoOut. Both libraries already link libScePad, so the headers that describe that state move there first; the include paths and guards follow.
2026-10-30 16:29:55 +01:00
MarcZX10 b8f692f88f test(libSceAudioOut): cover rounding and upward ramps of the 16-bit host gain
Halves round toward positive, and a ramp from silence back to unity never falls, stays within the slope and lands exactly on unity.
2026-10-30 16:29:55 +01:00
MarcZX10 e68a8008b2 test(libSceAudioOut): cover the shared host volume, its settings and its focus rule
Register audio_out_host_volume_state. Covers the unity default, each command publishing its gain, focus acting only with the option on, initial values, a refused configuration leaving the state alone, both variables read from the environment with the invalid one named, and readers never seeing a gain above unity while commands run.
2026-10-30 16:29:55 +01:00
MarcZX10 49d4cd5d9b test(libSceAudioOut): cover the host volume feedback lines
Level at the default and after a step, the user's mute, the focus mute, and the user's mute taking precedence.
2026-10-30 16:29:55 +01:00
MarcZX10 0034db7a8c test(libSceAudioOut): cover accepting and refusing the host volume settings
Accepts 0 and 1 for the flag and 0 to 100 for the level; refuses empty, padded, signed, fractional, out-of-range and overflowing values with the variable named.
2026-10-30 16:29:55 +01:00
MarcZX10 98d5899f44 test(libSceAudioOut): cover the host gain filter's bypass and copy rules
At unity the title's pointer comes back and nothing is copied, a changed gain works on a copy and leaves the title's buffer as it was, and the scratch buffer is processed in place.
2026-10-30 16:29:55 +01:00
MarcZX10 049cf7c80f test(libSceAudioOut): cover the float host gain on mono, stereo and 8 channels
Covers the byte-for-byte bypass at unity, the first sample and landing frame matching the 16-bit ramp, no step above the slope, a ramp split across buffers, and the absence of clamping.
2026-10-30 16:29:55 +01:00
MarcZX10 fc729b1f4a test(libSceAudioOut): cover the 16-bit host gain on mono, stereo and 8 channels
Register audio_out_host_gain. Covers the byte-for-byte bypass at unity, the exact first sample and landing frame of a ramp, no step larger than the ramp slope, a ramp split across buffers equal to one buffer, saturation above unity, one gain per frame on every channel, a silent gain, and the return to bypass.
2026-10-30 16:29:55 +01:00
MarcZX10 0c5e8f4fec test(libSceAudioOut): cover the gain derived from the host volume
Unity at the default, 16384 at 50, strictly growing and never above unity, and 0 while muted or focus muted.
2026-10-30 16:29:55 +01:00
MarcZX10 a0dd35ca5f test(libSceAudioOut): cover the focus mute transitions
Covers the option off, a focus loss and gain with it on, the user's own mute and volume surviving a round trip, and the option changing while the window is unfocused.
2026-10-30 16:29:55 +01:00
MarcZX10 a42c4ecb0b test(libSceAudioOut): cover setting the host volume directly
Values 0 to 100 are taken, anything else is refused without changing the state, and the mute is left alone.
2026-10-30 16:29:55 +01:00
MarcZX10 e729d8fbf5 test(libSceAudioOut): cover volume steps ending a mute
Both directions unmute, including at 0 and at 100 where the volume itself cannot move.
2026-10-30 16:29:55 +01:00
MarcZX10 a5a8a4ba74 test(libSceAudioOut): cover mute and unmute restoring the volume
Muting at 100, at 90 and at 0 keeps the volume, and unmuting returns it.
2026-10-30 16:29:54 +01:00
MarcZX10 2c0f6a8174 test(libSceAudioOut): cover the host volume steps and their limits
Register audio_out_host_volume. It starts at 100, moves in steps of 5 in both directions, and refuses to leave 0 to 100.
2026-10-30 16:29:54 +01:00
Adrià 01069f4d2b Merge pull request #12954 from hugodearaujo/fix/audioout2-blocking-push
fix(libSceAudioOut): return from a blocking AudioOut2 push once the queue has room
2026-10-30 15:45:36 +01:00
MarcZX10 5f55ca31f1 test(libSceAudioOut): cover the controller sound card reopen after a host stop
The vibration harness gains a disconnect mode. It opens a vibration port
on the controller sound card, reports that card as stopped, and writes
one buffer. The output must open the card again, queue the PCM into the
new device and never into the stopped one, then close both devices with
the port.

On a tree without the reopen the mode fails at "the stopped controller
sound card was not reopened".
2026-10-30 13:59:24 +00:00
MarcZX10 503fe9a8c4 test(libSceAudioOut): cover the default output reopen after a host stop
The default-open harness gains a disconnect mode. It opens the main port
on the default output, reports that device as stopped, and writes one
buffer. The output must open a replacement device, queue into it and
never queue into the stopped one, then close both devices with the port.

On a tree without the reopen the mode fails at "the removed default
output was not replaced".
2026-10-30 13:58:01 +00:00
MarcZX10 b87075aad9 fix(libSceAudioOut): reopen the default output after the host stops it
SDL marks an opened device as disabled when the backend reports it lost
(SDL_OpenedAudioDeviceDisconnected in src/audio/SDL_audio.c of the
bundled 3rdparty/SDL2 at 4b69833bc). The flag is set back only when a
device is opened again, so a disabled device stays silent until it is
closed, and SDL_GetAudioDeviceStatus reports SDL_AUDIO_STOPPED.

AudioOut never checked that status for a port's default output, so
after the output went away the title's audio stayed silent for the rest
of its run while every output call still returned success.

Before a default-output port is used, reopen its device when its status
is stopped. A failed reopen leaves the port with no device, so it runs
as a virtual port, as a port opened with no output does today. Such a
port is not retried later.
2026-10-30 13:57:41 +00:00
Adrià a36ff7f47e Merge pull request #12584 from Biologisten/fix/audio-pad-speaker-mute
feat(audio): add controller speaker fallback override
2026-10-30 07:12:28 +01:00
hugodearaujo 56fd9eac87 Merge main into fix/audioout2-blocking-push
# Conflicts:
#	core/libs/prx/libSceAudioOut/src/AudioOut2Context.cpp
2026-10-30 03:03:08 -03:00
Adrià 4628011bc8 Merge pull request #12727 from XairRrR/fix-audioout-context-handles
fix(libSceAudioOut): reject AudioOut2 context handles that are not live contexts
2026-10-30 05:51:47 +01:00
hugodearaujo 3fc5485e6c test(libSceAudioOut): keep the timing test includes sorted 2026-10-29 22:17:42 -03:00
hugodearaujo 107e3c5f76 test(libSceAudioOut): run the test-clock push tests before the live-clock one 2026-10-29 22:15:42 -03:00
hugodearaujo 2aca989548 test(libSceAudioOut): hold a blocking push on a test clock until playback frees a slot
A device-less context can run its queue model on a clock the test sets. With the clock frozen, a blocking push that fills the queue is seen still waiting with its grain queued and not counted, and returns once the test plays one grain; a blocking push that meets a queue filled by non-blocking pushes does not queue past the depth.
2026-10-29 22:14:23 -03:00
Adrià 7a225bb303 Merge pull request #12686 from MarcZX10/feat/pad-rumble-intensity
feat(libSceVideoOut): add ANYPS5_RUMBLE to scale or turn off host controller vibration
2026-10-29 23:46:17 +01:00
AdriàandClaude Sonnet 5.5 1ed07de320 test(libSceAudioOut): assert the blocking push level, not elapsed time; note destroy during a push is unsupported
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-29 18:43:12 +01:00
AdriàandClaude Sonnet 5.5 bb6d79e52e test(libSceAudioOut): drop the comment above the blocking push test
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-29 18:11:39 +01:00
hugodearaujo 42beeaa468 fix(libSceAudioOut): return from a blocking AudioOut2 push once the queue has room
A blocking sceAudioOut2ContextPush waited only before queueing its grain, so the push that filled the queue returned at once. PRAGMATA's Wwise feeds its context from a thread that pushes and then wakes the renderer; the renderer sees a full queue, sleeps, and is woken again only by the game's next RenderAudio, so the mix advanced four grains per game frame. A blocking push now also waits after queueing until a grain finishes, bounded by the existing 200 ms limit.
2026-10-29 12:39:32 -03:00
slopgobblercobbler 120b2036a5 fix(libSceAudioOut): validate open format parameter and virtual port buffer boundaries 2026-10-29 14:27:50 +01:00
XairRrR 03decdabe0 fix(libSceAudioOut): reject AudioOut2 context handles that are not live contexts
An AudioOut2 context handle was the host pointer itself, and every
sceAudioOut2Context* call and sceAudioOut2PortCreate only rejected 0. A
second sceAudioOut2ContextDestroy of the same handle deleted the context
twice, Push, Advance, GetQueueLevel and SetAttributes on a destroyed
context used freed memory, and PortCreate accepted any nonzero value and
kept it as the port's context, so the next PCM attribute on that port read
the grain size through it.

Live contexts are now kept in a set: ContextCreate adds the context,
ContextDestroy removes it before releasing it, and the other context calls
and PortCreate return SCE_AUDIO_OUT2_ERROR_INVALID_HANDLE for a handle that
is not in the set. The queue level test that passed a stack object as a
handle now uses a created context with its device closed.

AI-assisted: yes
2026-10-29 06:38:00 +01:00
Biologisten 80df59b666 test(audio): isolate AudioOut2 tests from APS5_PAD_SPEAKER_FALLBACK_DB
CreateContext() reads the variable, so a value exported in the developer's shell reached the AudioOut2 tests: garbage aborted seven of the sixty audio tests and -15 broke the unity fold in audio_out2_port_layouts. Every test that creates a context now unsets the variable at the start of main(), and the tests that exercise it set it themselves.

Throws() now takes the exception type it expects, so the two port checks still require std::invalid_argument while the environment check requires std::runtime_error. The rejection error keeps the original pointer to the value, so a value with leading whitespace is reported verbatim and the test checks the name=value prefix.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-10-29 05:46:33 +01:00
MarcZX10 208375142d test(libSceAudioOut): cover the actuator percentage of AudioOut2WritePadFrames
Check on the quad and pulse layouts that 100 and above write the same bytes as the call without a percentage, that 0 silences exactly the actuator channels, that 50 halves them, and that the speaker and unmapped channels are never touched.
2026-10-29 02:06:36 +00:00
Biologisten 315050d000 fix(audio): reject invalid APS5_PAD_SPEAKER_FALLBACK_DB values and read the gain once
A set-but-invalid value, including an empty one, a non-finite number, a
number outside -60 to 0 or trailing text, stops the title with an error
naming the variable and the value instead of silently keeping 0 dB. The
gain is parsed once when the AudioOut2 context is created, kept in the
context and passed to the mix loop, so the audio thread never reads the
environment.

The one-read rule is pinned end to end: a play that changes the variable
to a value that would stop the title after the context was created keeps
the parsed fold and never re-reads the environment.
2026-10-29 00:16:16 +01:00
Biologisten 84b5542fdc feat(audio): add controller speaker fallback override
Add APS5_PAD_SPEAKER_FALLBACK_DB for AudioOut2 controller-speaker ports
folded into the main mix when no controller speaker is present. The
default 0 dB keeps the existing unity mix; mute removes the fallback
copy so a title's own main-port copy is heard instead.
2026-10-29 00:16:16 +01:00
SeaSunPTandClaude Opus 5.5 9f6c3527ed fix(libSceAudioOut): refuse system debug state and chat calls before sceAudioOut2Initialize
#9838 read sceAudioOut2SetSystemDebugState in PS5 firmware 3.20 and 4.03:
it returns 0x80268006 (not initialized) before sceAudioOut2Initialize,
ahead of its pointer, id and size checks. The debt entry for
sceAudioOut2EnableChat and sceAudioOut2DisableChat records the same
0x80268006 before AudioOut2 initialization. Both were left out while
AudioOut2 initialization was not tracked; AudioOut2IsInitialized_nid_no_patch
now tracks it, so all three return 0x80268006 first and change no state.
The two debt entries drop the closed gap.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-28 12:56:22 +00:00
Dean a1f5ae4e8b Merge pull request #11244 from SeaSunPT/fix/audioout2-mastering-not-initialized
fix(libSceAudioOut): refuse sceAudioOut2Mastering calls before sceAudioOut2Initialize
2026-10-28 13:02:46 +13:00
Dean 091967e234 Merge pull request #11055 from JJenkx/fix/audioout2-device-queue-poll
fix(audioout2): poll device queues without the callback mutex
2026-10-28 13:02:30 +13:00
Dean 6c48f35a95 Merge pull request #8098 from LuisAguilarDev/fix/audioout2-silent-ports
fix(audioout2): keep each port's grain when ports share a buffer
2026-10-28 12:59:20 +13:00
Dean 7461dd1ed3 Merge pull request #10532 from LeandroLP23/fix/audioout-skip-open-without-output-devices
fix(libSceAudioOut): skip the default open only when Windows reports no default output endpoint
2026-10-28 02:31:48 +13:00
Dean fc7e583e6e Merge pull request #11035 from orezraey/fix/libsceaudioout-repeated-init-measured-ps5
fix(libSceAudioOut): fail a repeated sceAudioOut2Initialize and sceAudioOutInit as measured on a PS5
2026-10-27 09:16:48 +13:00
SeaSunPTandClaude Opus 5.5 d736ea814e Merge branch 'main' into fix/audioout2-mastering-not-initialized
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-26 15:34:06 +00:00
SeaSunPTandClaude Opus 5.5 4128be2f60 fix(libSceAudioOut): refuse sceAudioOut2Mastering calls before sceAudioOut2Initialize
The PS5 module read for #9027 returns 0x80268006 from sceAudioOut2MasteringInit,
sceAudioOut2MasteringInitEx, sceAudioOut2MasteringTerm,
sceAudioOut2MasteringGetState and sceAudioOut2MasteringSetParam before
sceAudioOut2Initialize. #9027 left the check out because AudioOut2
initialization was not tracked; AudioOut2IsInitialized_nid_no_patch now
tracks it, so each of these returns 0x80268006 first, before its own
mastering-state and argument checks, and changes no state. The debt entry
drops the closed gap.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 22:07:11 +00:00
Dean Galvin 91039afff1 Merge branch 'main' into feat/audioout-set-main-output 2026-10-26 09:57:37 +13:00
orezraeyandClaude Opus 5.5 9925a9e401 fix(libSceAudioOut): fail a repeated sceAudioOut2Initialize and sceAudioOutInit as measured on a PS5
On PS5 firmware 13.60 a second sceAudioOut2Initialize returns 0x80268004,
also after sceAudioOutInit, and a second sceAudioOutInit returns
0x8026000e. sceAudioOutInit after sceAudioOut2Initialize still returns 0.
sceAudioOut2InitializeEx and sceAudioOut2LoInit keep returning 0; their
repeats were not measured.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 11:36:01 -03:00
JJenkx fef6f77622 fix(audioout2): poll device queue levels without the callback mutex 2026-10-25 10:34:14 -04:00
LeandroLP23andClaude Opus 5.5 e63a51c93a fix(libSceAudioOut): confirm the missing WASAPI endpoint before skipping the open
SDL's WASAPI enumeration drops failures silently: EnumAudioEndpoints or
GetCount errors leave the list empty, and a device whose metadata lookup
fails is left out, so an empty list does not prove there is no default
endpoint. The skip now also requires IMMDeviceEnumerator's
GetDefaultAudioEndpoint(eRender, eConsole), the call SDL's default open
makes, to return ERROR_NOT_FOUND. The probe runs only when the wasapi list
is empty.

audio_out_default_open gains wasapi_zero_default (empty WASAPI list, the
probe finds an endpoint, the default is opened) and checks that the probe
runs only for an empty WASAPI list.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 10:50:38 +01:00