views:

127

answers:

4

Ok, to you understand I will explain the problem: I am using a library called ClanLIB (not my choice), that library, SEEMLY (I am not certain, even reading the sourcE), creates a thread that handles sound.

This thread, when the buffer is empty, tries to fetch more data, usually this cause a underrun when the data generating library is too slow to give more data before the soundcard reaches the buffer end.

So I added my own thread, that keeps generating sound on the background.

This worked fine, except that my own thread sometimes hijacked too much CPU time and froze everything else. To fix it, I added a conditional wait.

The conditional wait happens when the buffer is full, and when ClanLIB ask for more data, the wait is signaled, thus the buffer write thread resumes (until it is full again).

My issue is that since I added this conditional wait, the ClanLIB sound thread, and my own music thread, SOMETIMES get "runaway", playing music while the rest of the application freezes.

What sort of strange condition would cause that?

pseudocode:

//main thread (that get frozen)
start_sound_thread();
do_lots_of_stuff();
quit();

//Sound Thread:

While(true)
{
    play(buffer);
    if(buffer_empty)
    {
         mutex.lock()
         buffer = buffer2;
         if(buffer2_full)
         {
             signal(cond1);
             buffer2_full = false;
         }
         mutex.unlock()
    }
}

//Music Library Thread:

while(true)
{
    mutex.lock()        
    if( check_free_space(buffer2) == 0)
    {
        buffer2_full = true;
        condition_wait(cond1);
    }
    write_music(buffer2);
    mutex.unlock()
}
+1  A: 

If you are using ClamLib game SDK it is a well establish, tested and supported SDK. No offence intended, but, as you are an admitted newbie, the problem is more likely in your code than theirs.

I find it difficult to believe that such a well established library would develop an underrun, and, even if it it does, I doubt that the best solution would be to added my own thread, that keeps generating sound on the background. I say this because I suspect that you are taking the wrong approach and that if you can find a solution with CLamLib then you won't need your thread & your problem will be gone without needing to be solved.

It is goo that you posted code, thanks. I'll go off and look at that now.

And, finally, as great a fan as I am of SO, wouldn't it be better to ask first at the official ClanLib forum first?


Edit: what makes you so sure it is an underrun? i still find that hard to believe, but if you cna detect it in your program, then why not sleep(), rather than generating sound? (how long to sleep? how do you know how much sound to generate? and doesn't that generated sound interfere with the "real" sound?)

LeonixSolutions
I already asked there, they don't know why their code was made that way better (if you read the source, you will even see that their buffer read is HARDCODED to 1024*16 no matter how much is the playback frequency, or channels, or how much bytes per sample there are...)Also, it is ClanLIB 1.0, and it DO cause underruns when the data is not fetched fast enough, and it does not pre-buffer either (it REALLY waits for the buffer to end, I've read the source myself to make sure)
speeder
You already asked. Good (+1). I am surprised that they are not prepared to fix it. Still, it looks liek you can detect it with ` if(buffer_empty)`, so when you detect it why bother adding more sound (woudl it sound strange)? Why not just sleep() and forget the second thread? You cna wake periodically and check for more sound
LeonixSolutions
I cannot detect underrun, I hear the underrun (in the form of the soundcard repeating the last section of the buffer until new data is handed), and the problem is that ClanLIB only allow a little time to the sound generator to generate sound, so if the code is heavier, it WILL underrun...Anyway, I added some conditional waits... (I tried sleep, but when heavier music showed up, they got totally broken), seemly it solved (seemly, because some bugs we never know if we fixed them or not, specially when they are rare)
speeder
Glad to hear that it "seems" to be solved :-)
LeonixSolutions
+1  A: 

You're doing WAY too much within the mutex zones - it's likely you are deadlocking on the cond1 signal. You should do as little as possible within locking regions, because the more you do, the more risk you will introduce a deadlock - and you absolutely should never wait on a signal inside of a mutex that guards the sending of the signal - if you're waiting, it isn't ever going to be sent - condition_wait is not unblocking your mutex object, how could it know about it ?

The 'solved by addition of conditional waits' is a strong indicator you've got a race condition leading to deadlock - you haven't solved the problem, as soon as the execution timing of your logic changes for any reason, say because another app is running, the deadlock can return.

Mark Mullin
A: 

I actually, don't know what the issue was, it was fixed by accident...

I had a related issue, this one was caused by race condition when deleting the thread... I moved some code around (I don't even needed to recode anything) and it went away too. Now the thing is perfectly stable! (well, still has underruns but they are more rare now)

speeder
A: 

I'm using clanlib for a project too, but using OpenAL for sound. It seems to work the same way with feeding the buffer etc.

I also use a seperate thread for sound, but my solution was to just add a fixed sleep period after each attempt to feed the buffer. It's simple and seems pretty solid. And no locking is required ;)

Nemurenai