[MPlayer-dev-eng] ao_alsa9 cleanup

joy joy at pingfm.org
Thu Jun 27 06:18:03 CEST 2002


i currently cleaned up the code of ao_alsa9, throwed away some parts which aren't used since this nice part of software was created i guess. i also rewrote some main parts, especially the play function, mainly based on marius suggestions but added some better buffer underrun handling.
it works fine only tested with my ens1371 and some divx and asf movies (i need some kind of testsuite for this;). it seems to work also with the default MAX_OUTBURST=65536 option, but i think it would be better to set this value as default to 16384 cause all soundplugins has a max buffersize of 16384, without alsa5. and if im not wrong MAX_OUTBURST describes simply the available buffersize.
i took off the alpha warning cause i think the alsa9-driver is at some kind of beta stage now.
Alex Beregszaszi would you take a look at it and commit it?


-- 
regards

____-
joy

________/\---------%%%___________-----------
webcast every sunday 2000 cest at pingfm.org

pgp key at: x-hkp://wwwkeys.de.pgp.net
-------------- next part --------------
--- /usr/local2/cvs_work2/mplayer/mplayer_26_06_02/libao2/ao_alsa9.c	Sun May 26 14:30:54 2002
+++ ao_alsa9.c	Thu Jun 27 04:25:39 2002
@@ -3,16 +3,17 @@
 
   (C) Alex Beregszaszi <alex at naxine.org>
   
-  modified for better alsa-0.9.0beta8a-support by Joy Winter <joy at pingfm.org>
+  modified for better alsa-0.9.0beta12(rc1)-support by Joy Winter <joy at pingfm.org>
   additional AC3 passthrough support by Andy Lo A Foe <andy at alsaplayer.org>
   
-  This driver is still at alpha stage. 
-  If you want stable sound-support use the OSS emulation instead.
-  
   Any bugreports regarding to this driver are welcome either to the mplayer-user-mailinglist or directly to the authors.
 */
 
 #include <errno.h>
+#include <sys/time.h>
+#include <stdlib.h>
+//#include <unistd.h>
+//#include <string.h>
 
 #include "../config.h"
 
@@ -46,13 +47,23 @@
 static snd_pcm_hw_params_t *alsa_hwparams;
 static snd_pcm_sw_params_t *alsa_swparams;
 static char *alsa_device;
-#define ALSA_DEVICE_SIZE 48
 
-static int alsa_fragsize = 8192; /* possible 4096, original 8192 */
+static int alsa_fragsize = OUTBURST; /* possible 4096, original 8192, OUTBURST is set statically to 512 in config.h but now its not used cause chunksize is allocated dynamically. */
 static int alsa_fragcount = 8;
 
 static int chunk_size = -1;
-static int start_delay = 1;
+static int buffer_size = 0;
+static int start_delay = 0;
+static int stop_delay = 0;
+static size_t bits_per_sample, bits_per_frame;
+static size_t chunk_bytes;
+
+#define ALSA_DEVICE_SIZE 48
+
+#define buffertime /* last undef */
+#undef set_period /* only function now is to set chunksize staticaly, last defined */
+#define sw_params /* last undef */
+
 
 snd_pcm_t *
 spdif_init(int acard, int adevice)
@@ -178,12 +189,6 @@
     return(CONTROL_UNKNOWN);
 }
 
-#undef start /* orig. undef */
-#define buffsize 
-#define buffertime /* orig. undef? */
-#define set_period
-#define sw_params /* orig. undef */
-#undef set_start_mode /* orig. undef */
 
 /*
     open & setup audio device
@@ -198,7 +203,7 @@
     size_t xfer_align; //new
     snd_pcm_uframes_t start_threshold, stop_threshold; //new
 
-    printf("alsa-init: this driver is still at alpha-stage. if you want stable sound support use the OSS emulation instead.\n");    
+    printf("alsa-init: testing and bugreports are welcome.\n");    
     printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz,
 	channels, audio_out_format_name(format));
 
@@ -298,8 +303,7 @@
     }	    
    
     if (!alsa_handler) {
-	    if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK,
-					    0)) < 0)
+	    if ((err = snd_pcm_open(&alsa_handler,alsa_device,SND_PCM_STREAM_PLAYBACK,0)) < 0)
 	    {
 		    printf("alsa-init: playback open error: %s\n", snd_strerror(err));
 		    return(0);
@@ -308,6 +312,8 @@
 
     snd_pcm_hw_params_malloc(&alsa_hwparams);
     snd_pcm_sw_params_alloca(&alsa_swparams);
+
+    // setting hw-parameters
     if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
     {
 	printf("alsa-init: unable to get initial parameters: %s\n",
@@ -340,7 +346,6 @@
     }
 
         if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, ao_data.samplerate, 0)) < 0) 
-/* was originally only snd_pcm_hw_params_set_rate jp*/ 
         {
     	printf("alsa-init: unable to set samplerate-2: %s\n",
     	    snd_strerror(err));
@@ -348,33 +353,14 @@
     	return(0);
         }
 
+
 #ifdef set_period
     {
-	if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, alsa_fragsize / 4, 0)) < 0)
+	if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, alsa_fragsize, 0)) < 0)
 	{
-	    printf("alsa-init: unable to set periodsize: %s\n",
-		snd_strerror(err));
+	    printf("alsa-init: unable to set periodsize: %s\n", snd_strerror(err));
 	    return(0);
 	}
-		if ((err = snd_pcm_hw_params_set_periods(alsa_handler, alsa_hwparams, alsa_fragcount, 0)) < 0)
-		{
-		    printf("alsa-init: unable to set periods: %s\n",
-			snd_strerror(err));
-		    return(0);
-		}
-    }
-#endif
-#ifdef buffsize
-    if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0)
-    {
-	printf("alsa-init: unable to get buffer size: %s\n",
-	    snd_strerror(err));
-	return(0);
-    } else
-    {
-	ao_data.buffersize = err;
-        if (verbose)
-	    printf("alsa-init: got buffersize %i\n", ao_data.buffersize);
     }
 #endif
 
@@ -397,95 +383,140 @@
 		snd_strerror(err));
 	    return(0);
 	}
-	printf("alsa-init: buffer_time: %d, period_time :%d\n",
-	    alsa_buffer_time, err);
+	if (verbose)
+	  printf("alsa-init: buffer_time: %d, period_time :%d\n",alsa_buffer_time, err);
     }
 #endif
 
+    /* get chunk-size */
+    if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, 0)) < 0)
+      {
+	printf("alsa-init: unable to get chunk-size in hw-params: %s\n", snd_strerror(err));
+	return(0);
+      } else
+	{
+	  chunk_size = err;
+	  if (verbose) {printf("alsa-init: got chunksize %i\n", chunk_size);}
+	}
+
+    /* get buffer size */
+    if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0)
+    {
+      printf("alsa-init: unable to get buffersize in hw-params: %s\n", snd_strerror(err));
+      return(0);
+    } else
+      {
+      ao_data.buffersize = err;
+      if (verbose) {printf("alsa-init: got buffersize %i\n", ao_data.buffersize);}
+      }
+    
+    if (MAX_OUTBURST > ao_data.buffersize) { //warning if MAX_OUTBURST is bigger than buffersize
+      printf("alsa-init: WARNING! MAX_OUTBURST exceeds your available buffersize.\nalsa-init: MAX_OUTBURST=%i, buffersize=%i\n",MAX_OUTBURST,ao_data.buffersize);}
+
+    if (chunk_size == ao_data.buffersize)
+      {
+      printf("alsa-init: Can't use period equal to buffer size (%u == %lu)", chunk_size, (long)buffer_size);
+      return(0);
+      }
+
+    /* finally install hardware parameters */
     if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
     {
-	printf("alsa-init: unable to set parameters: %s\n",
+	printf("alsa-init: unable to set hw-parameters: %s\n",
 	    snd_strerror(err));
 	return(0);
     }
+    // end setting hw-params
 
 #ifdef sw_params
     {
-    chunk_size = snd_pcm_hw_params_get_period_size(alsa_hwparams, 0);
-    start_threshold = (double) ao_data.samplerate * start_delay / 1000000;
-    xfer_align = snd_pcm_sw_params_get_xfer_align(alsa_swparams);
+      size_t n;
+      xfer_align = snd_pcm_sw_params_get_xfer_align(alsa_swparams);
+      if (xfer_align == 0)
+	xfer_align = 4;
+      n = (ao_data.buffersize / xfer_align) * xfer_align;
+
+      if (start_delay <= 0) {
+	start_threshold = n + (double) ao_data.samplerate * start_delay / 1000000;
+      } else {
+	start_threshold = (double) ao_data.samplerate * start_delay / 1000000;
+      }
+      if (start_threshold < 1)
+	start_threshold = 1;
+      if (start_threshold > n)
+	start_threshold = n;
+
+      if (stop_delay <= 0) {
+	stop_threshold = ao_data.buffersize + (double) ao_data.samplerate * stop_delay / 1000000;
+      } else {
+	stop_threshold = (double) ao_data.samplerate * stop_delay / 1000000;
+      }
+
+      if (verbose) {
+	printf("alsa-init: start_threshold=%lu, stop_threshold=%lu\n",start_threshold,stop_threshold);
+	printf("alsa-init: n=%i\n", n);
+      }
 
     if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0)
-    {
-	printf("alsa-init: unable to get parameters: %s\n",
-	    snd_strerror(err));
+      {
+	printf("alsa-init: unable to get parameters: %s\n",snd_strerror(err));
 	return(0);
-    }
+      }
+
+    //set min available frames to consider pcm ready (4)
+    if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, 4)) < 0)
+      {
+	printf("alsa-init: unable to set avail_min %s\n",snd_strerror(err));
+	return(0);
+      }
 	
-	if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, chunk_size)) < 0)
-	  {
-	    printf("alsa-init: unable to set avail_min %s\n",snd_strerror(err));
-	    return(0);
-	  }
+    if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, start_threshold)) < 0)
+      {
+	printf("alsa-init: unable to set start_threshold %s\n",snd_strerror(err));
+	return(0);
+      }
 
+    if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, stop_threshold)) < 0)
+      {
+	printf("alsa-init: unable to set stop_threshold %s\n",snd_strerror(err));
+	return(0);
+      }
 
-	
-	if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, start_threshold)) < 0)
-	  {
-	    printf("alsa-init: unable to set start_threshold %s\n",snd_strerror(err));
-	    return(0);
-	  }
-    } 
-    //      if ((err = snd_pcm_sw_params_set_xfer_align(alsa_handler, alsa_swparams, xfer_align)) < 0)
-    //{
-    //	printf("alsa-init: unable to set xfer_align: %s\n",
-    //	    snd_strerror(err));
-    //	return(0);
-    //}
-
-#ifdef set_start_mode
-    if ((err = snd_pcm_sw_params_set_start_mode(alsa_handler, alsa_swparams,
-	SND_PCM_START_DATA)) < 0)
-    {
-	printf("alsa-init: unable to set start mode: %s\n",
-	    snd_strerror(err));
+    //transfers stream aligned to 4 in nonblocking-mode it would be 1
+    if ((err = snd_pcm_sw_params_set_xfer_align(alsa_handler, alsa_swparams, 4)) < 0)
+      {
+	printf("alsa-init: unable to set xfer_align: %s\n",snd_strerror(err));
 	return(0);
-    }
-#endif
+      }
 
     if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0)
-    {
-	printf("alsa-init: unable to set parameters: %s\n",
-	    snd_strerror(err));
+      {
+	printf("alsa-init: unable to install sw-params\n");
 	return(0);
+      }
+
+    bits_per_sample = snd_pcm_format_physical_width(alsa_format);
+    bits_per_frame = bits_per_sample * channels;
+    chunk_bytes = chunk_size * bits_per_frame / 8;
+
+    if (verbose) {
+      printf("alsa-init: bits per sample (bps)=%i, bits per frame (bpf)=%i, chunk_bytes=%i\n",bits_per_sample,bits_per_frame,chunk_bytes);}
     }
 
-//    snd_pcm_sw_params_default(alsa_handler, alsa_swparams);
-#endif
+#endif //end swparams
+
     if ((err = snd_pcm_prepare(alsa_handler)) < 0)
     {
 	printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err));
 	return(0);
     }
 
-#ifdef start
-    if ((err = snd_pcm_start(alsa_handler)) < 0)
-    {
-	printf("alsa-init: pcm start error: %s\n", snd_strerror(err));
-	if (err != -EPIPE)
-	    return(0);
-	if ((err = snd_pcm_start(alsa_handler)) < 0)
-	{
-	    printf("alsa-init: pcm start error: %s\n", snd_strerror(err));
-		return(0);
-	}
-    }
-#endif
-    printf("AUDIO: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
+    printf("alsa9: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
 	ao_data.samplerate, ao_data.channels, ao_data.bps, ao_data.buffersize,
 	snd_pcm_format_description(alsa_format));
     return(1);
-}
+} // end init
+
 
 /* close audio device */
 static void uninit()
@@ -503,19 +534,14 @@
 	return;
     }
 
-#ifdef start
-    if ((err = snd_pcm_reset(alsa_handler)) < 0)
-    {
-	printf("alsa-uninit: pcm reset error: %s\n", snd_strerror(err));
-	return;
-    }
-#endif
-
     if ((err = snd_pcm_close(alsa_handler)) < 0)
     {
 	printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err));
 	return;
     }
+    else {
+      printf("alsa-uninit: pcm closed\n");
+    }
 }
 
 static void audio_pause()
@@ -546,14 +572,6 @@
 	printf("alsa-resume: pcm prepare error: %s\n", snd_strerror(err));
 	return;
     }
-
-#ifdef start
-    if ((err = snd_pcm_start(alsa_handler)) < 0)
-    {
-	printf("alsa-resume: pcm start error: %s\n", snd_strerror(err));
-	return;
-    }
-#endif
 }
 
 /* stop playing and empty buffers (for seeking/pause) */
@@ -567,62 +585,90 @@
 	return;
     }
 
-#ifdef start
-    if ((err = snd_pcm_reset(alsa_handler)) < 0)
-    {
-	printf("alsa-reset: pcm reset error: %s\n", snd_strerror(err));
-	return;
-    }
-#endif
-
     if ((err = snd_pcm_prepare(alsa_handler)) < 0)
     {
 	printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err));
 	return;
     }
 
-#ifdef start
-    if ((err = snd_pcm_start(alsa_handler)) < 0)
-    {
-	printf("alsa-reset: pcm start error: %s\n", snd_strerror(err));
-	return;
-    }
-#endif
 }
 
+#ifndef timersub
+#define timersub(a, b, result) \
+do { \
+	(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+  (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+  if ((result)->tv_usec < 0) { \
+		--(result)->tv_sec; \
+		(result)->tv_usec += 1000000; \
+	} \
+} while (0)
+#endif
+
 /*
     plays 'len' bytes of 'data'
     returns: number of bytes played
+    modified last at 26.06.02 by jp
 */
 
 static int play(void* data, int len, int flags)
 {
-    int got_len;
-	
-    got_len = snd_pcm_writei(alsa_handler, data, len / 4);
-    
-    //if ((got_len = snd_pcm_writei(alsa_handler, data, (len/ao_data.bps))) != (len/ao_data.bps)) {     
-    //SHOULD BE FIXED      
-	if (got_len == -EPIPE) /* underrun? */
-	{
-	    printf("alsa-play: alsa underrun, resetting stream\n");
-	    if ((got_len = snd_pcm_prepare(alsa_handler)) < 0)
-	    {
-		printf("alsa-play: playback prepare error: %s\n", snd_strerror(got_len));
-		return(0);
-	    }
-	    if ((got_len = snd_pcm_writei(alsa_handler, data, (len/ao_data.bps))) != (len/ao_data.bps))
-	    {
-		printf("alsa-play: write error after reset: %s - giving up\n",
-		    snd_strerror(got_len));
-		return(0);
-	    }
-	    return(len); /* 2nd write was ok */
-    }
-    return(len);
-    //}
+
+  snd_pcm_status_t *status;
+
+  int num_frames=len/ao_data.bps;
+  signed short *output_samples=data;
+  snd_pcm_sframes_t res = 0;
+
+  if (!alsa_handler) {
+    printf("alsa-play: device configuration error");
+    return 0;
+  }
+
+  do {
+    if (res == -EPIPE) {  /* underrun */
+      snd_pcm_status_alloca(&status);
+      if ((res = snd_pcm_status(alsa_handler, status))<0) {
+	printf("alsa-play: buffer underrun. can't determine length");
+      } else {
+	if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
+	  struct timeval now, diff, tstamp;
+	  gettimeofday(&now, 0);
+	  snd_pcm_status_get_trigger_tstamp(status, &tstamp);
+	  timersub(&now, &tstamp, &diff);
+	  printf("alsa-play: xrun of at least %.3f msecs. resetting stream",
+		 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
+	} else 
+	  printf("alsa-play: xrun. can't determine length");
+      }	
+      res = snd_pcm_prepare(alsa_handler);
+    }
+    else if (res == -ESTRPIPE) {	/* suspend */
+      printf("alsa-play: pcm in suspend mode. trying to resume");
+      while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
+	sleep(1);
+      if (res < 0)
+	res = snd_pcm_prepare(alsa_handler);
+    }
+    
+    if (res >= 0)
+      res = snd_pcm_writei(alsa_handler, (void *)output_samples, num_frames);
+    
+    if (res > 0) {
+      output_samples += ao_data.channels * res;
+      num_frames -= res;
+    }
+
+  } while (res == -EPIPE || num_frames > 0);
+
+  if (res < 0) {
+    printf("alsa-play: write error %s", snd_strerror(res));
+    return 0;
+  }
+  return res < 0 ? (int)res : len;
 }
 
+
 /* how many byes are free in the buffer */
 static int get_space()
 {
@@ -690,7 +736,9 @@
     
     snd_pcm_status_free(status);
 
-    if (ret < 0)
+    if (ret < 0) {
+
 	ret = 0;
     return(ret);
+    }
 }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 234 bytes
Desc: not available
URL: <http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/attachments/20020627/5ffa5da6/attachment.pgp>


More information about the MPlayer-dev-eng mailing list