mackron / miniaudio

Audio playback and capture library written in C, in a single source file.
https://miniaud.io
Other
4.07k stars 361 forks source link

Miniaudio waiting infinitely when calling ma_engine_uninit #823

Closed Lazrius closed 8 months ago

Lazrius commented 8 months ago

Heya. I am having an issue using Miniaudio where the program hangs when trying to terminate.

Project Context:

The summary is that I have a MoviePlayer class that handles the rendering of frames (using FFMPEG) and playing of audio (using miniaudio). When this class is being deconstructed, I call the relevent cleanup functions, but when it gets around to calling ma_engine_uninit, it tries to clean up the device which waits forever for a thread to terminate that never does. This leads to my application closing correctly, but actually existing in the background and never properly terminating.

I am using the following ma_ types:

My constructor looks like so:

MoviePlayer()
{
    stopwatch = new TimeUtils::Stopwatch();

    ma_engine_init(nullptr, &engine);
    ma_engine_set_volume(&engine, 0.4f);
}

My destructor looks like the following:

        ~MoviePlayer()
        {
            delete stopwatch;

            if (currentPlayingMovie.has_value())
            {
                StopMovie();
            }

            // Unregister movies
            for (auto& data : movies | std::views::values)
            {
                ma_audio_buffer_uninit(&data.audioBufferWrapper);
            }

            ma_engine_uninit(&engine);
        }

The audio buffer is constructed like so:

            auto audioBufferConfig = ma_audio_buffer_config_init(format,
                                                                 audioStream->codecpar->ch_layout.nb_channels,
                                                                 data.audioBuffer.size() / audioStream->codecpar->ch_layout.nb_channels,
                                                                 data.audioBuffer.data(),
                                                                 nullptr);

            audioBufferConfig.sampleRate = decoderContext->sample_rate / 2;
            ma_audio_buffer_init(&audioBufferConfig, &data.audioBufferWrapper);

In the destructor StopMovie calls ma_sound_stop(&miniAudioSound); and ma_sound_uninit(&miniAudioSound);, as well as other FFMPEG functions for the video encoding. I have been looking at this for a really long time, and have not seen anything in the documentation that might indicate why this is happening.

The callstack looks like the following when it tries to termiante:

    ntdll.dll!770f671c()    Unknown
    [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
    KernelBase.dll!75671d08()   Unknown
    KernelBase.dll!75671c72()   Unknown
    Movie.dll!ma_thread_wait__win32(void * * pThread) Line 16372    C++
    Movie.dll!ma_thread_wait(void * * pThread) Line 16563   C++
    Movie.dll!ma_device_uninit(ma_device * pDevice) Line 42151  C++
    Movie.dll!ma_engine_uninit(ma_engine * pEngine) Line 75189  C++
    Movie.dll!MoviePlayer::~MoviePlayer() Line 226  C++
    .......

If you have any ideas or need any more information please do say. Thank you very much for your project.

Lazrius commented 8 months ago

While putting together a minimal example, I have come across this stackoverflow post, which seems to be the root cause.

Closing this as it's not directly related to miniaudio, but it might be a helpful thing to add a note of this to the readme! Thanks again, sorry for bothering.