0
0

I upgraded from 4.00.34 to 4.04.06, and I am seeing memory leaks reported now. I tried version 4.04.04 and saw the same leaks there too, but 4.00.34 shows none. There is no change in my code other than swapping FMOD versions (fmodex.dll, fmodex_vc.lib and the headers).

Here are the details.

I am playing only ogg files, both mono as 3D sounds and stereo as 2D sounds. I am using the flags FMOD_SOFTWARE | FMOD_UNICODE | FMOD_CREATESTREAM | FMOD_IGNORETAGS. I have added my own memory and file routines, and when I am done with the sound and called all of the appropriate release functions, I see for each sound two blocks of 68 bytes, 1 block of 43 bytes, and 1 block of 23 bytes left unfreed. It is always those specific sizes, despite the very different sizes of the ogg files being played.

Any ideas?

  • You must to post comments
0
0

Ok, we’ve found an OGG that reproduces the leak and we’re working on fixing it.

Cheers,

  • You must to post comments
0
0

Hi i’ve just tested this with fmod’s memory manager, and also with straight malloc + rational purify, and it comes back as 0 bytes used at the end when everything is released.
I would verify your memory manager and let me know if FMOD_UNICODE makes any difference if it is not set (pretty sure it doesnt allocates memory just because of that).
Also let me know if it is a particular ogg file, or all ogg files, and if you can reproduce it in a small test let me know and I can take a look.

  • You must to post comments
0
0

Hi Brett,

I have been tracing through my code, and I noticed what could be a problem. I am using my own file system which runs asynchronously on its own thread, and when the read callback occurs before my file system has read any data for the sound in question, I am returning 0 and FMOD_OK. BUt I saw this line in System::setFileSystem:

"You must also return FMOD_ERR_FILE_EOF from a read callback if the number of bytes read is smaller than the number of bytes requested"

What should I return if I want FMOD to try back again but I have no data to give it yet? Or should I not return until I have some data?

Tim.

  • You must to post comments
0
0

Well, I ripped out my filesystem and did just plain calls into CreateFile, ReadFile, CloseHandle, and SetFilePointer, and I still see exactly those memory leaks: two 68 byte leaks, a 43 byte leak, and a 23 byte leak per sound played. All of these are coming from calls to the malloc callback (as opposed to realloc) made after calling system::createSound(). Actually, I see five calls to create 68 byte blocks, but only three are freed on release, so two of those are leaking, plus the 43 and 23 byte block.

I will try to create a small stand-alone module that recreates this.

  • You must to post comments
0
0

If I remove the FMOD_CREATESTREAM flag from my call to system::createSound (so I am just using the flags FMOD_SOFTWARE | FMOD_UNICODE | FMOD_IGNORETAGS), all leaks disappear. This is with the simple file system I mentioned above.

  • You must to post comments
0
0

What does Memory_GetStats say? There is no reproducable memory leak here. The file system is irrelevant , i was talking more about your memory system.
Rational purify is the authority on this subject, even though my own memory manager agrees with it, and there are no fmod leaks.

  • You must to post comments
0
0

The next message contains a small piece of C++ code that causes the leak. I noticed that it only leaks with OGG files, not with WAV. If you want me to send you an OGG file that causes a leak, let me know.

Also, in line 172, you will see a note that adding FMOD_CREATESTREAM causes a crash in this code. The crash occurs after I return from the SoundEndCallBack() function.

  • You must to post comments
0
0

include "fmod.hpp"

include "fmod_errors.h"

include <assert.h>

include <stdlib.h>

include <tchar.h>

include <windows.h>

pragma comment(lib, "\Game\Source\SDK\FMOD Programmers API 4.04.06\api\lib\fmodex_vc")

static FMOD::System* m_system;
static FMOD::Sound* m_sound;
static FMOD::Channel* m_channel;
static unsigned int m_memTotal = 0;

HRESULT StopFModSound(void);

BOOL SOUNDFAILED(FMOD_RESULT result)
{
return result != FMOD_OK;
}

// ————————————————————————————————————————-
// Memory callbacks
// These three functions (malloc, realloc and free) keep track of how much memory is in use by storing the size of the block
// at the start of each block. The requested size is increased to account for this storage

void* F_CALLBACK MallocCallback(unsigned int size)
{
void *p;

size += sizeof(m_memTotal);
p = malloc(size);
if (p)
{
    m_memTotal += size;
    unsigned int *ip = (unsigned int *) p;
    *ip = size;
    ip++;
    p = ip;
}
return p;

}

void* F_CALLBACK ReallocCallback(void *ptr, unsigned int size)
{
void *p;
unsigned int *ip = (unsigned int *) ptr;
ip–;
m_memTotal -= *ip;
size += sizeof(m_memTotal);
p = realloc(ip,size);
if (p)
{
m_memTotal += size;
ip = (unsigned int *) p;
*ip = size;
ip++;
p = ip;
}

return p;

}

void F_CALLBACK FreeCallback(void *ptr)
{
unsigned int *ip = (unsigned int *) ptr;
ip–;
m_memTotal -= *ip;
free(ip);
}

// ————————————————————————————————————————-
// File callbacks
// These four functions (open, close, read and seek) perform all of the I/O. Note that open must stop the sound because
// if a sound fails to open, the end callback for that channel is never called

FMOD_RESULT F_CALLBACK OpenCallback(const char* name, int unicode, unsigned int* filesize, void** handle, void** userdata)
{
HANDLE fHandle = CreateFile((LPCWSTR)name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if(INVALID_HANDLE_VALUE == fHandle)
{
StopFModSound();
return FMOD_ERR_FILE_NOTFOUND;
}
else
{
*filesize = GetFileSize(fHandle, NULL);
*handle = fHandle;
}

return FMOD_OK;

}

FMOD_RESULT F_CALLBACK CloseCallback(void* handle, void* userdata)
{
CloseHandle(((HANDLE) handle));

return FMOD_OK;

}

FMOD_RESULT F_CALLBACK ReadCallback(void* handle, void* buffer, unsigned int sizebytes, unsigned int* bytesread, void* userdata)
{
bytesread = 0;
if (!ReadFile(((HANDLE)handle),buffer,sizebytes,(LPDWORD)bytesread,NULL))
{
*bytesread = 0;
return FMOD_ERR_FILE_EOF;
}
if (
bytesread == 0)
{
return FMOD_ERR_FILE_EOF;
}

return FMOD_OK;

}

FMOD_RESULT F_CALLBACK SeekCallback(void *handle, unsigned int pos, void *userdata)
{
if (INVALID_SET_FILE_POINTER == SetFilePointer(((HANDLE) handle),pos,NULL,FILE_BEGIN))
{
return FMOD_ERR_FILE_COULDNOTSEEK;
}

return FMOD_OK;

}

FMOD_RESULT F_CALLBACK SoundEndCallBack(FMOD_CHANNEL *channel, FMOD_CHANNEL_CALLBACKTYPE type, int command, unsigned int commanddata1, unsigned int commanddata2)
{
StopFModSound();
return FMOD_OK;
}

// ————————————————————————————————————————-
// These four functions (startup, play, stop, shutdown) encapsulate our FMOD calls

HRESULT StartupFMod()
{
FMOD_RESULT result;

if( SOUNDFAILED(result = FMOD::Memory_Initialize(NULL, 0, MallocCallback, ReallocCallback, FreeCallback)))
    return E_FAIL;

if( SOUNDFAILED(result = FMOD::System_Create(&amp;m_system)))
    return E_FAIL;

if( SOUNDFAILED(result = m_system-&gt;setFileSystem(OpenCallback, CloseCallback, ReadCallback, SeekCallback, 4096 )))
    return E_FAIL;

if( SOUNDFAILED(result = m_system-&gt;set3DNumListeners(1)))
    return E_FAIL;

static const FMOD_VECTOR pos            = { 0.0f, 0.0f, 0.0f };
static const FMOD_VECTOR vel            = { 0.0f, 0.0f, 0.0f };
static const FMOD_VECTOR forward        = { 0.0f, 0.0f, 1.0f };
static const FMOD_VECTOR up             = { 0.0f, 1.0f, 0.0f };

if( SOUNDFAILED(result = m_system-&gt;set3DListenerAttributes(0, &amp;pos, &amp;vel, &amp;forward, &amp;up)))
    return E_FAIL;

if( SOUNDFAILED(result = m_system-&gt;init(32, FMOD_INIT_NORMAL, 0)))
    return E_FAIL;

return S_OK;

}

HRESULT PlayFModSound(WCHAR *fname)
{
HRESULT hr = S_OK;
FMOD_RESULT result;
// NOTE: this flag setting, with FMOD_CREATESTREAM, crashes!
// UINT flags = FMOD_SOFTWARE | FMOD_UNICODE | FMOD_CREATESTREAM | FMOD_IGNORETAGS;
UINT flags = FMOD_SOFTWARE | FMOD_UNICODE | FMOD_IGNORETAGS;
flags |= FMOD_2D;
LPCWSTR ext = wcsrchr(fname, ‘.’);
if (ext && !_wcsicmp(ext, _T(".mp3")))
flags |= FMOD_MPEGSEARCH;

if(SOUNDFAILED(result = m_system-&gt;createSound((char *)fname, (FMOD_MODE) flags, 0, &amp;m_sound)))
    return E_FAIL;

//add this to the desc especially the priority
if(SOUNDFAILED(result = m_sound-&gt;setDefaults(44100.0, 1.0, 0.0f, 0 )))
    return E_FAIL;

//play the sound, but pause it
if(SOUNDFAILED(result = m_system-&gt;playSound(FMOD_CHANNEL_FREE, m_sound, true, &amp;m_channel)))
    return E_FAIL;

// add a callback to the channel
if( SOUNDFAILED(result = m_channel-&gt;setCallback(FMOD_CHANNEL_CALLBACKTYPE_END, SoundEndCallBack, 0)))
    return E_FAIL;

// unpause the sound
if(SOUNDFAILED(result = m_channel-&gt;setPaused(false)))
    return E_FAIL;

return hr;

}

HRESULT StopFModSound()
{
// always check these values, so this function is safe to call multiple times
if (m_channel)
m_channel->stop();
m_channel = NULL;
if (m_sound)
m_sound->release();
m_sound = NULL;

return S_OK;

}

HRESULT ShutdownFMod(void)
{
m_system->release();
m_system = NULL;
assert(m_memTotal == 0);

return S_OK;

}

int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
// start fmod
StartupFMod();
// play sound
PlayFModSound(_T("Z:\Sound\Game Audio\SFX\feb demo_ogg_vorbis_files_premixed\FootstepSnowSoft01.ogg"));
// loop for 10 second
UINT64 CountsPerSecond, StartCounts, CurrCounts;
QueryPerformanceFrequency((LARGE_INTEGER*)&CountsPerSecond);
QueryPerformanceCounter((LARGE_INTEGER*)&StartCounts);
do
{
m_system->update();
QueryPerformanceCounter((LARGE_INTEGER*)&CurrCounts);
} while (CurrCounts < (CountsPerSecond * 10 + StartCounts));
// stop and free sound, if needed (it may have been stopped by the end callback)
StopFModSound();
// stop fmod
ShutdownFMod();
}

  • You must to post comments
0
0

I ran that code and it neither crashes with the stream flag, and it doesn’t leak either according to your m_memTotal variable. It was 0 at this line
assert(m_memTotal == 0); in ShutdownFMod.
Did you do what I asked in the last post? Have you accidently used an old dll somewhere?

Try not freeing sounds in a channel end callback either, you’re not supposed to do that.

  • You must to post comments
0
0

OK, I don’t call StopFModSound() inside of the endcallback anymore, but I am not sure why it is unsafe. The documentation for channel::setCallback() states that it "allows all FMOD commands".

Calling Memory_GetStats() produces these values for current memory usage:

after the call to StartupFMod: 330469
after the call to m_system->update(): 542365
after the call to StopFModSound: 379791

Also, further investigation shows that I do not get the leak for any of the ogg files in your examples/media folder, and I don’t get leaks from ogg files made by OggDrop, but I do get it for any ogg file created by SoundForge 8. These oggs play correctly on WinAmp 5.1.

  • You must to post comments
Showing 10 results
Your Answer

Please first to submit.