UltraStar-Deluxe / USDX

The free and open source karaoke singing game UltraStar Deluxe, inspired by Sony SingStar™

Home Page:https://usdx.eu

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Windows crashes on certain audio formats

barbeque-squared opened this issue · comments

This is from the top of my head, but there is definitely a difference in how Windows vs Linux handles files they cannot play. I suspect it has to do with Windows using BASS whereas Linux uses FFmpeg.

Linux behaviour:
If Linux encounters an audio file it cannot play (this is usually something that is 24-bit), it:

  • does not play preview audio
  • if you try to sing the song, it just ends immediately

Windows behaviour:
If Windows encounters an audio file it cannot play, it immediately crashes to the desktop. If you have preview audio on, just pressing right, right, right, right in the song collection and it will crash the instant the song gets selected.
I've seen Windows crash on at least:

  • 24-bit
  • some (not all?) flacs (maybe s16 vs s16le or something?)
  • opus

I see two possible solutions:

  1. delete BASS decoder entirely, isn't it shipped with FFmpeg for the videos anyway?
  2. make BASS do the FFmpeg behaviour instead of crashing

Option 1 has my preference because it both gives better behaviour as well as supports more formats, but if that's hard to implement option 2 is also still an improvement over just completely killing the application.

Linux has problems with 24-bit files? Should be easy to fix that.

I never understood why BASS is used on Windows. Was this done to avoid patent issues?

I don’t know the details about why BASS was/is used on Windows, maybe @basisbit or @brunzel know more? It probably makes a lot of sense to get rid of BASS and harmonize the usage of FFMPEG on all three platforms IMHO.

Bass was used for the Windows release because all the other options didn't work back at the time when mp3 was still patented and SDL library had no audio input/output device support itself.

I absolutely favor using ffmpeg for everything that it supports, but I assume that for audio input and output you'll still need bass for Windows, until someone implements the audio input/output support which current version of SDL bring along afaik.

I absolutely favor using ffmpeg for everything that it supports, but I assume that for audio input and output you'll still need bass for Windows, until someone implements the audio input/output support which current version of SDL bring along afaik.

What is wrong with the current implementation in UAudioInput_SDL.pas and UAudioPlayback_SDL.pas? And why did you rule out our PortAudio code?

PortAudio on Windows is a UX nightmare and reliability nightmare. It shows the same input devices multiple times through the different available Windows APIs and doesn't filter for the API with the lowest latency. It would need quite a couple of hours of extra development time to make the portaudio variant properly usable under windows.

SDL doesn't care about the latency when selecting the backend. On Windows it tries WASAPI, DirectSound, and WinMM in that order and uses the first one that works. It will not use more than one backend at the same time. According to this WASAPI is the lowest level API of those three.

On Windows it tries WASAPI, DirectSound, and WinMM in that order and uses the first one that works.

@s09bQ5 Does SDL do this for each input & output device? That would be perfect

Once SDL manages to sucessfully initialize an audio backend, it will only list and use devices of that backend.

😩😩😩
meh, then it is probably not a good option to switch to that. I have already seen a few setups where some mics were only available over WASAPI, and some others only through WinMM/MME.
Guess it is time to open an issue in the SDL issue tracker...

okay, none of this makes any sense.
Locally I use MSYS, the pipeline uses the dpr thing.

I've added some logging to know for sure which audio output is being used.

Both my local builds as well as the CI use Bass for audio output, do mp3 decoding with Bass, and decode other formats with FFMpeg. This works absolutely fine if I use my local build, but it crashes with the CI build.
At a glance, the only differences I can see are in the .exe size -- my local build is under 3MB, the CI one is over 8MB.

I did mess around a bit with my local build with the switches.inc but the furthest I got with that was that it just wasn't playing the song -- the game didn't crash, which is basically the Linux behaviour. Clearly the CI build is doing something different but I don't know what.

Probably relevant output below:

Local build:

fpc -Si -Sg- -Sc- -v0Binwe -Xs- -O2 -k"-z noexecstack" -k" -L/mingw64/lib" -Fi../src/lib/JEDI-SDL/SDL/Pas -Fu. -FU../build/fpc-i386-win32 -o../game/ultrastardx.exe ultrastardx.dpr
Free Pascal Compiler version 3.2.2 [2021/05/15] for i386
Copyright (c) 1993-2021 by Florian Klaempfl and others
Target OS: Win32 for i386
Compiling ultrastardx.dpr

CI:

Info: (lazarus) Executable="c:\newpascal\fpc\bin\i386-win32\fpc.exe"
Info: (lazarus) Param[0]="-B"
Info: (lazarus) Param[1]="-Pi386"
Info: (lazarus) Param[2]="-MObjFPC"
Info: (lazarus) Param[3]="-Si"
Info: (lazarus) Param[4]="-CX"
Info: (lazarus) Param[5]="-Ciro"
Info: (lazarus) Param[6]="-O2"
Info: (lazarus) Param[7]="-gs"
Info: (lazarus) Param[8]="-gl"
Info: (lazarus) Param[9]="-XX"
Info: (lazarus) Param[10]="-vewibq"
Info: (lazarus) Param[11]="-vn-h-"
Info: (lazarus) Param[12]="-FuC:\projects\usdx\src\base"
Info: (lazarus) Param[13]="-FuC:\projects\usdx\src\lua"
Info: (lazarus) Param[14]="-FuC:\projects\usdx\src\media"
Info: (lazarus) Param[15]="-FuC:\projects\usdx\src\menu"
Info: (lazarus) Param[16]="-FuC:\projects\usdx\src\screens"
Info: (lazarus) Param[17]="-FuC:\projects\usdx\src\lib\dglOpenGL"
Info: (lazarus) Param[18]="-FuC:\projects\usdx\src\lib\SDL2"
Info: (lazarus) Param[19]="-FuC:\projects\usdx\src\lib\portaudio"
Info: (lazarus) Param[20]="-FuC:\projects\usdx\src\lib\ffmpeg-3.1"
Info: (lazarus) Param[21]="-FuC:\projects\usdx\src\lib\SQLite"
Info: (lazarus) Param[22]="-FuC:\projects\usdx\src\lib\other"
Info: (lazarus) Param[23]="-FuC:\projects\usdx\src\lib\openCV"
Info: (lazarus) Param[24]="-FuC:\projects\usdx\src\webSDK"
Info: (lazarus) Param[25]="-FuC:\projects\usdx\src\webSDK\encrypt"
Info: (lazarus) Param[26]="-Fuc:\newpascal\lazarus\components\lazutils"
Info: (lazarus) Param[27]="-FuC:\projects\usdx\src\lib\freetype"
Info: (lazarus) Param[28]="-FuC:\projects\usdx\src\lib\bass"
Info: (lazarus) Param[29]="-FuC:\projects\usdx\src\lib\Lua"
Info: (lazarus) Param[30]="-FuC:\projects\usdx\src\screens\controllers"
Info: (lazarus) Param[31]="-FuC:\projects\usdx\src\screens\views"
Info: (lazarus) Param[32]="-FuC:\projects\usdx\src\lib\midi"
Info: (lazarus) Param[33]="-Fuc:\newpascal\lazarus\components\lazutils\lib\i386-win32"
Info: (lazarus) Param[34]="-Fuc:\newpascal\lazarus\packager\units\i386-win32"
Info: (lazarus) Param[35]="-FuC:\projects\usdx\src\"
Info: (lazarus) Param[36]="-FUC:\projects\usdx\build\fpc-i386-win32\"
Info: (lazarus) Param[37]="-FEC:\projects\usdx\game\"
Info: (lazarus) Param[38]="ultrastardx.dpr"
Free Pascal Compiler version 3.1.1 [2017/03/01] for i386
Copyright (c) 1993-2017 by Florian Klaempfl and others
(1002) Target OS: Win32 for i386
(3104) Compiling ultrastardx.dpr

The CI uses a much older Free Pascal version and it has debugging symbols, range checks and integer overflow checks enabled.

There were stack alignment issues on Linux with old Free Pascal versions that affected SSE code in FFMpeg, but Windows never guaranteed 16 byte stack alignment with 32 bit code.

No window with a stack trace when it crashes?
Can you run the executable in a debugger?
Put the .debug files from the game folder next to the DLLs to allow addresses to be resolved.

Does the v2023.5.0 CI build crash on these songs?
Does it crash if you also pass -Ciro to fpc?
Does it crash if you downgrade fpc to 3.1.1?

(sorry, this took a while to get around to)
@s09bQ5

No window with a stack trace when it crashes?

2023-11-27-usdx-opus

the error was taken with the CI version. The last line in Error.log at the time of crashing is this one:

INFO:   Using decoder FFmpeg_Decoder for "C:\Users\bbq\Desktop\usdxportable\UltraStar.Deluxe_v2023dev_portable\songs\Wolfcora Zebry - B??se Stuten\Du bist ein Wunder (Karaoke Version) [f3rfSkBCTT8].opus" [TAudioPlaybackBase.OpenDecodeStream]

Audio file in question is the .opus stream from youtube f3rfSkBCTT8 (but I'm pretty sure any opus will trigger this)

Does the v2023.5.0 CI build crash on these songs?

2023-11-27-usdx-202350

Does it crash if you also pass -Ciro to fpc?

I added -Ciro -gl to the PFLAGS_BASE_DEFAULT line in src/Makefile.in:
2023-11-27-usdx-localcompile-Ciro-gl
the -gl was to get the debug symbols to do anything. If I remove -Ciro again it plays the file just fine

Does it crash if you downgrade fpc to 3.1.1?

I cannot easily test this but considering the above findings I don't think this is related to the fpc version.

Line 1388 in UAudioDecoder_FFmpeg.pas is

BufferPtr := @Buffer[BufferPos];

Buffer is a pointer to a TByteArray and TByteArray is defined as array of 32768 bytes. The disassembly shows that fpc_rangeerror is called in this line when BufferPos is larger than 32767 and that there is no other error checking in this line. Lines 1334, 1357, and 1365 make sure that BufferPos is positive and smaller than BufferSize. So I assume that BASS sometimes passes a buffer that is larger than 32768 bytes. Can you verify that this is the case?

tldr; yes it looks like BASS can pass buffers > 32768 bytes.

For this specific opus file, both with and without -Ciro the ReadData function gets called (the first time) with a BufferSize = 38400.

When it crashes (with -Ciro) at line 1338 BufferPos=33312. This is the 10th time it calls that line.

If I remove -Ciro it also gets called with BufferPos=33312, and even one more iteration with BufferPos=37152. After that the entire function gets called again (BufferSize=28800) and in further calls the BufferSize eventually fluctuates between 19000 and 19400.

I did some extra investigation and the code also works with -Cio aka it is indeed the -Cr option that 'causes' it (more like why is the buffer so big to begin with, but I wouldn't know where to start).

Of course it works if we tell the compiler to stop checking.
But the proper fix would be to change PByteArray to PByte - everywhere there might be a buffer larger than 32768 bytes.

What is the benefit of PByteArray over PByte anyway when Free Pascal allows the array operator to be used on pointers like in C?

I think you're right about the PByte here. I did some searching in the repo and apparently this isn't the first time this has come up; there have been discussions/commits about this in December 2016 and January 2017 which I've listed in chronological order here:
#187
6cac983
#211
#217

I don't know if it was changed before this, but using PByte seems reasonable.

I think I have it fixed, PR incoming.
Funny detail: one of my other test files has always worked fine but the initial buffer size is 35280. This is actually also larger than PByteArray, but the error has never gone off. I'm assuming this is because BufferPos itself is never too big for the -Cr to cause it to fail -- even if it's then totally happy to read bytes it's not supposed to.

The file in question is flac, I also heard from others that some opus file do actually work. Yeah I'd rather we support all of them.