Thread: FMOD - Crash on Closure Releasing Resources

  1. #1
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465

    FMOD - Crash on Closure Releasing Resources

    In an initialization routine, I have the code

    Code:
        HRSRC hrsrc = ::FindResource( NULL, MAKEINTRESOURCE(IDB_ORIGINALSONG), TEXT("BIN") );
        HGLOBAL rsc = ::LoadResource( NULL, hrsrc );
        LPVOID lock = ::LockResource( rsc );
        DWORD size  = ::SizeofResource( NULL, hrsrc );
    
        FMOD::System * fmodSystem = 0;
        FMOD_CREATESOUNDEXINFO fmodExInfo = { 0 };
    
        fmodExInfo.cbsize   = sizeof( FMOD_CREATESOUNDEXINFO );
        fmodExInfo.length   = size;
    
        fmodSystem = m_parent.getFmodSystem();
        
        fmodSystem->createSound( LPCSTR(lock), FMOD_OPENMEMORY, &fmodExInfo, &m_sound );
        fmodSystem->playSound( FMOD_CHANNEL_FREE, m_sound, false, &m_channel );
    And in the destruction routine, that will be called when the app is closed, I say.

    Code:
        m_channel->stop();
        m_sound->release();
    It crashes somewhere inside of the release of my m_sound.

    Could it have anything to do with this: http://support.microsoft.com/default...b;en-us;193678 Because my destruction things go from lowest level things up to the top, which would destroy the HWND before getting to releasing the sound. I thought that FMOD makes a copy of everything. But, um, am I right? Anyone have any ideas?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    I would say that since you create m_sound, then m_channel, that you should release in m_channel then m_sound order.

    > playSound( FMOD_CHANNEL_FREE, m_sound, false, &m_channel );
    This is what effectively tells you which depends on which.
    A channel is created based on the sound, so you need to finish with the channel before you finish with the sound.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    >> A channel is created based on the sound, so you need to finish with the channel before you finish with the sound.

    >> I would say that since you create m_sound, then m_channel, that you should release in m_channel then m_sound order.

    Is that conflicting logic? Well, whatever way I order those two statements, it crashes. If the stopping of the m_channel is before the release of the m_sound, there is no error, and either way, it just crashes in m_sound->release();

    I don't touch the m_sound, or m_channel pointer at any point outside the init / deinit. And I don't believe that freeresource thing is of any consequence anymore, as the FMOD system does internally convert the mp3 into it's own format elsewhere.

    Edit: But to be clear, I thought I'd say/reiterate that the crash only occurs when I exit while a sound is playing.
    Last edited by Tonto; 12-26-2006 at 01:33 PM.

  4. #4
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    Okay. New data for you peepz. Figgurredd out how to use fmod_error.h and got some infoz.

    Apparently Channel::stop first complains that I give it an invalid object handle, and then it crashes trying to release the sound as always. Here's how it goes.

    Code:
        // Initialization
    
        FMOD_RESULT f;
    
        HRSRC hrsrc = ::FindResource( NULL, MAKEINTRESOURCE(IDB_ORIGINALSONG), TEXT("BIN") );
        HGLOBAL rsc = ::LoadResource( NULL, hrsrc );
        LPVOID lock = ::LockResource( rsc );
        DWORD size  = ::SizeofResource( NULL, hrsrc );
    
        FMOD::System * fmodSystem = 0;
        FMOD_CREATESOUNDEXINFO fmodExInfo = { 0 };
    
        fmodExInfo.cbsize   = sizeof( FMOD_CREATESOUNDEXINFO );
        fmodExInfo.length   = size;
    
        fmodSystem = m_parent.getFmodSystem();
    
        f = fmodSystem->createSound( LPCSTR(lock), FMOD_OPENMEMORY, &fmodExInfo, &m_sound );
        if( f != FMOD_OK )
        {
            dout << FMOD_ErrorString(f) << "\n";
        }
        f = fmodSystem->playSound( FMOD_CHANNEL_FREE, m_sound, false, &m_channel );
        if( f != FMOD_OK )
        {
            dout << FMOD_ErrorString(f) << "\n";
        }
    
        dout << m_sound << " " << m_channel << "\n"; // Prints 0a4f7e10 10630002
    }


    Code:
        // Cleanup
    
        dout << m_sound << " " << m_channel << "\n"; // Prints 0a4f7e10 10630002
        FMOD_RESULT f;
        
        f = m_channel->stop();
        if( f != FMOD_OK )
        {
            dout << FMOD_ErrorString(f) << "\n"; // Prints an invalid object handle was used. 
        }
    
        f = m_sound->release();
        if( f != FMOD_OK )
        {
            dout << FMOD_ErrorString(f) << "\n";
        }
    Wierd?

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    As with all things, have you tried to repeat this in a small standalone program which can be easily analysed?

    > dout << m_sound
    A better name for a debug stream would be
    doh << m_sound
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    DOH << ENDL;

    Order of destructors. Blah. I was close()'ing the system before I stopped playing music and released the sound. If a mod sees it fit, they can split this thread, but I have a related question, about opening it in non-blocking mode instead.

    Code:
        struct fmod_system
        {
            FMOD::System * fsystem;
            FMOD::Sound * fsound;
            FMOD::Channel * fchannel;
    
            fmod_system()
            {
                FMOD_RESULT result;
    
                result = FMOD::System_Create( &fsystem );
                if (result != FMOD_OK)
                {
                    cout << TEXT("FMOD: ") << FMOD_ErrorString(result) << endl;
                }
    
                result = fsystem->init(10, FMOD_INIT_NORMAL, 0);
                if (result != FMOD_OK)
                {
                    cout << TEXT("FMOD: ") << FMOD_ErrorString(result) << endl;
                }
    
                FMOD_CREATESOUNDEXINFO exInfo = { 0 };
    
                exInfo.cbsize           = sizeof( FMOD_CREATESOUNDEXINFO );
                exInfo.nonblockcallback = asyncOpen;
    
                result = fsystem->createSound( "C:\\Documents and Settings\\Tonto\\My Documents\\Visual Studio 2005\\Projects\\Base\\Base\\Black Fire.mp3", 
                    FMOD_DEFAULT | FMOD_NONBLOCKING, &exInfo, &fsound );
    
                if( result != FMOD_OK )
                {
                    cout << TEXT("FMOD: ") << FMOD_ErrorString(result) << endl;
                }
    
                FMOD_OPENSTATE open_state;
                unsigned int percent, i = 0;
    
                do
                {
                    fsystem->update();
    
                    result = fsound->getOpenState( &open_state, &percent, 0 );
                    if( result == FMOD_OK )
                    {
                        cout << TEXT("FMOD: ") << open_state << TEXT(" ") << percent << TEXT("\n");
                    }
                    else
                    {
                        cout << TEXT("FMOD: ") << FMOD_ErrorString(result) << TEXT("\n");
                        break;
                    }
    
                    ::Sleep( 100 );
                }
                while( !g_thang );
    
                result = fsystem->playSound( FMOD_CHANNEL_FREE, fsound, false, &fchannel );
                if( result != FMOD_OK )
                {
                    cout << TEXT("FMOD: ") << FMOD_ErrorString(result) << endl;
                }
                cout << "HERE!\n";
            }
            ~fmod_system()
            {
                fchannel->stop();
                fsound->release();
                fsystem->release();
            }
        } system;
    And then this

    Code:
    static bool g_thang = false;
    FMOD_RESULT F_CALLBACK asyncOpen( FMOD_SOUND * sound, FMOD_RESULT result )
    
    {
        FMOD::Sound * cppsound = reinterpret_cast< FMOD::Sound * >( sound );
        g_thang = true;
    
        return result;
    }
    When FMOD finishes loading the sound asynchronously, then it calls my callback routine, where I set a global variable. This is a wierd design I know, but the callback doesn't have access to the FMOD::System pointer so I can't do anything more useful. Anyways, two things are wierd about that code:

    1) When I do not have the Sleep(x) in there, then that loop will never stop, and apparently FMOD will never load the sound. If I force myself out of that loop with a break, right after I exit it FMOD loads the sound just fine. So, if the Sleep(x) isn't there, the sound doesn't load.
    2) The getOpenState doesn't do squat. It tells me that the FMOD_OPENSTATE is always FMOD_LOADING, and the percent buffered is always 0. And then, somehow the callback is called and it says it's done, without ever telling me anything. Mind you, it's not the sleep that skipped over the loading process or anything, it sits for a good couple seconds before it's loaded. Here's what the docs say:

    Code:
    Sound::getOpenState
    Retrieves the state a sound is in after FMOD_NONBLOCKING has been used to open it, or the state of the streaming buffer.  
    
    Syntax
    
    FMOD_RESULT Sound::getOpenState(
      FMOD_OPENSTATE *  openstate, 
      unsigned int *  percentbuffered, 
      bool *  starving
    );
    
    Parameters
    
    openstate
    
    Address of a variable that receives the open state of a sound. Optional. Specify 0 or NULL to ignore. 
    
    percentbuffered
    
    Address of a variable that receives the percentage of the file buffer filled progress of a stream. Optional. Specify 0 or NULL to ignore. 
    
    starving
    
    Address of a variable that receives the starving state of a sound. If a stream has decoded more than the stream file buffer has ready for it, it will return TRUE. Optional. Specify 0 or NULL to ignore. 
    
     
    
    Return Values
    
    If the function succeeds then the return value is FMOD_OK.
    If the function fails then the return value will be one of the values defined in the FMOD_RESULT enumeration.
    Note: The return value will be the result of the asynchronous sound create. Use this to determine what happened if a sound failed to open.
    
    Remarks
    
    When a sound is opened with FMOD_NONBLOCKING, it is opened and prepared in the background, or asynchronously.
    This allows the main application to execute without stalling on audio loads.
    This function will describe the state of the asynchronous load routine. I.e. whether it has succeeded or failed.
    Sorry the docs aren't online. So, it doesn't -- seem -- like I'm doing anything wrong. But it's definitely wierd. Any thoughts about this?
    Last edited by Tonto; 12-29-2006 at 02:52 PM.

  7. #7
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    This is getting wierd. I check in my loop with Sound::getOpenState that percent != 100 && g_thang != true, yet it still breaks out of the loop, when clearly the sound is still not ready!

    Code:
    #include "fmod.hpp"
    #include "fmod_errors.h"
    
    using namespace std;
    
    static bool g_thang = false;
    
    FMOD_RESULT F_CALLBACK asyncOpen( FMOD_SOUND * sound, FMOD_RESULT result )
    
    {
        cout << "OMG!\n";
    
        FMOD::Sound * cppsound = reinterpret_cast< FMOD::Sound * >( sound );
        g_thang = true;
    
        return result;
    }
    
    struct fmod_system
    {
        FMOD::System * fsystem;
        FMOD::Sound * fsound;
        FMOD::Channel * fchannel;
    
        fmod_system()
        {
            FMOD_RESULT result;
    
            result = FMOD::System_Create( &fsystem );
            if (result != FMOD_OK)
            {
                cout << TEXT("FMOD: ") << FMOD_ErrorString(result) << endl;
            }
    
            result = fsystem->init(10, FMOD_INIT_NORMAL, 0);
            if (result != FMOD_OK)
            {
                cout << TEXT("FMOD: ") << FMOD_ErrorString(result) << endl;
            }
    
            FMOD_CREATESOUNDEXINFO exInfo = { 0 };
    
            exInfo.cbsize           = sizeof( FMOD_CREATESOUNDEXINFO );
            exInfo.nonblockcallback = asyncOpen;
    
            result = fsystem->createSound( "C:\\Black Fire.mp3", 
                FMOD_DEFAULT | FMOD_NONBLOCKING, &exInfo, &fsound );
    
            if( result != FMOD_OK )
            {
                cout << TEXT("FMOD 1: ") << FMOD_ErrorString(result) << endl;
            }
    
            FMOD_OPENSTATE open_state;
            unsigned int percent = 0, i = 0;
    
            do
            {
                result = fsound->getOpenState( &open_state, &percent, 0 );
                if( result == FMOD_OK )
                {
                    cout << TEXT("FMOD 2: ") << open_state << TEXT(" ") << percent << TEXT("\n");
                }
                else
                {
                    cout << TEXT("FMOD 3: ") << FMOD_ErrorString(result) << TEXT("\n");
                    break;
                }
    
                fsystem->update();
            }
            while( percent != 100 && g_thang != true );
    
            result = fsystem->playSound( FMOD_CHANNEL_FREE, fsound, false, &fchannel );
            if( result != FMOD_OK )
            {
                cout << TEXT("Percent loaded: ") << percent << endl << TEXT("FMOD 4: ") << FMOD_ErrorString(result) << endl;
            }
        }
        ~fmod_system()
        {
            fchannel->stop();
            fsound->release();
            fsystem->release();
        }
    };
    
    
    int main()
    {
        fmod_system system;
    }
    Output

    Code:
    FMOD 2: OMG!
    1 0
    Percent loaded: 0
    FMOD 4: Operation could not be performed because specified sound is not ready.
    Why am I being informed that the sound is complete when it isn't?
    Last edited by Tonto; 01-07-2007 at 03:08 AM.

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    The only thing I can suggest is a look around (and perhaps ask) here -> http://www.fmod.org/forum
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User Tonto's Avatar
    Join Date
    Jun 2005
    Location
    New York
    Posts
    1,465
    If that not extremely funky that it get's out of the loop with percent not being 100? I'm going to go through the debugging to see what led to that happening.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Windows Programs Note Releasing Resources
    By bartybasher in forum Windows Programming
    Replies: 3
    Last Post: 08-04-2003, 09:14 AM