Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[raudio] Crash when changing playback device #3743

Open
thabetx opened this issue Jan 20, 2024 · 4 comments
Open

[raudio] Crash when changing playback device #3743

thabetx opened this issue Jan 20, 2024 · 4 comments
Labels
bug This is a bug

Comments

@thabetx
Copy link

thabetx commented Jan 20, 2024

Issue description

Example (audio_sound_loading.c) crashes when changing playback device,.

Environment

This happens on Windows.

Initialization Logs

INFO: Initializing raylib 5.1-dev
INFO: Platform backend: DESKTOP (GLFW)
INFO: Supported raylib modules:
INFO: > rcore:..... loaded (mandatory)
INFO: > rlgl:...... loaded (mandatory)
INFO: > rshapes:... loaded (optional)
INFO: > rtextures:. loaded (optional)
INFO: > rtext:..... loaded (optional)
INFO: > rmodels:... loaded (optional)
INFO: > raudio:.... loaded (optional)
INFO: DISPLAY: Device initialized successfully
INFO: > Display size: 1600 x 900
INFO: > Screen size: 800 x 450
INFO: > Render size: 800 x 450
INFO: > Viewport offsets: 0, 0
INFO: GLAD: OpenGL extensions loaded successfully
INFO: GL: Supported extensions count: 230
INFO: GL: OpenGL device information:
INFO: > Vendor: Intel
INFO: > Renderer: Intel(R) UHD Graphics
INFO: > Version: 3.3.0 - Build 27.20.100.8190
INFO: > GLSL: 3.30 - Build 27.20.100.8190
INFO: GL: VAO extension detected, VAO functions loaded successfully
INFO: GL: NPOT textures extension detected, full NPOT textures supported
INFO: GL: DXT compressed textures supported
INFO: GL: ETC2/EAC compressed textures supported
INFO: GL: ASTC compressed textures supported
INFO: PLATFORM: DESKTOP (GLFW): Initialized successfully
INFO: TEXTURE: [ID 1] Texture loaded successfully (1x1 | R8G8B8A8 | 1 mipmaps)
INFO: TEXTURE: [ID 1] Default texture loaded successfully
INFO: SHADER: [ID 1] Vertex shader compiled successfully
INFO: SHADER: [ID 2] Fragment shader compiled successfully
INFO: SHADER: [ID 3] Program shader loaded successfully
INFO: SHADER: [ID 3] Default shader loaded successfully
INFO: RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)
INFO: RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)
INFO: RLGL: Default OpenGL state initialized successfully
INFO: TEXTURE: [ID 2] Texture loaded successfully (128x128 | GRAY_ALPHA | 1 mipmaps)
INFO: FONT: Default font loaded successfully (224 glyphs)
INFO: AUDIO: Device initialized successfully
INFO: > Backend: miniaudio / WASAPI
INFO: > Format: 32-bit IEEE Floating Point -> 32-bit IEEE Floating Point
INFO: > Channels: 2 -> 2
INFO: > Sample rate: 48000 -> 48000
INFO: > Periods size: 1440
INFO: FILEIO: [resources/sound.wav] File loaded successfully
INFO: WAVE: Data loaded successfully (44100 Hz, 16 bit, 1 channels)
INFO: FILEIO: [resources/target.ogg] File loaded successfully
INFO: WAVE: Data loaded successfully (22050 Hz, 16 bit, 2 channels)
INFO: TIMER: Target time per frame: 16.667 milliseconds

Also note that miniaudio has a similar example (simple_playback.c) that doesn't have an issue with switching playback devices.

Issue Screenshot

Code_diNg0dzx5J.mp4

Code Example

This happened to me on some personal projects and happens with the audio_sound_loading example.

@raysan5 raysan5 added the bug This is a bug label Jan 31, 2024
@raysan5
Copy link
Owner

raysan5 commented Jan 31, 2024

@thabetx Thanks for reporting, raudio initializes some buffers internally and the player thread, probably the crash is related to some missing mutex or not properly managing the device change... It requires some review.

@veins1
Copy link
Contributor

veins1 commented Feb 4, 2024

I looked into this a bit and here's what I found:
in miniaudio.h -> ma_context_get_MMDevice__wasapi there is a call to ma_CoCreateInstance . It works initially on launch of the program when it's called from the main thread.
When default audio device is changed ma_context_get_MMDevice__wasapi is eventually called from ma_IMMNotificationClient_OnDefaultDeviceChanged callback, from a different thread, which causes ma_CoCreateInstance to fail, because there was no ma_CoInitializeEx call from this thread.
I haven't debug miniaudio simple_playback.c example, so I don't know how it works there.

@CalvinWilkinson
Copy link

Quick question @raysan5.

I looked into miniaudio and noticed that it can return a list of audio devices and to use a particular device. I currently do not see that feature in raylib. Is that something that we could get added to raylib?

I have an audio library that I built called CASL that my 2D game framework Velaptor uses for audio. Currently, CASL provides the ability to enumerate audio devices and switch to them. I was hoping to be able to use RayLib for audio under the hood in CASL instead of what it currently uses which is OpenAL.

Would this possibly be a feature added into RayLib?

@CalvinWilkinson
Copy link

CalvinWilkinson commented Feb 5, 2024

Here is some info to possibly help with this.

Using this sample, I created a quick app to get familiar with how sound is done with RayLib using the C# binding project.

In my Windows system, I have the built-in system audio which is a Realtek Audio device. I also have a pair of Sony noise-canceling headphones which is the WH-1000XM5 model.

I connected the headphones and played the sample project and everything worked great. As the sound was playing, I turned off the headphones. I expected the app to crash, but to my surprise, it did not and just automatically started playing through the Realtek Audio device on the laptop. I also turned the headphones back on and it automatically changed from the laptop audio device back to the Sony headphones with no issue.

I hope this helps you out!!

Extra info:
OS: Windows 11 PRO 23H2 (OS Build 22631.3085)
C#/dotnet: v8.0

Example Source Code Used

using Raylib_cs;

const int screenWidth = 800;
const int screenHeight = 450;

Raylib.InitWindow(screenWidth, screenHeight, "Sound Testing");

Raylib.InitAudioDevice();

var music = Raylib.LoadMusicStream("Content/Audio/brinstar.mp3");

Raylib.PlayMusicStream(music);

var timePlayed = 0f;
var pause = false;

music.Looping = true;

Raylib.SetTargetFPS(30);

while (!Raylib.WindowShouldClose())
{
    Raylib.UpdateMusicStream(music);

    // Restart music playing (stop and play)
    if (Raylib.IsKeyPressed(KeyboardKey.Space))
    {
        Raylib.StopMusicStream(music);
        Raylib.PlayMusicStream(music);
    }

    // Pause/Resume music playing
    if (Raylib.IsKeyPressed(KeyboardKey.P))
    {
        pause = !pause;

        if (pause)
        {
            Raylib.PauseMusicStream(music);
        }
        else
        {
            Raylib.ResumeMusicStream(music);
        }
    }

    if (Raylib.IsKeyPressed(KeyboardKey.Right))
    {
        var currentPosition = Raylib.GetMusicTimePlayed(music);
        var newPosition = currentPosition + 10;
        Raylib.SeekMusicStream(music, newPosition);
    }

    if (Raylib.IsKeyPressed(KeyboardKey.Left))
    {
        var currentPosition = Raylib.GetMusicTimePlayed(music);
        var newPosition = currentPosition - 10;
        Raylib.SeekMusicStream(music, newPosition);
    }

    // Get normalized time played for current music stream
    timePlayed = Raylib.GetMusicTimePlayed(music)/Raylib.GetMusicTimeLength(music);

    if (timePlayed > 1.0f) timePlayed = 1.0f;   // Make sure time played is no longer than music
    //----------------------------------------------------------------------------------

    // Draw
    //----------------------------------------------------------------------------------
    Raylib.BeginDrawing();

    Raylib.DrawText("MUSIC SHOULD BE PLAYING!", 255, 150, 20, Color.LightGray);

    Raylib.DrawRectangle(200, 200, 400, 12, Color.LightGray);
    Raylib.DrawRectangle(200, 200, (int)(timePlayed*400.0f), 12, Color.Maroon);
    Raylib.DrawRectangleLines(200, 200, 400, 12, Color.Gray);

    Raylib.DrawText("PRESS SPACE TO RESTART MUSIC", 215, 250, 20, Color.LightGray);
    Raylib.DrawText("PRESS P TO PAUSE/RESUME MUSIC", 208, 280, 20, Color.LightGray);

    Raylib.EndDrawing();
}

// De-Initialization
//--------------------------------------------------------------------------------------
Raylib.UnloadMusicStream(music);   // Unload music stream buffers from RAM
Raylib.CloseAudioDevice();         // Close audio device (music streaming is automatically stopped)
Raylib.CloseWindow();              // Close window and OpenGL context
//--------------------------------------------------------------------------------------

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This is a bug
Projects
None yet
Development

No branches or pull requests

4 participants