[MPlayer-dev-eng] [PATCH] Prevent ao_win32 from hanging during uninit(0)

David Bolen db3l.net at gmail.com
Thu Mar 5 08:47:48 CET 2009


Based a few weeks of continuous usage of mplayer with ao_win32, I've
discovered that a very small percentage of the time, it can hang in
the call to uninit(0), while ostensibly waiting for any buffered bytes
to complete.  I'm using mplayer in slave mode and this hangs the slave
interface at the point when new media is loaded and/or when existing
media is allowed to terminate.

While it's quite low probability - across 16 mplayer processes on 8
machines for about 10 days, I've seen it 5 times over maybe 100,000
loads - but it does happen.

The attached proposed patch protects against this by bounding the wait
loop in uninit based on current output rate and buffered bytes.

I suspect there may be flaws in how the buffered data is maintained
that I'm still playing with.  For example, based on a visual
inspection, I can't see how write_waveOutBuffer can be correct, as it
is written to permit chunks smaller than BUFFER_SIZE, but in such
cases seems likely to reuse active buffers, not to mention the
callback routine assumes always full buffers.  The problem is I have a
hard time figuring out how even if those items go wrong, it could lead
to uninit() not eventually terminating.  So maybe it's just a Windows
thing (I'm currently operating on XP SP2).

But regardless if there are other later cleanups, it seems prudent to
avoid the possibility of an infinite loop in a cleanup routine.
Certainly the below change resolved my immediate problems.

Patch is against trunk.  The warning could probably be considered
optional, although it at least let me know when I hit and got through
one of the cases.

-- David

Index: ao_win32.c
===================================================================
--- ao_win32.c	(revision 28810)
+++ ao_win32.c	(working copy)
@@ -251,8 +251,19 @@
 // close audio device
 static void uninit(int immed)
 {
-    if(!immed)while(buffered_bytes > 0)usec_sleep(50000);
+    int timeout_cnt = 20;
+
+    /* Wait long enough as is reasonable for pending bytes (loop = 1/20s) */
+    if (ao_data.bps) {
+        timeout_cnt = (((double)buffered_bytes) / ao_data.bps * 20) + 2;
+    }
+    if(!immed)while(timeout_cnt-- && buffered_bytes > 0)usec_sleep(50000);
     else buffered_bytes=0;
+    if (buffered_bytes > 0) {
+        mp_msg(MSGT_AO, MSGL_WARN,
+               "Warning: Failed to play %d buffered bytes\n", buffered_bytes);
+        buffered_bytes = 0;
+    }
 	waveOutReset(hWaveOut);
 	waveOutClose(hWaveOut);
 	mp_msg(MSGT_AO, MSGL_V,"waveOut device closed\n");




More information about the MPlayer-dev-eng mailing list