WinMMRenderer close

WinMMRenderer close

Hi!

Iexperienced some problem with WinMMRenderer. Well not exactly with WinMMRenderer but with waveOutClose. I'm playing audio with the renderer, and if somebody push the stop button in my application then I call the WinMMRenderer's Close() function. I examined my application with Process Explorer and I experienced thatthe wdmaud.drv!waveThread didn't finished when I called the Close() function. I examined thisproblem and I found that when the Close calls the waveOutClose function then it returns with 33 (which means still playing) and didn'tclose the waveOut device. I tried to use waveOutReset before waveOutClose but the program run into deadlock. How can I stop the playing when I want(not only between buffer changes)? Thanks in advance:

Bendeguy

17 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Hello Bendeguy!

I've just checked your investigations on my machine. You're right thesystem thread you mentioned above does not finish itself when one call Close() method. Moreover if several buffers are in use at the moment (remember BUF_NUM?) the system creates the adequate number of threads and when the renderer is being closed only the lastthread really finishes. So, congratulations! You found a real bug. I believe the developer didn't notice these unfinished system threads since it is not easy. I used ProcessExplorer from sysinternals.com for it. It will take some time to fix the problem. If this issue is important for you I'll let you know later how it can be fixed. Thanks a lot for your help.

BTW I've just read your replysin "DSoundRender delay" topic. Somehow I didn't receive notifications about your answers. I'm glad that you fixed your problem finally. Good luck.

-Sergey

vladimir-dudnik (Intel)'s picture

Hello Bendeguy,

let me also express my thanks for your help in improvement of audio part of IPP media sample! And I also want to express my sorry for that bugs, we are trying to intesively test samples before each release, but unfortunately there is nothing ideal in this world.

Regards,
Vladimir

Hello,

I think you are doing a very great job both in development and user help so I'm glad to help you. Thanks for all of your help.

Greetings,

Bendeguy

Hi Sergey!

Yes, this issue is important for me so I would like to ask you to send me a message when you find out how to fix this bug. Thanks in advance:

Bendeguy

Hi Bendeguy!

As I said earlier we have unfinished thread because we don't close the queue of waveOut buffers. To fix this you can try the following:

Insert the following lines into Close() method:

if (m_hWO) {
m_StopFlag = 1;//new variable to be inserted into the header
vm_time_sleep(10);
mmres = waveOutClose(m_hWO);
if (mmres == WAVERR_STILLPLAYING) { // need to reset buffers
mmres = waveOutReset(m_hWO);
mmres = waveOutClose(m_hWO);
}
m_hWO = NULL;
}

When we call waveOutReset the Release method will be called as many time as many buffers we have in the queue. So you should insert if (!m_StopFlag) before you call waveOutUnprepareHeader.

Don't forget to initialize m_StopFlag to 0.

And the last: you should provide breaking the loop in SendFrame after WaitForSingleObject when !m_StopFlag to avoid coredump in case you are in the middle of the loop by the time waveOut object is closed.

-Sergey

Hi Sergey?

Where I have to put it exacty?

UMC::WinMMAudioRender::Close()
{
if (m_hWO)
{
Release();
waveOutClose(m_hWO);
m_hWO = NULL;
}

if (m_sm_free_buffers)
{ CloseHandle(m_sm_free_buffers); }

m_sm_free_buffers = NULL;

return BasicAudioRender::Close();
}

Thanks in advance,

Bendeguy

You should insert my code instead of first if. (instead of "if (m_hWO)" )
-Sergey

Hi Sergey!

A few more questions about this. Isn't it a problem you removed the Release() call from your code?I've changed my program a little, so it starts an audio thread at the beggining and starts to play when somebody push the play button. When somebody push the play button I call renderer.Reset() and after then I start to play.The renderer.Reset()uses the Release() and waveOutClose functions. So do I have to change the code there exactly the same way as you mentioned?

Thanks in advance:

Bendeguy

Release performs UnprepareHeader and updates semaphore when a buffer is freed. When you call waveOutReset functionthe Release() is called automatically as many times as the amount of buffers in the queue (not more than NUM_BUF). Actually Reset()is almost equal to Close() + Init() except that it should notreset all renderers parameters (just clean the buffers). I beleive that Reset() is buggy too. You'll have to change its code the same way. I don't quite understand why you call Reset() when push Play button. Does another stream start in this case? If stream is the same one should use Pause() method.

Regards

-Sergey

Sometimes I have to restart the audio and video playing because of some syncronization issue. If I don't reset the audiodevice then some audio data will stay in the buffers, and when I want to play the new data, then it starts to play the older. So this is why I have to call reset.

Greetings,

Bendeguy

You're right. Reset() is neededexactly for this. Fix it like Close() and I think everything will be OK.

Thanks

-Sergey

Hi Sergey!

A few more question about your code:

You said :So you should insert if (!m_StopFlag) before you call waveOutUnprepareHeader

Do I only have to do it with waveOutUnprepareHeader?

if (!m_StopFlag) {
waveOutUnprepareHeader(m_hWO,
&m_Hdrs.m_pArray[m_iDoneBuf],
sizeof(WAVEHDR));
}

You said: And the last: you should provide breaking the loop in SendFrame after WaitForSingleObject when !m_StopFlag

Don't I have to break the loop if m_StopFlag instead of !m_StopFlag?

And last: Where I have to set m_StopFlag back to 0?

Thanks in advance,

Bendeguy

1) Yes. After you call waveOutReset you should not call waveOutUnprepareHeader.

2) You're right. It's a typo. You should break the loop when the flag is set.

3) Youmay do it in the constructor. Write m_StopFlag(0)just after m_DataSize(0). (Don't forget to declare it in header winmm_render.h)

Thanks for your quick answer. To tell the truth I didn't found the m_DataSize(0) line in the constructor. My constructor looks like this:

UMC::WinMMAudioRender::WinMMAudioRender():
m_hWO(NULL),
m_sm_free_buffers(0),
m_dfStartPTS(-1.0),
m_dfSampleNorm(1.0)
{m_StopFlag = 0;}

This code solves the starting initialization of m_StopFlag. I have to set it back to 0 after I called reset. So is that good if I put the m_StopFlag = 0 line before the Reset() function's"return umcRes;" line?

Thanks,

Bendeguy

Your code is OK.I think theplace is good too. Really I didn't check the work of Reset() method properly. So you can come across some pitfalls but I hope you won't. If you find anything interesting please let me know.

Regards

-Sergey

Hi Sergey,

I made the changes to my code and tested it. Everything looks fine. Thanks for your help.

Greetings,

Bendeguy

Login to leave a comment.