Commit Graph
228 Commits
Author SHA1 Message Date
Adrià a85102910a Merge pull request #13694 from MarcZX10/fix/host-device-changes
fix(libSceAudioOut): reopen the output device the host stopped
2026-10-31 20:31:07 +01:00
Adrià 0da91ea5be Merge pull request #13658 from Gonic0/fix/audioout-host-gain-default-ctor
fix(libSceAudioOut): give HostGainRamp an implicit default constructor
2026-10-31 12:28:18 +01:00
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
Adrià b55fa1b387 Merge pull request #13223 from kyon-eth/feat/audio-out-320-exports
feat(libSceAudioOut): declare 33 callable exports
2026-10-30 23:57:31 +01:00
Nicolas GonzalezandClaude Opus 5.5 06c1bee072 fix(libSceAudioOut): give HostGainRamp an implicit default constructor
AudioOut.cpp resets a port with `port = Port{}`, which copy-list-initializes
its HostGainRamp member. With the default argument on the explicit
constructor, clang rejects that ("chosen constructor is explicit in
copy-initialization"), so libSceAudioOut does not build on macOS. The default
constructor is now separate and implicit; the one taking the ramp length
stays explicit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-30 18:47:47 -03: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 737bcb8f69 refactor(libScePad): own the shared host volume state
The volume, mute and focus state that libSceAudioOut applies and libSceVideoOut changes now lives in libScePad, which both libraries already link, instead of in libSceAudioOut. The tests that compile the state directly and the environment reference follow the file.
2026-10-30 16:29:55 +01: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 22cb1123a0 refactor(libSceAudioOut): give the host volume helpers C linkage
They are called across libraries like the other _nid_no_patch and _nid_postfix helpers, so their symbols must not depend on the C++ mangling of a particular compiler.
2026-10-30 16:29:55 +01:00
MarcZX10 c255f112db feat(libSceAudioOut): apply the host volume where AudioOut2 hands PCM to the device
DeviceCallback applies the context's ramp to the stereo float it just filled, which is the only place the AudioOut2 main mix reaches the speakers; the title's own volumes and the mastering stay before it. At the default volume the ramp is at unity and the call returns without touching the stream. The controller sound card keeps its own path and is not touched.
2026-10-30 16:29:55 +01:00
MarcZX10 1e82fc5a7e feat(libSceAudioOut): give each AudioOut2 context a host gain ramp
Ten milliseconds of the 48 kHz stereo output for a full-scale change.
2026-10-30 16:29:55 +01:00
MarcZX10 0b8656250b feat(libSceAudioOut): apply the host volume where AudioOut queues PCM to SDL
Every non-vibration port goes through HostGainFilter just before SDL_QueueAudio, after the title's volume and channel order. With the default volume the filter returns the title's buffer untouched. Vibration ports go to the controller's sound card and are not touched.
2026-10-30 16:29:55 +01:00
MarcZX10 30cca88304 feat(libSceAudioOut): give every AudioOut port its own host gain ramp
The ramp is ten milliseconds of the port's own frame rate for a full-scale change, and a reopened port starts from unity.
2026-10-30 16:29:55 +01:00
MarcZX10 4957afdb77 build(libSceAudioOut): compile the host volume state into the tests that build AudioOut.cpp
The vibration device, default open and buffer size tests compile AudioOut.cpp directly, so they need the state it will read.
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 31c54b6cb3 feat(libSceAudioOut): keep one shared host volume for the process
The state sits behind a mutex and publishes its gain through an atomic, so the audio threads read it without locking. HostVolumeConfigure replaces the state, parsing ANYPS5_VOLUME and ANYPS5_MUTE_ON_FOCUS_LOSS before changing anything, so an invalid value leaves it untouched and throws an error naming the variable.
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 685ea93a0e feat(libSceAudioOut): word the one-line host volume feedback
The message gives the level, or says the volume is muted by the user or by the window losing focus, always with the level it returns to.
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 2dbb988fae feat(libSceAudioOut): parse the host volume settings strictly
A flag is exactly 0 or 1 and a level a whole number from 0 to 100. Anything else, including an empty value, throws an error that names the variable and quotes the value.
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 cd606d57a1 feat(libSceAudioOut): add a filter that leaves the title's buffer alone
HostGainFilter returns the title's own pointer when the ramp is at unity with a unity target, so the default path copies nothing and multiplies nothing. Otherwise it applies the ramp to a scratch copy, or in place when the data already is the scratch buffer, and never writes the title's memory.
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 eed0017aa0 feat(libSceAudioOut): add the gain ramp for 32-bit float host audio
The float overload uses the same per-frame gain as the 16-bit one, converted exactly from the fixed-point value, and does not clamp. At unity with a unity target it touches nothing.
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 9ba3f5d80a feat(libSceAudioOut): add a gain ramp for 16-bit host audio
HostGainRamp moves a 16.16 fixed-point gain toward its target by a constant step per frame, so the ramp is exact, continues across buffers and applies one gain to every channel of a frame. 16-bit samples are rounded and saturate. At unity with a unity target nothing is touched.
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 7a95f2cefd feat(libSceAudioOut): derive the output gain from the host volume
The gain is a 16.16 fixed-point amplitude of the volume squared, so 100 is exactly unity and 0 is silence. Mute and focus mute force it to 0.
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 4d7b8f0180 feat(libSceAudioOut): track window focus in the host volume
With the option on, a window without focus counts as muted and gaining focus ends it. The focus mute is derived from the focus and the option, so it never replaces the user's own mute. With the option off, focus changes change nothing.
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 dc7fc6b108 feat(libSceAudioOut): let the host volume be set directly
SetVolume takes a value from 0 to 100 for an initial volume and refuses anything else.
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 e2962efdb8 feat(libSceAudioOut): let a volume step end an explicit mute
Raising or lowering the volume while muted unmutes, so the step is audible. A step that cannot move the volume still reports a change when it unmutes.
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 67cb5a3301 feat(libSceAudioOut): add a mute toggle to the host volume
The muted flag is separate from the volume, so unmuting brings back the volume that was set before.
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
MarcZX10 42a4f6b20d feat(libSceAudioOut): add the host volume state with fixed steps
HostVolume holds the host output volume from 0 to 100 and moves it in steps of 5 without leaving the range. A move that changes nothing returns false.
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 ccaac6602b fix(libSceAudioOut): reopen a controller sound card the host stopped
A vibration port plays through the controller's own sound card, such as
a DualSense over Bluetooth. When the backend disables that device, SDL
keeps the port's device disabled until it is closed (see the default
output fix), so the port's haptic audio stopped for the rest of the run.

Before a vibration port's device is used, close it and open the
controller sound card again when its status is stopped. A failed reopen
leaves the port with no device, so its output runs as a virtual port,
as a vibration port opened with no controller card does today. Such a
port is not retried later.
2026-10-30 13:58:28 +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
Kyon e4b274109f feat(libSceAudioOut): declare 33 callable exports 2026-10-30 07:02: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