[MPlayer-dev-eng] alsa9_adds

joy joy at pingfm.org
Tue Jul 2 02:58:30 CEST 2002


i added some improvements and fixes again to ao_alsa9.
the main changes/adds are:

added get/set_sound controls

stripped down initalizing, cause most of the settings were unusefull
and default settings seems to be ok.

changed play() again. i put write_to_buffer() to the beginning of the
loop, so it seems more stable as before (less xruns).

outsourced xrun-handling.

added some cases to get_space() as xrun-handling, cause get_space() is
the first which trys to access sound and if some xrun occured it simply
stopped in the versions before.

added workaround if mplayer trys to call get_delay() without sound
being init. (nosound crash).

added nonblock-mode: this should be the prefered mode cause mplayer
should be the only app which uses the sounddevice and with nonblock
all samples are written continously to the buffer without waiting for
blocks are finished. cause i'm don't know if its
really stable and if all hardware support it, i consider it as
experimental. could be switched on with -noblock.

added mmap-mode: this is some kind of direct-write-transfer to memory
areas (zero-copy), which sould be result in faster communication.
till know only some kind of mmap-emulation is implemented but could be
improved in future. cause im also don't know if its really stable on
all hardware and it's not fully implemented i consider it as
exeprimental. it could be probably switched on with -mmap.

i would add these opts to cfg-mplayer.h, don't know what the 'core'
thinks about it? i see that there are 1000s of opts know, but its
easier to switch on theese features by runtime and play with it as
hardcode it in some config-header i think.

at least ao_alsa9 seems to be funtioning pretty well, cause the main
'bugs' are away, but i have tested it only with some creative cards.

alex if its no problem for you i will commit it to cvs (i found back
may old login again :).

-- 
regards

____-
joy

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

pgp key at: x-hkp://wwwkeys.de.pgp.net
-------------- next part --------------
--- mplayer.old/libao2/ao_alsa9.c	Tue Jul  2 06:03:21 2002
+++ mplayer/libao2/ao_alsa9.c	Tue Jul  2 01:24:29 2002
@@ -12,8 +12,7 @@
 #include <errno.h>
 #include <sys/time.h>
 #include <stdlib.h>
-//#include <unistd.h>
-//#include <string.h>
+#include <math.h>
 
 #include "../config.h"
 
@@ -48,24 +47,29 @@
 static snd_pcm_sw_params_t *alsa_swparams;
 static char *alsa_device;
 
-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. */
+/* possible 4096, original 8192, OUTBURST is set statically to 512 in config.h */
+static int alsa_fragsize = 4096; //OUTBURST
 static int alsa_fragcount = 8;
 
 static int chunk_size = -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
+int ao_mmap = 0;
+int ao_noblock = 0;
+
+static int open_mode;
+static int set_block_mode;
 
-#define BUFFERTIME /* last undef */
-#undef SET_PERIOD /* only function now is to set chunksize staticaly, last defined */
-#define SW_PARAMS /* last undef */
+#define ALSA_DEVICE_SIZE 48
 
+#undef BUFFERTIME
+#define SET_CHUNKSIZE
+#define SW_PARAMS
 
 snd_pcm_t *
+
 spdif_init(int acard, int adevice)
 {
 	//char *pcm_name = "hw:0,2"; /* first card second device */
@@ -149,8 +153,8 @@
              fprintf(stderr, "Broken configuration for this PCM: no configurations available");                                                                        
 	     return NULL;
 	  }
-	  err = snd_pcm_hw_params_set_access(handler, params,
-	  				    SND_PCM_ACCESS_RW_INTERLEAVED);
+
+	  err = snd_pcm_hw_params_set_access(handler, params,SND_PCM_ACCESS_RW_INTERLEAVED);
 	  if (err < 0) {
 	    fprintf(stderr, "Access tyep not available");
 	    return NULL;
@@ -186,7 +190,105 @@
 /* to set/get/query special features/parameters */
 static int control(int cmd, int arg)
 {
-    return(CONTROL_UNKNOWN);
+  switch(cmd) {
+  case AOCONTROL_QUERY_FORMAT:
+    return CONTROL_TRUE;
+  case AOCONTROL_GET_VOLUME:
+  case AOCONTROL_SET_VOLUME:
+    {
+      ao_control_vol_t *vol = (ao_control_vol_t *)arg;
+
+      int err;
+      snd_mixer_t *handle;
+      snd_mixer_elem_t *elem;
+      snd_mixer_selem_id_t *sid;
+
+      const char *mix_name = "PCM";
+      char *card = "default";
+
+      long pmin, pmax;
+      long get_vol, set_vol;
+      float calc_vol, diff, f_multi;
+
+      if(ao_data.format == AFMT_AC3)
+	return CONTROL_TRUE;
+
+      //allocate simple id
+      snd_mixer_selem_id_alloca(&sid);
+	
+      //sets simple-mixer index and name
+      snd_mixer_selem_id_set_index(sid, 0);
+      snd_mixer_selem_id_set_name(sid, mix_name);
+
+      if ((err = snd_mixer_open(&handle, 0)) < 0) {
+	printf("alsa-control: mixer open error: %s\n", snd_strerror(err));
+	return CONTROL_ERROR;
+      }
+
+      if ((err = snd_mixer_attach(handle, card)) < 0) {
+	printf("alsa-control: mixer attach %s error: %s", card, snd_strerror(err));
+	snd_mixer_close(handle);
+	return CONTROL_ERROR;
+      }
+
+      if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
+	printf("alsa-control: mixer register error: %s", snd_strerror(err));
+	snd_mixer_close(handle);
+	return CONTROL_ERROR;
+      }
+      err = snd_mixer_load(handle);
+      if (err < 0) {
+	printf("alsa-control: mixer load error: %s", snd_strerror(err));
+	snd_mixer_close(handle);
+	return CONTROL_ERROR;
+      }
+
+      elem = snd_mixer_find_selem(handle, sid);
+      if (!elem) {
+	printf("alsa-control: unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
+	snd_mixer_close(handle);
+	return CONTROL_ERROR;
+	}
+
+      snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
+      f_multi = (100 / (float)pmax);
+
+      if (cmd == AOCONTROL_SET_VOLUME) {
+
+	diff = (vol->left+vol->right) / 2;
+	set_vol = rint(diff / f_multi);
+	
+	if (set_vol < 0)
+	  set_vol = 0;
+	else if (set_vol > pmax)
+	  set_vol = pmax;
+
+	//setting channels
+	if ((err = snd_mixer_selem_set_playback_volume(elem, 0, set_vol)) < 0) {
+	  printf("alsa-control: error setting left channel, %s",snd_strerror(err));
+	  return CONTROL_ERROR;
+	}
+	if ((err = snd_mixer_selem_set_playback_volume(elem, 1, set_vol)) < 0) {
+	  printf("alsa-control: error setting right channel, %s",snd_strerror(err));
+	  return CONTROL_ERROR;
+	}
+
+	//printf("diff=%f, set_vol=%i, pmax=%i, mult=%f\n", diff, set_vol, pmax, f_multi);
+      }
+      else {
+	snd_mixer_selem_get_playback_volume(elem, 0, &get_vol);
+	calc_vol = get_vol;
+	calc_vol = rintf(calc_vol * f_multi);
+
+	vol->left = vol->right = (int)calc_vol;
+
+	//printf("get_vol = %i, calc=%i\n",get_vol, calc_vol);
+      }
+      snd_mixer_close(handle);
+      return CONTROL_OK;
+    }
+  }
+  return(CONTROL_UNKNOWN);
 }
 
 
@@ -198,11 +300,10 @@
 {
     int err;
     int cards = -1;
+    int period_val;
     snd_pcm_info_t *alsa_info;
+    char *str_block_mode;
     
-    size_t xfer_align; //new
-    snd_pcm_uframes_t start_threshold, stop_threshold; //new
-
     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));
@@ -223,7 +324,7 @@
     ao_data.format = format;
     ao_data.channels = channels;
     ao_data.outburst = OUTBURST;
-    ao_data.buffersize = 16384;
+    ao_data.buffersize = MAX_OUTBURST; // was 16384
 
     switch (format)
     {
@@ -267,10 +368,10 @@
 		audio_out_format_name(format));
 	    return(0);
 	default:
-	    break;
+	    break;	    
     }
     
-    if (ao_subdevice != NULL) // ?? makes no sense
+    if (ao_subdevice != NULL)
 	alsa_device = ao_subdevice;
 
     if (alsa_device == NULL)
@@ -319,14 +420,46 @@
 	    // Try to initialize the SPDIF interface
 	    alsa_handler = spdif_init(0, 2);
     }	    
-   
+
+    //setting modes for block or nonblock-mode
+    if (ao_noblock) {
+      open_mode = SND_PCM_NONBLOCK;
+      set_block_mode = 1;
+      str_block_mode = "nonblock-mode";
+    }
+    else {
+      open_mode = 0;
+      set_block_mode = 0;
+      str_block_mode = "block-mode";
+    }
+      
+
+    //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
     if (!alsa_handler) {
-	    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);
+      if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, open_mode)) < 0)
+	{
+	  if (ao_noblock) {
+	    printf("alsa-init: open in nonblock-mode failed, trying to open in block-mode\n");
+	    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);
+	    } else {
+	      set_block_mode = 0;
+	      str_block_mode = "block-mode";
 	    }
-    }	    
+	  } else {
+	    printf("alsa-init: playback open error: %s\n", snd_strerror(err));
+	    return(0);
+	  }
+	}
+    }
+
+    if ((err = snd_pcm_nonblock(alsa_handler, set_block_mode)) < 0) {
+      printf("alsa-init: error set block-mode %s\n", snd_strerror(err));
+    }
+    else if (verbose) {
+      printf("alsa-init: pcm opend in %s\n", str_block_mode);
+    }
 
     snd_pcm_hw_params_alloca(&alsa_hwparams);
     snd_pcm_sw_params_alloca(&alsa_swparams);
@@ -339,12 +472,21 @@
 	return(0);
     }
     
-    if ((err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
-	SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
-    {
-	printf("alsa-init: unable to set access type: %s\n",
-	    snd_strerror(err));
-	return(0);
+    if (ao_mmap) {
+      snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
+      snd_pcm_access_mask_none(mask);
+      snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+      snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
+      snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
+      err = snd_pcm_hw_params_set_access_mask(alsa_handler, alsa_hwparams, mask);
+      printf("alsa-init: mmap set\n");
+    } else {
+      err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,SND_PCM_ACCESS_RW_INTERLEAVED);
+      printf("alsa-init: interleave set\n");
+    }
+    if (err < 0) {
+      printf("alsa-init: unable to set access type: %s\n", snd_strerror(err));
+      return (0);
     }
     
     if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
@@ -367,21 +509,9 @@
         {
     	printf("alsa-init: unable to set samplerate-2: %s\n",
     	    snd_strerror(err));
-	//snd_pcm_hw_params_dump(alsa_hwparams, errlog); jp
     	return(0);
         }
 
-
-#ifdef SET_PERIOD
-    {
-	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));
-	    return(0);
-	}
-    }
-#endif
-
 #ifdef BUFFERTIME
     {
       int alsa_buffer_time = 500000; /* original 60 */
@@ -406,36 +536,33 @@
     }
 #endif
 
-    /* get chunk-size */
-    if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, 0)) < 0)
+#ifdef SET_CHUNKSIZE
+ {
+    //set chunksize
+    chunk_size = alsa_fragsize / 4;
+
+    if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, chunk_size, 0)) < 0)
       {
-	printf("alsa-init: unable to get chunk-size in hw-params: %s\n", snd_strerror(err));
+	printf("alsa-init: unable to set periodsize: %s\n", snd_strerror(err));
 	return(0);
-      } else
-	{
-	  chunk_size = err;
-	  if (verbose) {printf("alsa-init: got chunksize %i\n", chunk_size);}
+      }
+    else if (verbose) {
+      printf("alsa-init: chunksize set to %i\n", chunk_size);
+    }
+
+    //set period_count
+    if ((period_val = snd_pcm_hw_params_get_periods_max(alsa_hwparams, 0)) < alsa_fragcount) {
+			alsa_fragcount = period_val;			
 	}
 
-    /* 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 (verbose)
+      printf("alsa-init: current val=%i, fragcount=%i\n", period_val, alsa_fragcount);
 
-    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);
-      }
+    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));
+    }
+ }
+#endif
 
     /* finally install hardware parameters */
     if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
@@ -446,34 +573,22 @@
     }
     // end setting hw-params
 
-#ifdef SW_PARAMS
-    {
-      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;
+    // gets buffersize for control
+    if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0)
+      {
+	printf("alsa-init: unable to get buffersize: %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 (verbose) {
-	printf("alsa-init: start_threshold=%lu, stop_threshold=%lu\n",start_threshold,stop_threshold);
-	printf("alsa-init: n=%i\n", n);
-      }
+    // setting sw-params (only avail-min) if noblocking mode was choosed
+    if (ao_noblock)
+    {
 
     if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0)
       {
@@ -482,30 +597,12 @@
       }
 
     //set min available frames to consider pcm ready (4)
-    if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, 4)) < 0)
+    //increased for nonblock-mode should be set dynamically later
+    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);
-      }
-
-    //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);
-      }
 
     if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0)
       {
@@ -519,9 +616,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);}
-    }
 
-#endif //end swparams
+    }//end swparams
 
     if ((err = snd_pcm_prepare(alsa_handler)) < 0)
     {
@@ -539,48 +635,52 @@
 /* close audio device */
 static void uninit()
 {
-    int err;
-
-    //if (alsa_device != NULL)
-    //free(alsa_device);
 
-    //snd_pcm_hw_params_free(alsa_hwparams);
+  if (alsa_handler) {
+    int err;
 
-    if ((err = snd_pcm_drain(alsa_handler)) < 0)
-    {
-	printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err));
-	return;
+    if (!ao_noblock) {
+      if ((err = snd_pcm_drain(alsa_handler)) < 0)
+	{
+	  printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err));
+	  return;
+	}
     }
 
     if ((err = snd_pcm_close(alsa_handler)) < 0)
-    {
+      {
 	printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err));
 	return;
-    }
+      }
     else {
       alsa_handler = NULL;
       alsa_device = NULL;
       printf("alsa-uninit: pcm closed\n");
     }
+  }
+  else {
+    printf("alsa-uninit: no handler defined!\n");
+  }
 }
 
 static void audio_pause()
 {
     int err;
 
-    if ((err = snd_pcm_drain(alsa_handler)) < 0)
-    {
-	printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err));
-	return;
+    if (!ao_noblock) {
+      //drain causes error in nonblock-mode!
+      if ((err = snd_pcm_drain(alsa_handler)) < 0)
+	{
+	  printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err));
+	  return;
+	}
     }
+    else {
+      if (verbose)
+	printf("alsa-pause: paused nonblock\n");
 
-#ifdef reset
-    if ((err = snd_pcm_reset(alsa_handler)) < 0)
-    {
-	printf("alsa-pause: pcm reset error: %s\n", snd_strerror(err));
-	return;
+      return;
     }
-#endif
 }
 
 static void audio_resume()
@@ -599,18 +699,24 @@
 {
     int err;
 
-    if ((err = snd_pcm_drain(alsa_handler)) < 0)
-    {
-	printf("alsa-reset: pcm drain error: %s\n", snd_strerror(err));
-	return;
-    }
+    if (!ao_noblock) {
+      //drain causes error in nonblock-mode!
+      if ((err = snd_pcm_drain(alsa_handler)) < 0)
+	{
+	  printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err));
+	  return;
+	}
 
-    if ((err = snd_pcm_prepare(alsa_handler)) < 0)
-    {
-	printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err));
-	return;
+      if ((err = snd_pcm_prepare(alsa_handler)) < 0)
+	{
+	  printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err));
+	  return;
+	}
+    } else {
+      if (verbose)
+	printf("alsa-reset: reset nonblocked");
+      return;
     }
-
 }
 
 #ifndef timersub
@@ -625,61 +731,96 @@
 } while (0)
 #endif
 
+/* I/O error handler */
+static int xrun(u_char *str_mode)
+{
+  int err;
+  snd_pcm_status_t *status;
+
+  snd_pcm_status_alloca(&status);
+  
+  if ((err = snd_pcm_status(alsa_handler, status))<0) {
+    printf("status error: %s", snd_strerror(err));
+    return(0);
+  }
+
+  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-%s: xrun of at least %.3f msecs. resetting stream\n",
+	   str_mode,
+	   diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
+  }
+
+  if ((err = snd_pcm_prepare(alsa_handler))<0) {
+    printf("xrun: prepare error: %s", snd_strerror(err));
+    return(0);
+  }
+
+  return(1); /* ok, data should be accepted again */
+}
+
 /*
     plays 'len' bytes of 'data'
     returns: number of bytes played
-    modified last at 26.06.02 by jp
+    modified last at 29.06.02 by jp
+    thanxs for marius <marius at rospot.com> for giving us the light ;)
 */
 
 static int play(void* data, int len, int flags)
 {
 
-  snd_pcm_status_t *status;
-
-  int num_frames=len/ao_data.bps;
+  //ao_data.bps is always 4 cause its set to channels * 2 by alsa_format??
+  int num_frames = len / ao_data.bps;
   signed short *output_samples=data;
   snd_pcm_sframes_t res = 0;
 
+  //printf("alsa-play: frames=%i, len=%i",num_frames,len);
+
   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");
+  while (num_frames > 0) {
+
+      if (ao_mmap) {
+	res = snd_pcm_mmap_writei(alsa_handler, (void *)output_samples, num_frames);
       } 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;
-    }
+	res = snd_pcm_writei(alsa_handler, (void *)output_samples, num_frames);
+      }
+
+      if (res == -EAGAIN) {
+	snd_pcm_wait(alsa_handler, 1000);
+      }
+      else if (res == -EPIPE) {  /* underrun */
+	if (xrun("play") <= 0) {
+	  printf("alsa-play: xrun reset error");
+	  return(0);
+	}
+      }
+      else if (res == -ESTRPIPE) {	/* suspend */
+	printf("alsa-play: pcm in suspend mode. trying to resume\n");
+	while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
+	  sleep(1);
+      }
+      else if (res < 0) {
+	printf("alsa-play: unknown status, trying to reset soundcard\n");
+	if ((res = snd_pcm_prepare(alsa_handler)) < 0) {
+	  printf("alsa-play: snd prepare error");
+	  return(0);
+	  break;
+	}
+      }
 
-  } while (res == -EPIPE || num_frames > 0);
+      if (res > 0) {
+	output_samples += ao_data.channels * res;
+	num_frames -= res;
+      }
+
+  } //end while
 
   if (res < 0) {
     printf("alsa-play: write error %s", snd_strerror(res));
@@ -688,12 +829,14 @@
   return res < 0 ? (int)res : len;
 }
 
-
 /* how many byes are free in the buffer */
 static int get_space()
 {
     snd_pcm_status_t *status;
     int ret;
+    char *str_status;
+
+    //snd_pcm_sframes_t avail_frames = 0;
     
     if ((ret = snd_pcm_status_malloc(&status)) < 0)
     {
@@ -709,26 +852,50 @@
     
     switch(snd_pcm_status_get_state(status))
     {
-	case SND_PCM_STATE_OPEN:
-	case SND_PCM_STATE_PREPARED:
-	case SND_PCM_STATE_RUNNING:
-	    ret = snd_pcm_status_get_avail(status) * ao_data.bps;
-	    break;
-	default:
-	    ret = 0;
+    case SND_PCM_STATE_OPEN:
+      str_status = "open";
+    case SND_PCM_STATE_PREPARED:
+      if (str_status != "open")
+	str_status = "prepared";
+    case SND_PCM_STATE_RUNNING:
+      ret = snd_pcm_status_get_avail(status) * ao_data.bps;
+      //avail_frames = snd_pcm_avail_update(alsa_handler) * ao_data.bps;
+      if (str_status != "open" && str_status != "prepared")
+	str_status = "running";
+      break;
+    case SND_PCM_STATE_PAUSED:
+      if (verbose) printf("alsa-space: paused");
+      str_status = "paused";
+      ret = 0;
+      break;
+    case SND_PCM_STATE_XRUN:
+      xrun("space");
+      str_status = "xrun";
+      ret = 0;
+      break;
+    default:
+      str_status = "undefined";
+      ret = 0;
     }
-    
+
+    if (verbose && str_status != "running")
+      printf("alsa-space: free space = %i, status=%i, %s --\n", ret, status, str_status);
     snd_pcm_status_free(status);
     
-    if (ret < 0)
+    if (ret < 0) {
+      printf("negative value!!\n");
       ret = 0;
-    //printf("alsa-space: free space = %i",ret);
+    }
+ 
     return(ret);
 }
 
 /* delay in seconds between first and last sample in buffer */
 static float get_delay()
 {
+
+  if (alsa_handler) {
+
     snd_pcm_status_t *status;
     float ret;
     
@@ -760,4 +927,8 @@
     if (ret < 0)
       ret = 0;
     return(ret);
+    
+  } else {
+    return(0);
+  }
 }
-------------- next part --------------
--- mplayer.old/mplayer_user/cfg-mplayer.h	Tue Jun 25 10:09:16 2002
+++ mplayer/cfg-mplayer.h	Mon Jul  1 22:39:38 2002
@@ -66,6 +66,12 @@
 extern char *ao_outputfilename;
 extern int ao_pcm_waveheader;
 
+/* adds mmap-support in alsa9 */
+#ifdef HAVE_ALSA9
+extern int ao_mmap;
+extern int ao_noblock;
+#endif
+
 #ifdef HAVE_X11
 extern char *mDisplayName;
 extern int WinID;
@@ -166,6 +166,11 @@
 	{"vo", &video_driver, CONF_TYPE_STRING, 0, 0, 0, NULL},
 	{"ao", &audio_driver, CONF_TYPE_STRING, 0, 0, 0, NULL},
 
+#ifdef HAVE_ALSA9
+	{"mmap", &ao_mmap, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+	{"noblock", &ao_noblock, CONF_TYPE_FLAG, 0, 0, 1, NULL},
+#endif
+	
 	{"aop", ao_plugin_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
 	{"dsp", "Use -ao oss:dsp_path!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
         {"mixer", &mixer_device, CONF_TYPE_STRING, 0, 0, 0, NULL},


More information about the MPlayer-dev-eng mailing list