# HG changeset patch
# User Lorenzo Desole <lorenzodes@fastwebnet.it>
# Date 1234215520 -3600
# Node ID aca4997f139d6120f736d9545237cc1144df274a
# Parent  b2fec0cd3e1b9645446408cf1f2c00ed2e9a99cc
demux_unstick_ao_loop() reports that xine might be stuck != is stuck

Don't give up immediately if demux_unstick_ao_loop() reports that xine might
be stuck, because it's not necessarily so.

According to my tests, this fixes
http://bugs.kde.org/show_bug.cgi?id=180339#c42 and
http://bugs.debian.org/514114.

This has been tested with Amarok and kde 4.1.x (with phonon) and kaffeine.

diff --git a/src/combined/ffmpeg/ff_audio_decoder.c b/src/combined/ffmpeg/ff_audio_decoder.c
--- a/src/combined/ffmpeg/ff_audio_decoder.c
+++ b/src/combined/ffmpeg/ff_audio_decoder.c
@@ -333,8 +333,10 @@ static void ff_audio_decode_data (audio_
         while (out < decode_buffer_size) {
           int stream_status = xine_get_status(this->stream);
 
-          if (stream_status == XINE_STATUS_QUIT || stream_status == XINE_STATUS_STOP)
+	  if (stream_status == XINE_STATUS_QUIT || stream_status == XINE_STATUS_STOP) {
+	    this->size = 0;
             return;
+	  }
 
           audio_buffer = 
             this->stream->audio_out->get_buffer (this->stream->audio_out);
diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c
--- a/src/xine-engine/demux.c
+++ b/src/xine-engine/demux.c
@@ -120,6 +120,16 @@ void _x_demux_flush_engine (xine_stream_
 }
 
 
+struct timespec _x_compute_interval(unsigned int millisecs) {
+  struct timespec ts;
+  clock_gettime(CLOCK_REALTIME, &ts);
+  uint64_t ttimer = (uint64_t)ts.tv_sec*1000 + ts.tv_nsec/1000000 + millisecs;
+  ts.tv_sec = ttimer/1000;
+  ts.tv_nsec = (ttimer%1000)*1000000;
+  return ts;
+}
+
+
 void _x_demux_control_newpts( xine_stream_t *stream, int64_t pts, uint32_t flags ) {
 
   buf_element_t *buf;
@@ -147,19 +157,20 @@ void _x_demux_control_newpts( xine_strea
  */
 static int demux_unstick_ao_loop (xine_stream_t *stream)
 {
-  if (!stream->audio_thread_created)
+/*  if (!stream->audio_thread_created)
     return 0;
-
+*/
   int status = xine_get_status (stream);
-  if (status != XINE_STATUS_QUIT && status != XINE_STATUS_STOP)
+  if (status != XINE_STATUS_QUIT && status != XINE_STATUS_STOP && stream->demux_plugin->get_status(stream->demux_plugin) != DEMUX_FINISHED)
     return 0;
-
+#if 0
   /* right, stream is stopped... */
   audio_buffer_t *buf = stream->audio_out->get_buffer (stream->audio_out);
   buf->num_frames = 0;
   buf->stream = NULL;
   stream->audio_out->put_buffer (stream->audio_out, buf, stream);
-
+#endif
+  lprintf("stuck\n");
   return 1;
 }
 
@@ -200,24 +211,27 @@ void _x_demux_control_headers_done (xine
   stream->audio_fifo->put (stream->audio_fifo, buf_audio);
 
   pthread_mutex_unlock(&stream->demux_mutex);  
+  unsigned int max_iterations = 0;
 
   while ((stream->header_count_audio < header_count_audio) || 
          (stream->header_count_video < header_count_video)) {
-    struct timeval tv;
-    struct timespec ts;
 
     lprintf ("waiting for headers. v:%d %d   a:%d %d\n",
 	     stream->header_count_video, header_count_video,
 	     stream->header_count_audio, header_count_audio); 
+  
+    struct timespec ts = _x_compute_interval(1000); 
+    int ret_wait;
 
-    gettimeofday(&tv, NULL);
-    ts.tv_sec  = tv.tv_sec + 1;
-    ts.tv_nsec = tv.tv_usec * 1000;
     /* use timedwait to workaround buggy pthread broadcast implementations */
-    pthread_cond_timedwait (&stream->counter_changed, &stream->counter_lock, &ts);
+    ret_wait = pthread_cond_timedwait (&stream->counter_changed, &stream->counter_lock, &ts);
 
-    if (demux_unstick_ao_loop (stream))
+    if (ret_wait == ETIMEDOUT && demux_unstick_ao_loop (stream) && ++max_iterations > 4) {
+      xine_log(stream->xine, 
+	  XINE_LOG_MSG,_("Stuck in _x_demux_control_headers_done(). Taking the emergency exit\n"));
+      stream->emergency_brake = 1;
       break;
+    }
   }
 
   stream->demux_action_pending = 0;
@@ -374,13 +388,21 @@ static void *demux_loop (void *stream_ge
   pthread_mutex_unlock( &stream->demux_lock );
 
   pthread_mutex_lock (&stream->counter_lock);
+  struct timespec ts;
+  unsigned int max_iterations = 0;
+  int ret_wait;
   while ((stream->finished_count_audio < finished_count_audio) || 
          (stream->finished_count_video < finished_count_video)) {
     lprintf ("waiting for finisheds.\n");
-    pthread_cond_wait (&stream->counter_changed, &stream->counter_lock);
+    ts = _x_compute_interval(1000);
+    ret_wait = pthread_cond_timedwait (&stream->counter_changed, &stream->counter_lock, &ts);
 
-    if (demux_unstick_ao_loop (stream))
-      /* break amarok */;
+    if (ret_wait == ETIMEDOUT && demux_unstick_ao_loop (stream) && ++max_iterations > 4) {
+      xine_log(stream->xine,
+	  XINE_LOG_MSG,_("Stuck in demux_loop(). Taking the emergency exit\n"));
+      stream->emergency_brake = 1;
+      break;
+    }
   }
   pthread_mutex_unlock (&stream->counter_lock);
   
