Buffer lost

I had problems with one of my apps running in windows media center that it crashed now and then. I found out that it was due too a buffer lost in directx.

I added following to row 488 (juce_win32_DirectSound.cpp):

	if (hr == MAKE_HRESULT (1, 0x878, 150)) // DSERR_BUFFERLOST
	{
		pOutputBuffer->Restore();
		hr = pOutputBuffer->GetCurrentPosition (&playCursor, &writeCursor);
	}

And I haven’t had any crashes in a couple of days now, probably it helped :slight_smile:

/Okku

Thanks Okku - that’s a good suggestion! When you say crash, do you just mean that the assertion was being triggered because the HRESULT wasn’t S_OK, or that something else was going wrong?

Yes the assert was hit, I got a nice error message in my log file.

Bah! The solution I suggested didn’t work :frowning:

The strange thing is that IDirectSoundBuffer8::GetCurrentPosition dosen’t return DSERR_BUFFERLOST (msdn documentation).
But I have messages in my log file: DS error at line 496 - Buffer lost
I will dig a little more into this and check what exact hresult GetCurrentPosition returns.

Another troublesome thing is that even if you call restore on a buffer you can’t be sure if the buffer gets restored.

What I really need is some way to know if the AudioDeviceManager is in a playable state or not, preferably an event/notification.

My app is a kind of a music player and it would be easy for me to just popup a message “Audiocard problems” when the AudioDeviceManager is in a nonplayable mode (and ofcourse remove it when the soundsystem is ok again).

Any clues how to solve this?

Not really sure what you mean by a “playable state”…

The most generic way to do it might be to increment a counter each time you process a buffer of data, and then have a timer that watches for the counter being ignored for too long, then you’d know that something had gone wrong for some reason?

Playable state is a value that signals the possibility to play audio with current settings of the AudioDeviceManager for the moment.

The problem is that even if you can play audio right now, you can not be sure that you can play audio later. For instance if your app loses focus and antoher app is taking exclusive control of the sound card. With directsound that is possible, and as I said before even if you tell directsound that you want to play it can neglect you.

From msdn:
If the application does not have the input focus, IDirectSoundBuffer8::Restore might not succeed. For example, if the application with the input focus has the DSSCL_WRITEPRIMARY cooperative level, no other application will be able to restore its buffers. Similarly, an application with the DSSCL_WRITEPRIMARY cooperative level must have the input focus to restore its primary buffer.

I tried the following:

		DWORD playCursor, writeCursor;
		HRESULT hr = pOutputBuffer->GetCurrentPosition (&playCursor, &writeCursor);

		if (hr != S_OK)
		{
			log (T("hr1 = ") + String ((int) hr));
			hr = pOutputBuffer->Restore();
			log (T("hr2 = ") + String ((int) hr));
			hr = pOutputBuffer->GetCurrentPosition (&playCursor, &writeCursor);
			log (T("hr3 = ") + String ((int) hr));
		}

        if (hr != S_OK)
        {
            logError (hr);
            jassertfalse
            return true;
        }

I start my JUCE app, then I start a windows media center TV channel and I get following in the log file:
hr1 = -2005401450
hr2 = 0
hr3 = -2005401450
DS error at line 499 - Buffer lost
hr1 = -2005401450
hr2 = 0
hr3 = -2005401450
DS error at line 499 - Buffer lost
hr1 = -2005401450
hr2 = 0
hr3 = -2005401450
DS error at line 499 - Buffer lost
…

-2005401450 = 0x88780096 (DSERR_BUFFERLOST)
Really strange that hr2 is S_OK, maybe it is not valid to call GetCurrentPosition on a newly restored surface?

Do you want me to look into this issue?

Just to rewind a bit, can I ask why you’re spending so much effort on this? If it doesn’t actually crash a user’s app, but just maybe glitches when they try to run another audio app, then why’s that a problem?

Surely anyone using Vista or Windows7 will be using WASAPI (and you should disable DSound when running on those OSes). If they’re stuck on XP but are bothered about having perfect, uninterrupted audio, then won’t they already be using a proper ASIO driver or ASIO4All?

Ok, thats not an option for me, I want the app to work flawlessly on XP to Win7 (and OS X and Linux in the future).

The app doesn’t crash but it stops working, and behaves strange and the log file gets filled with “DS error at line XXX - Buffer lost” (really spammed).
The user need to restart the app.

As DSound is the default device all juce apps must have this issue, I think it would be nice if juce had a fully working directsound integration, not just some special hack in my app to get it to work.

The music players I am using WinAmp and Spotify both uses DirectSound, and works :slight_smile:

Somehow i need to get a notification from the AudioDeviceManager or some other class that I cant play anything right now, I could call stop (so the service method doesn’t get called and spamming the log). Then at a later stage when the user wants to play audio i could try to play again… if it works everyhing is fine or else I get the notification again and I call stop.

And I also think that the buffer restore logic needs to be changed a bit.

Maybe the other apps are using a lower co-operative level?

With works I mean that both handle the loss of buffers correctly, (eg. they stop when they loose the buffers and can be started when the buffers are available again) sorry for that confusion.