mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
DualSense haptics and controller speaker sound bluethooth (#969)
* pad: send DualSense speaker and haptic audio over Bluetooth * ci: fix Opus clang-cl build and macOS memory tracker test * docs: remove Bluetooth notes from project README * pad: keep Bluetooth audio work off emulation timing path * pad: smooth DualSense speaker audio on USB and Bluetooth * tests: find available macOS guest range for page manager * pad: keep haptic waveform when Bluetooth queue overflows * audio: reject zero output sample frequency * Simplify DualSense audio routing and fix Bluetooth batching --------- Co-authored-by: Codex <codex@openai.com> Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
@@ -29,6 +29,8 @@ uint32_t oversleep = 0, processing = 0;
|
||||
std::vector<uint32_t> sleeps;
|
||||
std::vector<std::unique_ptr<Stream>> streams;
|
||||
bool fail_open = false, fail_put = false, stalled = false;
|
||||
bool pad_connected = false, pad_bluetooth = false;
|
||||
uint64_t pad_queue_us = 0;
|
||||
int clears = 0;
|
||||
|
||||
Stream& GetStream(SDL_AudioStream* stream) {
|
||||
@@ -136,11 +138,15 @@ int GetActiveControllerId() {
|
||||
|
||||
namespace DualSenseHaptics {
|
||||
Stream* Open(uint32_t, bool) {
|
||||
return nullptr;
|
||||
static int pad_stream;
|
||||
return pad_connected ? reinterpret_cast<Stream*>(&pad_stream) : nullptr;
|
||||
}
|
||||
void Close(Stream*) {}
|
||||
uint64_t Queue(Stream*, int, const void*, uint32_t, uint32_t, bool, const int*) {
|
||||
return 0;
|
||||
bool UsesBluetooth(const Stream* stream) {
|
||||
return stream != nullptr && pad_bluetooth;
|
||||
}
|
||||
uint64_t Queue(Stream* stream, int, const void*, uint32_t, uint32_t, bool, const int*) {
|
||||
return stream != nullptr ? pad_queue_us : 0;
|
||||
}
|
||||
} // namespace DualSenseHaptics
|
||||
} // namespace Libs::Controller
|
||||
@@ -170,6 +176,8 @@ struct Fixture {
|
||||
processing = oversleep = 0;
|
||||
clears = 0;
|
||||
fail_open = fail_put = stalled = false;
|
||||
pad_connected = pad_bluetooth = false;
|
||||
pad_queue_us = 0;
|
||||
sleeps.clear();
|
||||
}
|
||||
|
||||
@@ -336,6 +344,27 @@ void TestFailedQueueUsesFallbackClock() {
|
||||
Check(now - start == 16000, "repeated queue failures reset fallback pacing");
|
||||
}
|
||||
|
||||
void TestControllerSpeakerPacing() {
|
||||
Fixture f;
|
||||
fail_open = true; // No PC audio device paces the pad speaker.
|
||||
pad_connected = true;
|
||||
pad_queue_us = 80000;
|
||||
const auto speaker = f.Open(256, 4);
|
||||
|
||||
pad_bluetooth = true;
|
||||
f.Output(speaker);
|
||||
const auto bluetooth_start = now;
|
||||
f.Output(speaker);
|
||||
Check(now - bluetooth_start >= 5333 && now - bluetooth_start <= 5334,
|
||||
"Bluetooth speaker waited on its HID queue instead of the sample clock");
|
||||
|
||||
pad_bluetooth = false;
|
||||
const auto usb_start = now;
|
||||
f.Output(speaker);
|
||||
Check(now - usb_start >= 5333 && now - usb_start <= 5334,
|
||||
"stalled USB speaker waited longer than one audio block");
|
||||
}
|
||||
|
||||
void TestInvalidBatchSize() {
|
||||
Libs::Audio::AudioOut::AudioOutOutputParam param {};
|
||||
for (const auto count: {0u, 33u}) {
|
||||
@@ -344,6 +373,16 @@ void TestInvalidBatchSize() {
|
||||
"invalid batch size was not rejected before accessing ports");
|
||||
}
|
||||
}
|
||||
|
||||
void TestZeroOutputFrequency() {
|
||||
Fixture f;
|
||||
Check(Libs::Audio::AudioOut::AudioOutOpen(0, 0, 0, 256, 0, 4) ==
|
||||
Libs::Audio::AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ,
|
||||
"public output open accepted zero frequency");
|
||||
Check(!f.audio.AudioOutOpen(10, 256, 0, Audio::Format::FloatStereo).IsValid(),
|
||||
"internal output open accepted zero frequency");
|
||||
Check(f.Open().ToInt() == 1, "rejected output port occupied a handle");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main() {
|
||||
@@ -354,7 +393,9 @@ int main() {
|
||||
TestSynchronizedBatchAndInactivePorts();
|
||||
TestFallbackUsesEachPortsPeriod();
|
||||
TestFailedQueueUsesFallbackClock();
|
||||
TestControllerSpeakerPacing();
|
||||
TestInvalidBatchSize();
|
||||
TestZeroOutputFrequency();
|
||||
Check(streams.empty(), "output stream leaked");
|
||||
std::puts("AudioOutTimingTests: all cases passed");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user