Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Threads & "AL lib: (EE) alc_cleanup: 1 device not closed"  (Read 10927 times)

0 Members and 2 Guests are viewing this topic.

disaux

  • Newbie
  • *
  • Posts: 5
    • View Profile
Threads & "AL lib: (EE) alc_cleanup: 1 device not closed"
« on: November 09, 2015, 01:55:42 pm »
Hello community,

I'm new to programming with SFML and so far I really like this library.

I'm looking for a way to generate a beep tone with a certain frequency, which is played without blocking the rest of my program. I tried to start Sound.play() in a thread.

The problem is that it doesn't always actually play the sound and the program terminates with the message "AL lib: (EE) alc_cleanup: 1 device not closed" each time. Especially fixing the error message exceeds my understanding so I hope some of you guys have way more clue than I do :-)

Here's my code:

soundgenerator.h
Quote
#ifndef SOUNDGENERATOR_H
#define SOUNDGENERATOR_H
#include <SFML/Audio.hpp>

class SoundGenerator
{
public:
    SoundGenerator(double frequency, int amplitude, int duration);  // constructor
    void playSound();  // invokes a new thread

private:
    int duration;    // how long to play the sound
    sf::SoundBuffer buffer;     // storing the buffer as a member variable
    void playSoundThread(sf::SoundBuffer buffer);    // this fkt runs in a thread
};

#endif // SOUNDGENERATOR_H

soundgenerator.cpp
(taken from this tutorial: https://github.com/SFML/SFML/wiki/Tutorial:-Play-Sine-Wave)
Quote
#include "soundgenerator.h"
#include <SFML/Audio.hpp>
#include <cmath>
#include <thread>

// set up the parameters for the sine wave
SoundGenerator::SoundGenerator(double frequency, int amplitude, int duration)
{
    this->duration = duration;

    const unsigned SAMPLES = 44100;
    const unsigned SAMPLE_RATE = 44100;
    const unsigned AMPLITUDE = amplitude;

    sf::Int16 raw[SAMPLES];

    const double TWO_PI = 6.28318;
    const double increment = frequency/44100;
    double x = 0;
    for (unsigned j = 0; j < SAMPLES; j++) {
        raw[j] = (int)AMPLITUDE * sin(x*TWO_PI);
        x += increment;
    }

    if (!this->buffer.loadFromSamples(raw, SAMPLES, 1, SAMPLE_RATE)) {
        return;
    }
}

// here the thread is being invoked
void SoundGenerator::playSound()       
{
    std::thread t(&SoundGenerator::playSoundThread, this, this->buffer);
    t.detach();
}

// this function is put in the thread
void SoundGenerator::playSoundThread(sf::SoundBuffer buf)
{
    sf::Sound sound;
    sound.setBuffer(buf);
    sound.setLoop(true);
    sound.play();
    sf::sleep(sf::milliseconds(duration));
}

main.cpp
Quote
void main()
{
    // frequency=400 hz, amplitude=25000, duration=2000ms
    SoundGenerator* sg = new SoundGenerator(400, 25000, 2000);
    sg->playSound();

    ... going into a OpenGL loop, waiting for user input and stuff...
}

I'd be grateful for any suggestions! I'm using SFML 2.3.1 with QT 5.5 with QT Creator as IDE.

Cheers,
Dietmar
« Last Edit: November 09, 2015, 02:21:09 pm by disaux »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Threads & "AL lib: (EE) alc_cleanup: 1 device not closed"
« Reply #1 on: November 09, 2015, 02:01:13 pm »
sf::Sound and sf::Music are using threads themselves so there's no need for you to launch your own thread.

As for the error, you need to give the main thread a bit more time to sleep, since there's an overhead for launching and destroying a second thread. If you only let it sleep for the duration of the audio, the main thread will most likely close before the child thread ends.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

disaux

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Threads & "AL lib: (EE) alc_cleanup: 1 device not closed"
« Reply #2 on: November 09, 2015, 02:19:18 pm »
Hi, thank you for your reply!

Indeed, I've read about that they are using their own thread. But that seems to apply for playing music files only...? Maybe because I'm using values from a Buffer?

When I execute Sound.play() e. g. from the main loop of my OpenGL application (or any other terminating function), it will not play the sound. Doesn't matter whether Sound.play() runs within a separate threaded function or not. If I add sf::sleep() afterwards, it will play the sound while sleeping but the program is blocked. So I've put it all into a thread.

I will try your suggestion about the thread termination time!
Edit: Actually the main thread launches bunch of other code, in real it's waiting for a user input. So it does not terminate before the thread does.

Cheers
« Last Edit: November 09, 2015, 02:40:10 pm by disaux »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Threads & "AL lib: (EE) alc_cleanup: 1 device not closed"
« Reply #3 on: November 09, 2015, 03:43:17 pm »
Well do you allow the sound to be played or are you just exiting the main thread?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

disaux

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Threads & "AL lib: (EE) alc_cleanup: 1 device not closed"
« Reply #4 on: November 09, 2015, 10:55:52 pm »
semantically, the main thread is not exited before the sound could play. Consider that this is just an mock-up. In my real code I have something like this:

warning: pseudocode!
Quote
void main_loop()
{
    sleep(1/60 seconds);
    do_stuff();
}

// is called 60 times a second
void do_stuff()
{
    ... // building the sound object
    // play sound each 600/60=10 seconds
    if (loop_counter % 600== 0)
    {
        sound.play()
        loop_counter++;
    }
    ... // operations that will finish in <1 ms
}

I can see that the scope from which sound.play() is started, is destroyed when do_stuff() terminates. Could this be why the sound does not play if I don't put a sleep() after sound.play()?
« Last Edit: November 09, 2015, 10:58:08 pm by disaux »

Arcade

  • Full Member
  • ***
  • Posts: 230
    • View Profile
Re: Threads & "AL lib: (EE) alc_cleanup: 1 device not closed"
« Reply #5 on: November 10, 2015, 12:36:37 am »
Is your sf::SoundBuffer going out of scope (being destroyed) before the sound has finished playing? The code fragments you provided make it seem like this could be the case. The SoundBuffer needs to exist as long as the sound is using it.

disaux

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: Threads & "AL lib: (EE) alc_cleanup: 1 device not closed"
« Reply #6 on: November 10, 2015, 03:10:28 pm »
thank you for your advice, that actually helped a lot! I also realized that I don't need to sleep() because I can define the playback duration by increasing SAMPLES. Now the error message does not occur anymore (unless I force the program to stop executing by IDE). The program still crashes at the end, probably due to my usage of the audio lib, but I'll investigate that later.