--- libao2/ao_oss.c.orig	2021-04-15 19:26:53 UTC
+++ libao2/ao_oss.c
@@ -57,6 +57,8 @@ static const ao_info_t info =
 	""
 };
 
+static int volume = -1;
+
 /* Support for >2 output channels added 2001-11-25 - Steve Davies <steve@daviesfam.org> */
 
 LIBAO_EXTERN(oss)
@@ -73,6 +75,11 @@ static int format2oss(int format)
     case AF_FORMAT_S16_BE: return AFMT_S16_BE;
 #ifdef AFMT_S24_PACKED
     case AF_FORMAT_S24_LE: return AFMT_S24_PACKED;
+#elif defined(__FreeBSD__) && defined(AFMT_S24_LE)
+    case AF_FORMAT_U24_LE: return AFMT_U24_LE;
+    case AF_FORMAT_U24_BE: return AFMT_U24_BE;
+    case AF_FORMAT_S24_LE: return AFMT_S24_LE;
+    case AF_FORMAT_S24_BE: return AFMT_S24_BE;
 #endif
 #ifdef AFMT_U32_LE
     case AF_FORMAT_U32_LE: return AFMT_U32_LE;
@@ -116,6 +123,11 @@ static int oss2format(int format)
     case AFMT_S16_BE: return AF_FORMAT_S16_BE;
 #ifdef AFMT_S24_PACKED
     case AFMT_S24_PACKED: return AF_FORMAT_S24_LE;
+#elif defined(__FreeBSD__) && defined(AFMT_S24_LE)
+    case AFMT_U24_LE: return AF_FORMAT_U24_LE;
+    case AFMT_U24_BE: return AF_FORMAT_U24_BE;
+    case AFMT_S24_LE: return AF_FORMAT_S24_LE;
+    case AFMT_S24_BE: return AF_FORMAT_S24_BE;
 #endif
 #ifdef AFMT_U32_LE
     case AFMT_U32_LE: return AF_FORMAT_U32_LE;
@@ -217,6 +229,48 @@ static int control(int cmd,void *arg){
     return CONTROL_UNKNOWN;
 }
 
+static void setfragment(int audio_fd)
+{
+    int buffer_bytes = ao_data.channels * ao_data.samplerate;
+    int block_size = 0;
+
+    switch (ao_data.format & AF_FORMAT_BITS_MASK) {
+    case AF_FORMAT_8BIT:
+      break;
+    case AF_FORMAT_16BIT:
+      buffer_bytes *= 2;
+      break;
+    case AF_FORMAT_24BIT:
+      buffer_bytes *= 3;
+      break;
+    case AF_FORMAT_32BIT:
+      buffer_bytes *= 4;
+      break;
+    }
+    buffer_bytes *= 0.050;
+
+    if(ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &block_size)==0){
+      int setfrag;
+      /* make block size power of two */
+      while (block_size & (block_size - 1))
+         block_size += block_size & ~(block_size - 1);
+      /* set number of fragments */
+      setfrag = ((buffer_bytes + block_size - 1) / block_size) << 16;
+      /* need at least double buffering */
+      if (setfrag < (2 << 16))
+        setfrag = (2 << 16);
+      /* set block size in power of two */
+      while (block_size) {
+        setfrag++;
+        block_size /= 2;
+      }
+      /* try to set a total buffer of 50ms */
+      if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &setfrag)==-1){
+        mp_msg(MSGT_AO,MSGL_V,"audio_setup: setfragment %d failed\n", setfrag);
+      }
+    }
+}
+
 // open & setup audio device
 // return: 1=success 0=fail
 static int init(int rate,int channels,int format,int flags){
@@ -364,6 +418,7 @@ ac3_retry:
       mp_msg(MSGT_AO,MSGL_WARN, "OSS: Failed setting sample-rate %i %s\n", rate, strerror(errno));
     mp_msg(MSGT_AO,MSGL_V,"audio_setup: using %d Hz samplerate (requested: %d)\n",ao_data.samplerate,rate);
   }
+  setfragment(audio_fd);
 
   if(ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz)==-1){
       int r=0;
@@ -441,10 +496,30 @@ static void uninit(int immed){
     audio_fd = -1;
 }
 
+static void savevol(void){
+	int fd;
+	if (volume < 0) {
+		if ((fd = open(oss_mixer_device, O_RDONLY)) >= 0) { 
+			ioctl(fd, MIXER_READ(oss_mixer_channel), &volume);
+			close(fd);
+		}
+	}     
+}
+
+static void restorevol(void){
+	int fd;
+	if ((fd = open(oss_mixer_device, O_RDONLY)) >= 0) {
+		ioctl(fd, MIXER_WRITE(oss_mixer_channel), &volume);
+		close(fd);
+	}
+	volume = -1;     
+}
+
 // stop playing and empty buffers (for seeking/pause)
 static void reset(void){
   int fail = 0;
   int oss_format;
+    savevol();
     uninit(1);
     audio_fd=open(dsp, O_WRONLY);
     if(audio_fd < 0){
@@ -456,6 +531,7 @@ static void reset(void){
   fcntl(audio_fd, F_SETFD, FD_CLOEXEC);
 #endif
 
+  ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
   oss_format = format2oss(ao_data.format);
   if(AF_FORMAT_IS_AC3(ao_data.format))
     fail |= ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate) == -1;
@@ -471,11 +547,14 @@ static void reset(void){
   }
   if (fail)
     mp_msg(MSGT_AO,MSGL_WARN, "OSS: Reset failed\n");
+  setfragment(audio_fd);
+  restorevol();
 }
 
 // stop playing, keep buffers (for pause)
 static void audio_pause(void)
 {
+    savevol();
     prepause_space = get_space();
     uninit(1);
 }
