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

Author Topic: AL lib: (EE) alc_cleanup: 1 device not closed  (Read 16086 times)

0 Members and 3 Guests are viewing this topic.

oddikaro

  • Newbie
  • *
  • Posts: 5
    • View Profile
AL lib: (EE) alc_cleanup: 1 device not closed
« on: July 09, 2021, 10:35:57 pm »
Hi all,

working with SMFL nuget package in .NET 5. I am experiencing 3 issues related with Sound:

1. When I close the window, the console shows this message:
AL lib: (EE) alc_cleanup: 1 device not closed

This is "not an issue" but would like to make it dissappear. I have tried using Sound.SoundBuffer.Dispose() and Sound.Dispose() when the window is closing. However, that does not seem to work in all situations. I think it mainly depends if the Sound instance belongs to the Game class (the one that has the event handler function when window is closing) or to another class (e.g., Player).

For instance, if I want to dispose Player's Sound's instance from Game's close window event handler function, it does not work (the message appears):


class Game{

...
public Player Player { get; set; }
...

        private void Window_Closed(object sender, EventArgs e)
        {
            Player.SoundBuffer.Dispose();
            Player.Sound.Dispose();
            (sender as RenderWindow).Close();


        }
 

In this same project, I have detected one exception

2. When I close the window "at the same time" the sound is going to play, an exception occurs in:

Sound.Play(); // System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'

It is not easy to reproduce this exception since I need to just close the window in a very specific time (seems so).

Maybe it is trying to run Play() when the Dispose() has already been executed (becasue the window has been closed from another class)¿? API comments state that Play uses another thread so maybe it is trying to access some data already deleted.

If you have any ideas, they are welcome!


eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: AL lib: (EE) alc_cleanup: 1 device not closed
« Reply #1 on: July 11, 2021, 03:54:39 pm »
working with SMFL nuget package in .NET 5. I am experiencing 3 issues related with Sound:
What happened to the third issue? :D

Can you provide a complete and minimal example, so I can test it on my side without spending time coming up with a reproducible example? :)

Also can you try changing the disposal order of buffer and sound, to see if the order has any effect?

There's still an open issue regarding music disposal causing crashes, but I think that's probably unrelated: https://github.com/SFML/SFML.Net/issues/179
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

oddikaro

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: AL lib: (EE) alc_cleanup: 1 device not closed
« Reply #2 on: July 13, 2021, 11:54:08 am »
I was creating a new instance elsewhere of the sound shape and I did not dispose its sound instance.

That was the issue. The message no longer appears and i tried to re-create the exception but seems no exception happens so far.

Sorry for the inconvenience, and thank you for the willing to help!!!

oddikaro

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: AL lib: (EE) alc_cleanup: 1 device not closed
« Reply #3 on: July 13, 2021, 02:03:39 pm »
Well, after trying for a while...exceptions do still occur. The message "AL lib: (EE) alc_cleanup: 1 device not closed" does not appear but there are exceptions if you close the window just when the ball is hitting and emitting its sound.

This is the code to reproduce the issue:

1. Create a new console app (.NET 5) in VSC2019.
2. Add SFML.NET nuget package to your project.
3. Add some ballHitSound.wav sample into you project's folder. You can find many sounds here: https://www.epidemicsound.com/sound-effects/search/?term=ball%20hit?term=ball%20hit. For instance "Ping Pong Ball Hit 4", i think that is the same as I am using.

4. Copy paste this code:

using SFML.Audio;
using SFML.Graphics;
using SFML.System;
using SFML.Window;
using System;

namespace MovingBall
{

    class Program
    {
        const int WINDOW_WIDTH = 50;
        const int WINDOW_HEIGHT = 50;

        static void Main(string[] args)
        {
            Game pg = new Game(WINDOW_WIDTH, WINDOW_HEIGHT, "Bouncing ball example");


            // Create a moving ball
            Random rand = new Random(1);
            float radius = 20.0f;// rand.Next(5, 30);
            Vector2f velocity = new Vector2f(rand.Next(100,1000), rand.Next(100, 1000));
            pg.CreateBall(radius, velocity);

            pg.Run();
        }
    }

    class Game
    {

        public string Title { get; set; }

        public VideoMode VideoMode { get; set; }

        public RenderWindow Window { get; set; }

        public Ball Ball { get; set; }

        /// <summary>
        /// Create a game with empty window
        /// </summary>
        public Game(uint windowWidth, uint windowHeight, string title)
        {
            Title = title;
            VideoMode = new VideoMode(windowWidth, windowHeight);
            Window = new RenderWindow(VideoMode, Title, Styles.Close);
            // Comment/uncomment does not matter, the issue happens either way
            //Window.SetVerticalSyncEnabled(true);
            //Window.SetFramerateLimit(60);

            Window.Closed += Window_Closed;
            Window.KeyPressed += Window_KeyPressed;

        }

        public void CreateBall(float radius, Vector2f velocity)
        {
            Ball = new Ball(radius, velocity, Window.Size.X, Window.Size.Y);
        }

        /* Window events */

        private void Window_Closed(object sender, EventArgs e)
        {
            // The exception occurs no matter the order of disposing...
            Ball.SoundBuffer.Dispose();
            Ball.Sound.Dispose();

            (sender as RenderWindow).Close();
        }

        private void Window_KeyPressed(object sender, KeyEventArgs e)
        {
            if (e.Code == Keyboard.Key.Escape)
            {
                (sender as RenderWindow).Close();
            }
        }

        /* Main loop */
        public void Run()
        {
            Clock clock = new Clock();
            Time delta = Time.Zero;
            while (Window.IsOpen)
            {


                // EVENTS
                // Check now all events (e.g., window close)
                Window.DispatchEvents();

                // Get elapsed time since last frame
                delta = clock.Restart();

                // UPDATE (positions, etc.)
                Ball.Update(delta, Window.Size.X, Window.Size.Y);


                // DRAW ELEMENTS
                Window.Clear();
                Window.Draw(Ball.Shape);

                // DISPLAY
                Window.Display();
            }
        }

    }


    class Ball
    {
        private uint _pointCount = 100;
        public CircleShape Shape { get; set; }
        public Vector2f Velocity { get; set; }

        public Sound Sound { get; set; }
        public SoundBuffer SoundBuffer { get; set; }

        public Ball(float radius, Vector2f velocity, uint windowWidth, uint windowHeight)
        {
            // Shape
            Shape = new CircleShape(radius, _pointCount);
            Shape.FillColor = Color.Red;

            // Sound (when hits something)
            SoundBuffer = new SoundBuffer("../../../ballHitSound.wav");
            Sound = new Sound(SoundBuffer);

            // Set origin to its center
            Shape.Origin = new Vector2f(Shape.GetLocalBounds().Width / 2.0f, Shape.GetLocalBounds().Height / 2.0f);

            // Set initial position to center of the window
            Shape.Position = new Vector2f(windowWidth / 2.0f, windowHeight / 2.0f);

            // Set speed
            Velocity = velocity;

        }

        public void Update(Time delta, uint windowWidth, uint windowHeight)
        {

            // Get current location borders of the ball
            // (Top-left, Top-right, top-top, top-bottom)
            float left = Shape.Position.X - Shape.Radius;
            float right = Shape.Position.X + Shape.Radius;
            float top = Shape.Position.Y - Shape.Radius;
            float bottom = Shape.Position.Y + Shape.Radius;

            // Check if current ball's boundaries are out of window's limits
            // If that is the case, change sign of speed and play the hit sound
            if ((left <= 0 && Velocity.X < 0) || (right >= windowWidth && Velocity.X > 0))
            {
                Velocity = new Vector2f(Velocity.X * -1, Velocity.Y);
                Sound.Play();
            }
            if ((top <= 0 && Velocity.Y < 0) || (bottom >= windowHeight && Velocity.Y > 0))
            {
                Velocity = new Vector2f(Velocity.X, Velocity.Y * -1);
                Sound.Play();
            }

            // Move
            Shape.Position += new Vector2f(delta.AsSeconds() * Velocity.X, delta.AsSeconds() * Velocity.Y);
        }

    }



}

 


Now, you can try to get the issue by closing the window just when the ball hits the walls. The easiest way is of course using a ball larger than the window size (so the hitting sound is happening at a very high frequency and the exception "System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'" will happen always.

In console window the error shown is:
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Repeat 2 times:
--------------------------------
   at SFML.Audio.Sound.sfSound_play(IntPtr)
--------------------------------
   at SFML.Audio.Sound.Play()
   at MovingBall.Ball.Update(SFML.System.Time, UInt32, UInt32)
   at MovingBall.Game.Run()
   at MovingBall.Program.Main(System.String[])

I may try the same in C++ and see what happens.
« Last Edit: July 13, 2021, 02:10:17 pm by oddikaro »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: AL lib: (EE) alc_cleanup: 1 device not closed
« Reply #4 on: July 13, 2021, 02:12:16 pm »
This can kind of make sense, since in a first step your event processing disposes the sound objects and then in the Ball Update function, you still try to use the already disposed sound instances.

Instead of manually disposing the objects at a "random" place, you should either use using to automatically define a usage block and auto disposal afterwards.
Or what probably works better in your scenario is implementing the IDisposable interface on your Ball (and Game) class and dispose the sound and sound buffer at the end of life of the Ball instance.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

oddikaro

  • Newbie
  • *
  • Posts: 5
    • View Profile
Re: AL lib: (EE) alc_cleanup: 1 device not closed
« Reply #5 on: July 13, 2021, 06:01:42 pm »
This can kind of make sense, since in a first step your event processing disposes the sound objects and then in the Ball Update function, you still try to use the already disposed sound instances.

Instead of manually disposing the objects at a "random" place, you should either use using to automatically define a usage block and auto disposal afterwards.
Or what probably works better in your scenario is implementing the IDisposable interface on your Ball (and Game) class and dispose the sound and sound buffer at the end of life of the Ball instance.

Yes, you are right! Thank you!

I have changed the code as suggested. Ball class is now "IDisposable" with a single method for it:
        public void Dispose()
        {
            Console.WriteLine("Dispoing....");
            SoundBuffer.Dispose();
            Sound.Dispose();
        }
 

Then, just after the main while loop, I just call Dispose():

        /* Main loop */
        public void Run()
        {
            Clock clock = new Clock();
            Time delta = Time.Zero;
            while (Window.IsOpen)
            {

                // EVENTS
                // Check now all events (e.g., window close)
                Window.DispatchEvents();

                // Get elapsed time since last frame
                delta = clock.Restart();

                // UPDATE (positions, etc.)
                Ball.Update(delta, Window.Size.X, Window.Size.Y);

                // DRAW ELEMENTS
                Window.Clear();
                Window.Draw(Ball.Shape);

                // DISPLAY
                Window.Display();
            }

            Ball.Dispose();
        }
 

This is fine now.

In case you are more experienced, could you share if there is a "better" approach? For instance, documentation suggests substantial different implementations of Dispose:

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: AL lib: (EE) alc_cleanup: 1 device not closed
« Reply #6 on: October 10, 2021, 06:29:00 pm »
My .NET experience is more with enterprise software, so I'm not sure what's best for "high-performance" C# code. Personally, I've never really called Dispose myself outside of an IDisposable implementation, instead I recommend to use a using var myObject = new MyObject() which will automatically call dispose, see here: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/