audio/xmms: sndio plugin update to test

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

audio/xmms: sndio plugin update to test

Alexandre Ratchov-2
This fixes threading bugs guenther found when we switched to
rthreads. Most changes are copy & paste from audacious.

Basically, call any sio_* function with the mutex locked. But since
we can't hold the mutex locked during blocking operations (the GUI
would block) use a simple "event loop" with non-blocking i/o.

Regressions? Comments? OKs?

-- Alexandre

Index: Makefile
===================================================================
RCS file: /cvs/ports/audio/xmms/Makefile,v
retrieving revision 1.79
diff -u -p -r1.79 Makefile
--- Makefile 9 Aug 2012 17:54:47 -0000 1.79
+++ Makefile 26 Aug 2012 19:21:35 -0000
@@ -10,7 +10,7 @@ SHARED_ONLY= Yes
 VERSION= 1.2.11
 DISTNAME= xmms-${VERSION}
 PKGNAME-main= xmms-${VERSION}
-REVISION-main= 10
+REVISION-main= 11
 PKGNAME-vorbis= xmms-vorbis-${VERSION}
 REVISION-vorbis= 4
 PKGNAME-mikmod= xmms-mikmod-${VERSION}
Index: files/audio_sndio.c
===================================================================
RCS file: /cvs/ports/audio/xmms/files/audio_sndio.c,v
retrieving revision 1.3
diff -u -p -r1.3 audio_sndio.c
--- files/audio_sndio.c 5 Dec 2010 15:52:19 -0000 1.3
+++ files/audio_sndio.c 26 Aug 2012 19:21:35 -0000
@@ -14,9 +14,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <errno.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <gtk/gtk.h>
 #include <libxmms/util.h>
@@ -54,8 +57,8 @@ static struct sio_par par;
 static struct sio_hdl *hdl;
 static long long rdpos;
 static long long wrpos;
-static int paused;
-static int volume = XMMS_MAXVOL;
+static int paused, restarted, volume;
+static int pause_pending, flush_pending, volume_pending;
 static long bytes_per_sec;
 static AFormat afmt;
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -91,6 +94,69 @@ get_oplugin_info (void)
 }
 
 static void
+reset(void)
+{
+ if (!restarted) {
+ restarted = 1;
+ sio_stop(hdl);
+ sio_start(hdl);
+ rdpos = wrpos;
+ }
+}
+static void
+onmove_cb (void *addr, int delta)
+{
+ rdpos += delta * (int)(par.bps * par.pchan);
+}
+
+static void
+onvol_cb(void *addr, unsigned ctl)
+{
+ /* Update volume only if it actually changed */
+ if (ctl != volume * SIO_MAXVOL / 100)
+ volume = ctl * 100 / SIO_MAXVOL;
+}
+
+static void
+wait_ready(void)
+{
+ int n;
+ struct pollfd pfds[16];
+
+ if (volume_pending) {
+ sio_setvol(hdl, volume * SIO_MAXVOL / 100);
+ volume_pending = 0;
+ }
+ if (flush_pending) {
+ reset();
+ flush_pending = 0;
+ }
+ if (pause_pending) {
+ if (paused)
+ reset();
+ pause_pending = 0;
+ }
+ if (paused) {
+ pthread_mutex_unlock(&mutex);
+ usleep(20000);
+ pthread_mutex_lock(&mutex);
+ return;
+ }
+ n = sio_pollfd(hdl, pfds, POLLOUT);
+ if (n != 0) {
+ pthread_mutex_unlock(&mutex);
+ while (poll(pfds, n, -1) < 0) {
+ if (errno != EINTR) {
+ perror("poll");
+ exit(1);
+ }
+ }
+ pthread_mutex_lock(&mutex);
+ }
+ (void)sio_revents(hdl, pfds);
+}
+
+static void
 op_about (void)
 {
  static GtkWidget *about;
@@ -118,7 +184,7 @@ op_init (void)
  xmms_cfg_free(cfgfile);
 
  if (!audiodev)
- audiodev = g_strdup("");
+ audiodev = g_strdup(SIO_DEVANY);
 }
 
 static void
@@ -146,13 +212,11 @@ op_open (AFormat fmt, int rate, int nch)
  struct sio_par askpar;
 
  pthread_mutex_lock (&mutex);
-
- hdl = sio_open (strlen (audiodev) > 0 ? audiodev : NULL, SIO_PLAY, 0);
+ hdl = sio_open (audiodev, SIO_PLAY, 1);
  if (hdl == NULL) {
  fprintf (stderr, "%s: failed to open audio device\n", __func__);
  goto error;
  }
-
  sio_initpar (&par);
  afmt = fmt;
  switch (fmt) {
@@ -225,17 +289,18 @@ op_open (AFormat fmt, int rate, int nch)
  rdpos = 0;
  wrpos = 0;
  sio_onmove (hdl, onmove_cb, NULL);
-
- paused = 0;
+ sio_onvol (hdl, onvol_cb, NULL);
+ sio_setvol(hdl, volume * SIO_MAXVOL / 100);
  if (!sio_start (hdl)) {
  fprintf (stderr, "%s: failed to start audio device\n",
  __func__);
  goto error;
  }
-
  bytes_per_sec = par.bps * par.pchan * par.rate;
+ pause_pending = flush_pending = volume_pending = 0;
+ restarted = 1;
+ paused = 0;
  pthread_mutex_unlock (&mutex);
- op_set_volume (volume, volume);
  return TRUE;
 
 error:
@@ -247,11 +312,9 @@ error:
 static void
 op_write (void *ptr, int len)
 {
+ unsigned n;
  EffectPlugin *ep;
 
- if (paused)
- return;
-
  /* This sucks but XMMS totally broke the effect plugin code when
    they added support for multiple enabled effects.  Complain to
    the non-existent XMMS team if a plugin does not work, however
@@ -259,13 +322,22 @@ op_write (void *ptr, int len)
  ep = get_current_effect_plugin ();
  ep->mod_samples (&ptr, len, afmt, par.rate, par.pchan);
 
- /* Do not lock sio_write as this will cause the GUI thread
-   to block waiting for a blocked sio_write to return. */
- len = sio_write (hdl, ptr, len);
-
- pthread_mutex_lock (&mutex);
- wrpos += len;
- pthread_mutex_unlock (&mutex);
+ pthread_mutex_lock(&mutex);
+ for (;;) {
+ if (paused)
+ break;
+ restarted = 0;
+ n = sio_write(hdl, ptr, len);
+ if (n == 0 && sio_eof(hdl))
+ return;
+ wrpos += n;
+ len -= n;
+ ptr = (char *)ptr + n;
+ if (len == 0)
+ break;
+ wait_ready();
+ }
+ pthread_mutex_unlock(&mutex);
 }
 
 static void
@@ -280,28 +352,30 @@ op_close (void)
 }
 
 static void
-op_seek (int time_ms)
+op_seek (int time)
 {
- int bufused;
+ int used;
 
  pthread_mutex_lock (&mutex);
- bufused = (rdpos < 0) ? wrpos : wrpos - rdpos;
- rdpos = time_ms / 1000 * bytes_per_sec;
- wrpos = rdpos + bufused;
+ used = wrpos - rdpos;
+ rdpos = (long long)time * bytes_per_sec / 1000;
+ wrpos = rdpos + used;
  pthread_mutex_unlock (&mutex);
 }
 
 static void
 op_pause (short flag)
 {
+ pthread_mutex_lock(&mutex);
  paused = flag;
+ pause_pending = 1;
+ pthread_mutex_unlock(&mutex);
 }
 
 static int
 op_buffer_free (void)
 {
-#define MAGIC 1000000 /* See Output/{OSS,sun,esd}/audio.c */
- return paused ? 0 : MAGIC;
+ return paused ? 0 : par.round * par.pchan * par.bps;
 }
 
 static int
@@ -333,14 +407,6 @@ op_get_written_time (void)
 }
 
 static void
-onmove_cb (void *addr, int delta)
-{
- pthread_mutex_lock (&mutex);
- rdpos += delta * (int)(par.bps * par.pchan);
- pthread_mutex_unlock (&mutex);
-}
-
-static void
 op_configure(void)
 {
  GtkWidget *dev_vbox;
@@ -370,9 +436,6 @@ op_configure(void)
  adevice_vbox = gtk_vbox_new(FALSE, 5);
  gtk_container_set_border_width(GTK_CONTAINER(adevice_vbox), 5);
  gtk_container_add(GTK_CONTAINER(adevice_frame), adevice_vbox);
-
- adevice_text = gtk_label_new(_("(empty means default)"));
- gtk_box_pack_start_defaults(GTK_BOX(adevice_vbox), adevice_text);
 
  adevice_entry = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(adevice_entry), audiodev);

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Brett Mahar-2
On Sun, 26 Aug 2012 21:48:52 +0200
Alexandre Ratchov <[hidden email]> wrote:

> This fixes threading bugs guenther found when we switched to
> rthreads. Most changes are copy & paste from audacious.
>
> Basically, call any sio_* function with the mutex locked. But since
> we can't hold the mutex locked during blocking operations (the GUI
> would block) use a simple "event loop" with non-blocking i/o.
>
> Regressions? Comments? OKs?
>
> -- Alexandre

On amd64-current, (with -mp3 -vorbis and -mikmod subpackages installed as well) this does not output any sound for me using .mp3s or .oggs. The time display on xmms remains on 00:00.

I tried changing the output plugin audio device from default to snd/0 and rsnd/0, but still no playback.

I deleted pkg, plist, and rebuilt using the version without this new diff, and it plays mp3s and oggs no problem.

Normally I don't use xmms so please let me know if there are some other settings I should alter to test.

Brett.


===================

OpenBSD 5.2-current (GENERIC.MP) #21: Sun Aug 26 18:41:18 EST 2012
    [hidden email]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 3218997248 (3069MB)
avail mem = 3110948864 (2966MB)
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 2.5 @ 0xf0000 (45 entries)
bios0: vendor Phoenix version "R01-A1" date 03/02/2009
bios0: eMachines ET1300
acpi0 at bios0: rev 0
acpi0: sleep states S0 S3 S4 S5
acpi0: tables DSDT FACP SSDT HPET SLIC MCFG APIC
acpi0: wakeup devices HUB0(S5) XVR0(S5) XVR1(S5) XVR2(S5) USB0(S3) USB2(S3) AZAD(S5) MMAC(S5)
acpitimer0 at acpi0: 3579545 Hz, 24 bits
acpihpet0 at acpi0: 25000000 Hz
acpimcfg0 at acpi0 addr 0xf0000000, bus 0-63
acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: AMD Athlon(tm) Dual Core Processor 5050e , 2612.30 MHz
cpu0: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,CX16,NXE,MMXX,FFXSR,LONG,3DNOW2,3DNOW,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,3DNOWP
cpu0: 64KB 64b/line 2-way I-cache, 64KB 64b/line 2-way D-cache, 512KB 64b/line 16-way L2 cache
cpu0: ITLB 32 4KB entries fully associative, 8 4MB entries fully associative
cpu0: DTLB 32 4KB entries fully associative, 8 4MB entries fully associative
cpu0: apic clock running at 200MHz
cpu1 at mainbus0: apid 1 (application processor)
cpu1: AMD Athlon(tm) Dual Core Processor 5050e , 2611.88 MHz
cpu1: FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,CX16,NXE,MMXX,FFXSR,LONG,3DNOW2,3DNOW,LAHF,CMPLEG,SVM,EAPICSP,AMCR8,3DNOWP
cpu1: 64KB 64b/line 2-way I-cache, 64KB 64b/line 2-way D-cache, 512KB 64b/line 16-way L2 cache
cpu1: ITLB 32 4KB entries fully associative, 8 4MB entries fully associative
cpu1: DTLB 32 4KB entries fully associative, 8 4MB entries fully associative
ioapic0 at mainbus0: apid 4 pa 0xfec00000, version 11, 24 pins
ioapic0: misconfigured as apic 0, remapped to apid 4
acpiprt0 at acpi0: bus 0 (PCI0)
acpiprt1 at acpi0: bus 1 (HUB0)
acpicpu0 at acpi0: PSS
acpicpu1 at acpi0: PSS
acpitz0 at acpi0: critical temperature is 75 degC
acpibtn0 at acpi0: PWRB
cpu0: PowerNow! K8 2612 MHz: speeds: 2600 2400 2200 2000 1800 1000 MHz
pci0 at mainbus0 bus 0
"NVIDIA MCP61 Memory" rev 0xa1 at pci0 dev 0 function 0 not configured
pcib0 at pci0 dev 1 function 0 "NVIDIA MCP61 ISA" rev 0xa2
nviic0 at pci0 dev 1 function 1 "NVIDIA MCP61 SMBus" rev 0xa2
iic0 at nviic0
spdmem0 at iic0 addr 0x51: 1GB DDR2 SDRAM non-parity PC2-6400CL5
spdmem1 at iic0 addr 0x52: 1GB DDR2 SDRAM non-parity PC2-6400CL5
spdmem2 at iic0 addr 0x53: 1GB DDR2 SDRAM non-parity PC2-6400CL5
iic1 at nviic0
"NVIDIA MCP61 Memory" rev 0xa2 at pci0 dev 1 function 2 not configured
ohci0 at pci0 dev 2 function 0 "NVIDIA MCP61 USB" rev 0xa3: apic 4 int 10, version 1.0, legacy support
ehci0 at pci0 dev 2 function 1 "NVIDIA MCP61 USB" rev 0xa3: apic 4 int 11
usb0 at ehci0: USB revision 2.0
uhub0 at usb0 "NVIDIA EHCI root hub" rev 2.00/1.00 addr 1
ppb0 at pci0 dev 4 function 0 "NVIDIA MCP61" rev 0xa1
pci1 at ppb0 bus 1
azalia0 at pci0 dev 5 function 0 "NVIDIA MCP61 HD Audio" rev 0xa2: apic 4 int 11
azalia0: codecs: Realtek ALC888
audio0 at azalia0
pciide0 at pci0 dev 6 function 0 "NVIDIA MCP61 IDE" rev 0xa2: DMA, channel 0 configured to compatibility, channel 1 configured to compatibility
pciide0: channel 0 disabled (no drives)
pciide0: channel 1 ignored (disabled)
nfe0 at pci0 dev 7 function 0 "NVIDIA MCP61 LAN" rev 0xa2: apic 4 int 15, address 00:25:11:3e:44:93
rlphy0 at nfe0 phy 1: RTL8201L 10/100 PHY, rev. 1
pciide1 at pci0 dev 8 function 0 "NVIDIA MCP61 SATA" rev 0xa2: DMA
pciide1: using apic 4 int 11 for native-PCI interrupt
wd0 at pciide1 channel 0 drive 0: <ST3160318AS>
wd0: 16-sector PIO, LBA48, 152627MB, 312581808 sectors
wd0(pciide1:0:0): using PIO mode 4, Ultra-DMA mode 6
wd1 at pciide1 channel 1 drive 0: <ST2000DM001-1CH164>
wd1: 16-sector PIO, LBA48, 1907729MB, 3907029168 sectors
wd1(pciide1:1:0): using PIO mode 4, Ultra-DMA mode 6
pciide2 at pci0 dev 8 function 1 "NVIDIA MCP61 SATA" rev 0xa2: DMA
pciide2: using apic 4 int 10 for native-PCI interrupt
atapiscsi0 at pciide2 channel 0 drive 0
scsibus0 at atapiscsi0: 2 targets
cd0 at scsibus0 targ 0 lun 0: <HL-DT-ST, DVDRAM GH40F, MG01> ATAPI 5/cdrom removable
cd0(pciide2:0:0): using PIO mode 4, Ultra-DMA mode 5
wd2 at pciide2 channel 1 drive 0: <WDC WD5000AADS-00M2B0>
wd2: 16-sector PIO, LBA48, 476940MB, 976773168 sectors
wd2(pciide2:1:0): using PIO mode 4, Ultra-DMA mode 6
ppb1 at pci0 dev 9 function 0 "NVIDIA MCP61 PCIE" rev 0xa2
pci2 at ppb1 bus 3
vga1 at pci2 dev 0 function 0 vendor "NVIDIA", unknown product 0x06e6 rev 0xa1
wsdisplay0 at vga1 mux 1: console (80x25, vt100 emulation)
wsdisplay0: screen 1-5 added (80x25, vt100 emulation)
ppb2 at pci0 dev 11 function 0 "NVIDIA MCP61 PCIE" rev 0xa2
pci3 at ppb2 bus 4
ppb3 at pci0 dev 12 function 0 "NVIDIA MCP61 PCIE" rev 0xa2
pci4 at ppb3 bus 5
pchb0 at pci0 dev 24 function 0 "AMD AMD64 0Fh HyperTransport" rev 0x00
pchb1 at pci0 dev 24 function 1 "AMD AMD64 0Fh Address Map" rev 0x00
pchb2 at pci0 dev 24 function 2 "AMD AMD64 0Fh DRAM Cfg" rev 0x00
kate0 at pci0 dev 24 function 3 "AMD AMD64 0Fh Misc Cfg" rev 0x00: core rev BH-G2
isa0 at pcib0
isadma0 at isa0
pckbc0 at isa0 port 0x60/5
pckbd0 at pckbc0 (kbd slot)
pckbc0: using irq 1 for kbd slot
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
it0 at isa0 port 0x2e/2: IT8726F rev 3, EC port 0x290
usb1 at ohci0: USB revision 1.0
uhub1 at usb1 "NVIDIA OHCI root hub" rev 1.00/1.00 addr 1
mtrr: Pentium Pro MTRR support
umass0 at uhub0 port 9 configuration 1 interface 0 "Generic Mass Storage Device" rev 2.00/1.00 addr 2
umass0: using SCSI over Bulk-Only
scsibus1 at umass0: 2 targets, initiator 0
sd0 at scsibus1 targ 1 lun 0: <Generic, Compact Flash, 0.00> SCSI2 0/direct removable
sd1 at scsibus1 targ 1 lun 1: <Generic, SD/MMC, 0.00> SCSI2 0/direct removable
sd2 at scsibus1 targ 1 lun 2: <Generic, microSD, 0.00> SCSI2 0/direct removable
sd3 at scsibus1 targ 1 lun 3: <Generic, MS/MS-PRO, 0.00> SCSI2 0/direct removable
sd4 at scsibus1 targ 1 lun 4: <Generic, SM/xD-Picture, 0.00> SCSI2 0/direct removable
uplcom0 at uhub1 port 1 "Prolific Technology Inc. USB-Serial Controller D" rev 1.10/4.00 addr 2
ucom0 at uplcom0
uhidev0 at uhub1 port 3 configuration 1 interface 0 "Logitech USB Receiver" rev 1.10/46.00 addr 3
uhidev0: iclass 3/1
ums0 at uhidev0: 8 buttons, Z dir
wsmouse0 at ums0 mux 0
uhidev1 at uhub1 port 3 configuration 1 interface 1 "Logitech USB Receiver" rev 1.10/46.00 addr 3
uhidev1: iclass 3/0, 16 report ids
uhid0 at uhidev1 reportid 16: input=6, output=6, feature=0
uhidev2 at uhub1 port 4 configuration 1 interface 0 "Holtek product 0x1203" rev 2.00/2.80 addr 4
uhidev2: iclass 3/1
ukbd0 at uhidev2: 8 variable keys, 6 key codes
wskbd1 at ukbd0 mux 1
wskbd1: connecting to wsdisplay0
uhidev3 at uhub1 port 4 configuration 1 interface 1 "Holtek product 0x1203" rev 2.00/2.80 addr 4
uhidev3: iclass 3/0, 2 report ids
uhid1 at uhidev3 reportid 1: input=1, output=0, feature=0
uhid2 at uhidev3 reportid 2: input=3, output=0, feature=0
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
scsibus3 at softraid0: 256 targets
root on wd2a (0b1f2f914f21fd86.a) swap on wd2b dump on wd2b
umass1 at uhub0 port 6 configuration 1 interface 0 "BUFFALO HD-PVU2" rev 2.00/1.04 addr 3
umass1: using SCSI over Bulk-Only
scsibus4 at umass1: 2 targets, initiator 0
sd5 at scsibus4 targ 1 lun 0: <BUFFALO, HD-PVU2, 1.04> SCSI2 0/direct fixed serial.04111101465A34303030
sd5: 476940MB, 512 bytes/sector, 976773168 sectors
sd5 detached
scsibus4 detached
umass1 detached
umass1 at uhub0 port 6 configuration 1 interface 0 "JetFlash Mass Storage Device" rev 2.00/1.00 addr 3
umass1: using SCSI over Bulk-Only
scsibus4 at umass1: 2 targets, initiator 0
sd5 at scsibus4 targ 1 lun 0: <JetFlash, Transcend 8GB, 8.07> SCSI2 0/direct removable
sd5: 7668MB, 512 bytes/sector, 15704064 sectors
sd5 detached
scsibus4 detached
umass1 detached

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Christian Weisgerber
In reply to this post by Alexandre Ratchov-2
Alexandre Ratchov <[hidden email]> wrote:

> This fixes threading bugs guenther found when we switched to
> rthreads. Most changes are copy & paste from audacious.
>
> Basically, call any sio_* function with the mutex locked. But since
> we can't hold the mutex locked during blocking operations (the GUI
> would block) use a simple "event loop" with non-blocking i/o.
>
> Regressions? Comments? OKs?

The good news is that this fixes the problem guenther@ found.
I can now play a directory full of MP3s just fine.  Streaming works,
too.  As do FLAC files, after installing xmms-flac.

The bad news is that this kills the Ogg Vorbis plugin.  I can't
play any Vorbis audio, neither local files nor streamed.  XMMS
doesn't crash, it just seems to stop playing immediately after
starting.  (Yes, I really have the Vorbis plugin installed.)

-current/amd64
--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Alexandre Ratchov-2
In reply to this post by Alexandre Ratchov-2
Thanks to all for the quick feedback. Below is a new diff; fixes
hangs with certain buffer size and updates the "unsupported format"
text.

-- Alexandre

Index: Makefile
===================================================================
RCS file: /cvs/ports/audio/xmms/Makefile,v
retrieving revision 1.79
diff -u -p -r1.79 Makefile
--- Makefile 9 Aug 2012 17:54:47 -0000 1.79
+++ Makefile 27 Aug 2012 23:23:15 -0000
@@ -10,7 +10,7 @@ SHARED_ONLY= Yes
 VERSION= 1.2.11
 DISTNAME= xmms-${VERSION}
 PKGNAME-main= xmms-${VERSION}
-REVISION-main= 10
+REVISION-main= 11
 PKGNAME-vorbis= xmms-vorbis-${VERSION}
 REVISION-vorbis= 4
 PKGNAME-mikmod= xmms-mikmod-${VERSION}
Index: files/audio_sndio.c
===================================================================
RCS file: /cvs/ports/audio/xmms/files/audio_sndio.c,v
retrieving revision 1.3
diff -u -p -r1.3 audio_sndio.c
--- files/audio_sndio.c 5 Dec 2010 15:52:19 -0000 1.3
+++ files/audio_sndio.c 27 Aug 2012 23:23:15 -0000
@@ -14,9 +14,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <errno.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <gtk/gtk.h>
 #include <libxmms/util.h>
@@ -54,8 +57,8 @@ static struct sio_par par;
 static struct sio_hdl *hdl;
 static long long rdpos;
 static long long wrpos;
-static int paused;
-static int volume = XMMS_MAXVOL;
+static int paused, restarted, volume;
+static int pause_pending, flush_pending, volume_pending;
 static long bytes_per_sec;
 static AFormat afmt;
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -91,6 +94,69 @@ get_oplugin_info (void)
 }
 
 static void
+reset(void)
+{
+ if (!restarted) {
+ restarted = 1;
+ sio_stop(hdl);
+ sio_start(hdl);
+ rdpos = wrpos;
+ }
+}
+static void
+onmove_cb (void *addr, int delta)
+{
+ rdpos += delta * (int)(par.bps * par.pchan);
+}
+
+static void
+onvol_cb(void *addr, unsigned ctl)
+{
+ /* Update volume only if it actually changed */
+ if (ctl != volume * SIO_MAXVOL / 100)
+ volume = ctl * 100 / SIO_MAXVOL;
+}
+
+static void
+wait_ready(void)
+{
+ int n;
+ struct pollfd pfds[16];
+
+ if (volume_pending) {
+ sio_setvol(hdl, volume * SIO_MAXVOL / 100);
+ volume_pending = 0;
+ }
+ if (flush_pending) {
+ reset();
+ flush_pending = 0;
+ }
+ if (pause_pending) {
+ if (paused)
+ reset();
+ pause_pending = 0;
+ }
+ if (paused) {
+ pthread_mutex_unlock(&mutex);
+ usleep(20000);
+ pthread_mutex_lock(&mutex);
+ return;
+ }
+ n = sio_pollfd(hdl, pfds, POLLOUT);
+ if (n != 0) {
+ pthread_mutex_unlock(&mutex);
+ while (poll(pfds, n, -1) < 0) {
+ if (errno != EINTR) {
+ perror("poll");
+ exit(1);
+ }
+ }
+ pthread_mutex_lock(&mutex);
+ }
+ (void)sio_revents(hdl, pfds);
+}
+
+static void
 op_about (void)
 {
  static GtkWidget *about;
@@ -118,7 +184,7 @@ op_init (void)
  xmms_cfg_free(cfgfile);
 
  if (!audiodev)
- audiodev = g_strdup("");
+ audiodev = g_strdup(SIO_DEVANY);
 }
 
 static void
@@ -146,13 +212,11 @@ op_open (AFormat fmt, int rate, int nch)
  struct sio_par askpar;
 
  pthread_mutex_lock (&mutex);
-
- hdl = sio_open (strlen (audiodev) > 0 ? audiodev : NULL, SIO_PLAY, 0);
+ hdl = sio_open (audiodev, SIO_PLAY, 1);
  if (hdl == NULL) {
  fprintf (stderr, "%s: failed to open audio device\n", __func__);
  goto error;
  }
-
  sio_initpar (&par);
  afmt = fmt;
  switch (fmt) {
@@ -217,7 +281,7 @@ op_open (AFormat fmt, int rate, int nch)
  fprintf (stderr, "%s: parameters not supported\n", __func__);
  xmms_show_message ("Unsupported format", "XMMS requested a "
  "format that is not supported by the audio device.\n\n"
- "Please try again with the aucat(1) server running.",
+ "Please try again with the sndiod(1) server running.",
  "OK", FALSE, NULL, NULL);
  goto error;
  }
@@ -225,17 +289,18 @@ op_open (AFormat fmt, int rate, int nch)
  rdpos = 0;
  wrpos = 0;
  sio_onmove (hdl, onmove_cb, NULL);
-
- paused = 0;
+ sio_onvol (hdl, onvol_cb, NULL);
+ sio_setvol(hdl, volume * SIO_MAXVOL / 100);
  if (!sio_start (hdl)) {
  fprintf (stderr, "%s: failed to start audio device\n",
  __func__);
  goto error;
  }
-
  bytes_per_sec = par.bps * par.pchan * par.rate;
+ pause_pending = flush_pending = volume_pending = 0;
+ restarted = 1;
+ paused = 0;
  pthread_mutex_unlock (&mutex);
- op_set_volume (volume, volume);
  return TRUE;
 
 error:
@@ -247,11 +312,9 @@ error:
 static void
 op_write (void *ptr, int len)
 {
+ unsigned n;
  EffectPlugin *ep;
 
- if (paused)
- return;
-
  /* This sucks but XMMS totally broke the effect plugin code when
    they added support for multiple enabled effects.  Complain to
    the non-existent XMMS team if a plugin does not work, however
@@ -259,13 +322,22 @@ op_write (void *ptr, int len)
  ep = get_current_effect_plugin ();
  ep->mod_samples (&ptr, len, afmt, par.rate, par.pchan);
 
- /* Do not lock sio_write as this will cause the GUI thread
-   to block waiting for a blocked sio_write to return. */
- len = sio_write (hdl, ptr, len);
-
- pthread_mutex_lock (&mutex);
- wrpos += len;
- pthread_mutex_unlock (&mutex);
+ pthread_mutex_lock(&mutex);
+ for (;;) {
+ if (paused)
+ break;
+ restarted = 0;
+ n = sio_write(hdl, ptr, len);
+ if (n == 0 && sio_eof(hdl))
+ break;
+ wrpos += n;
+ len -= n;
+ ptr = (char *)ptr + n;
+ if (len == 0)
+ break;
+ wait_ready();
+ }
+ pthread_mutex_unlock(&mutex);
 }
 
 static void
@@ -280,28 +352,30 @@ op_close (void)
 }
 
 static void
-op_seek (int time_ms)
+op_seek (int time)
 {
- int bufused;
+ int used;
 
  pthread_mutex_lock (&mutex);
- bufused = (rdpos < 0) ? wrpos : wrpos - rdpos;
- rdpos = time_ms / 1000 * bytes_per_sec;
- wrpos = rdpos + bufused;
+ used = wrpos - rdpos;
+ rdpos = (long long)time * bytes_per_sec / 1000;
+ wrpos = rdpos + used;
  pthread_mutex_unlock (&mutex);
 }
 
 static void
 op_pause (short flag)
 {
+ pthread_mutex_lock(&mutex);
  paused = flag;
+ pause_pending = 1;
+ pthread_mutex_unlock(&mutex);
 }
 
 static int
 op_buffer_free (void)
 {
-#define MAGIC 1000000 /* See Output/{OSS,sun,esd}/audio.c */
- return paused ? 0 : MAGIC;
+ return paused ? 0 : par.bufsz * par.pchan * par.bps;
 }
 
 static int
@@ -333,18 +407,10 @@ op_get_written_time (void)
 }
 
 static void
-onmove_cb (void *addr, int delta)
-{
- pthread_mutex_lock (&mutex);
- rdpos += delta * (int)(par.bps * par.pchan);
- pthread_mutex_unlock (&mutex);
-}
-
-static void
 op_configure(void)
 {
  GtkWidget *dev_vbox;
- GtkWidget *adevice_frame, *adevice_text, *adevice_vbox;
+ GtkWidget *adevice_frame, *adevice_vbox;
  GtkWidget *bbox, *ok, *cancel;
 
  if (configure_win) {
@@ -370,9 +436,6 @@ op_configure(void)
  adevice_vbox = gtk_vbox_new(FALSE, 5);
  gtk_container_set_border_width(GTK_CONTAINER(adevice_vbox), 5);
  gtk_container_add(GTK_CONTAINER(adevice_frame), adevice_vbox);
-
- adevice_text = gtk_label_new(_("(empty means default)"));
- gtk_box_pack_start_defaults(GTK_BOX(adevice_vbox), adevice_text);
 
  adevice_entry = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(adevice_entry), audiodev);

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Brett Mahar-2
In reply to this post by Christian Weisgerber

>
> The good news is that this fixes the problem guenther@ found.
> I can now play a directory full of MP3s just fine.  Streaming works,
> too.  As do FLAC files, after installing xmms-flac.
>
> -current/amd64

Also on amd64-current, I've got xmms (with the second diff that Alexandre sent out), xmms-flac, xmms-mikmod, xmms-mp3, xmms-vorbis installed, but I got no playback with mp3s, oggs, or flacs.

Is there some settings/configs you have changed from the default?

Brett.


Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Christian Weisgerber
Brett:

> Also on amd64-current, I've got xmms (with the second diff that Alexandre sent out), xmms-flac, xmms-mikmod, xmms-mp3, xmms-vorbis installed, but I got no playback with mp3s, oggs, or flacs.
>
> Is there some settings/configs you have changed from the default?

No.
I moved away my existing ~/.xmms and tried again--works just fine.

--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Brad Smith-14
In reply to this post by Alexandre Ratchov-2
On Tue, Aug 28, 2012 at 01:34:40AM +0200, Alexandre Ratchov wrote:
> Thanks to all for the quick feedback. Below is a new diff; fixes
> hangs with certain buffer size and updates the "unsupported format"
> text.

Brett, naddy or any other xmms users? Still looking for some
testing with the newer diff revision.

--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Brett Mahar-2
On Tue, 4 Sep 2012 20:08:52 -0400
Brad Smith <[hidden email]> wrote:

> On Tue, Aug 28, 2012 at 01:34:40AM +0200, Alexandre Ratchov wrote:
> > Thanks to all for the quick feedback. Below is a new diff; fixes
> > hangs with certain buffer size and updates the "unsupported format"
> > text.
>
> Brett, naddy or any other xmms users? Still looking for some
> testing with the newer diff revision.
>

Yes, the newest diff version that Alexandre sent to me (I don't think it went to the list) works fine for oggs, mp3s, and flacs (when the flac subpackage is installed). That is on amd64.

I guess when I reported that it works to Alexandre, I didn't notice ports was not cc'd, sorry.

Brett.

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Christian Weisgerber
In reply to this post by Brad Smith-14
Brad Smith <[hidden email]> wrote:

> Brett, naddy or any other xmms users? Still looking for some
> testing with the newer diff revision.

The second diff works fine for me and I told ratchov@ so.  I haven't
seen the third version Brett mentions.

--
Christian "naddy" Weisgerber                          [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Alexandre Ratchov-2
In reply to this post by Alexandre Ratchov-2
Here's the "final" xmms diff; I got two test reports only, but I
believe this is correct.

ok?

-- Alexandre

Index: Makefile
===================================================================
RCS file: /cvs/ports/audio/xmms/Makefile,v
retrieving revision 1.79
diff -u -p -r1.79 Makefile
--- Makefile 9 Aug 2012 17:54:47 -0000 1.79
+++ Makefile 6 Sep 2012 06:49:30 -0000
@@ -10,7 +10,7 @@ SHARED_ONLY= Yes
 VERSION= 1.2.11
 DISTNAME= xmms-${VERSION}
 PKGNAME-main= xmms-${VERSION}
-REVISION-main= 10
+REVISION-main= 11
 PKGNAME-vorbis= xmms-vorbis-${VERSION}
 REVISION-vorbis= 4
 PKGNAME-mikmod= xmms-mikmod-${VERSION}
Index: files/audio_sndio.c
===================================================================
RCS file: /cvs/ports/audio/xmms/files/audio_sndio.c,v
retrieving revision 1.3
diff -u -p -r1.3 audio_sndio.c
--- files/audio_sndio.c 5 Dec 2010 15:52:19 -0000 1.3
+++ files/audio_sndio.c 6 Sep 2012 06:49:30 -0000
@@ -14,9 +14,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <errno.h>
+#include <poll.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include <gtk/gtk.h>
 #include <libxmms/util.h>
@@ -44,8 +47,6 @@ static int op_playing (void);
 static int op_get_output_time (void);
 static int op_get_written_time (void);
 
-static void onmove_cb (void *, int);
-
 static void configure_win_ok_cb(GtkWidget *, gpointer);
 static void configure_win_cancel_cb(GtkWidget *, gpointer);
 static void configure_win_destroy(void);
@@ -54,8 +55,8 @@ static struct sio_par par;
 static struct sio_hdl *hdl;
 static long long rdpos;
 static long long wrpos;
-static int paused;
-static int volume = XMMS_MAXVOL;
+static int paused, restarted, volume;
+static int pause_pending, flush_pending, volume_pending;
 static long bytes_per_sec;
 static AFormat afmt;
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -91,6 +92,74 @@ get_oplugin_info (void)
 }
 
 static void
+reset(void)
+{
+ if (!restarted) {
+ restarted = 1;
+ sio_stop(hdl);
+ sio_start(hdl);
+ rdpos = wrpos;
+ }
+}
+static void
+onmove_cb (void *addr, int delta)
+{
+ rdpos += delta * (int)(par.bps * par.pchan);
+}
+
+static void
+onvol_cb(void *addr, unsigned ctl)
+{
+ /* Update volume only if it actually changed */
+ if (ctl != volume * SIO_MAXVOL / 100)
+ volume = ctl * 100 / SIO_MAXVOL;
+}
+
+static void
+pending_events(void)
+{
+ if (volume_pending) {
+ sio_setvol(hdl, volume * SIO_MAXVOL / 100);
+ volume_pending = 0;
+ }
+ if (flush_pending) {
+ reset();
+ flush_pending = 0;
+ }
+ if (pause_pending) {
+ if (paused)
+ reset();
+ pause_pending = 0;
+ }
+}
+
+static void
+wait_ready(void)
+{
+ int n;
+ struct pollfd pfds[16];
+
+ if (paused) {
+ pthread_mutex_unlock(&mutex);
+ usleep(20000);
+ pthread_mutex_lock(&mutex);
+ return;
+ }
+ n = sio_pollfd(hdl, pfds, POLLOUT);
+ if (n != 0) {
+ pthread_mutex_unlock(&mutex);
+ while (poll(pfds, n, -1) < 0) {
+ if (errno != EINTR) {
+ perror("poll");
+ exit(1);
+ }
+ }
+ pthread_mutex_lock(&mutex);
+ }
+ (void)sio_revents(hdl, pfds);
+}
+
+static void
 op_about (void)
 {
  static GtkWidget *about;
@@ -118,7 +187,7 @@ op_init (void)
  xmms_cfg_free(cfgfile);
 
  if (!audiodev)
- audiodev = g_strdup("");
+ audiodev = g_strdup(SIO_DEVANY);
 }
 
 static void
@@ -135,8 +204,7 @@ op_set_volume (int left, int right)
  /* Ignore balance control, so use unattenuated channel. */
  pthread_mutex_lock (&mutex);
  volume = left > right ? left : right;
- if (hdl != NULL)
- sio_setvol (hdl, volume * SIO_MAXVOL / XMMS_MAXVOL);
+ volume_pending = 1;
  pthread_mutex_unlock (&mutex);
 }
 
@@ -146,8 +214,7 @@ op_open (AFormat fmt, int rate, int nch)
  struct sio_par askpar;
 
  pthread_mutex_lock (&mutex);
-
- hdl = sio_open (strlen (audiodev) > 0 ? audiodev : NULL, SIO_PLAY, 0);
+ hdl = sio_open (audiodev, SIO_PLAY, 1);
  if (hdl == NULL) {
  fprintf (stderr, "%s: failed to open audio device\n", __func__);
  goto error;
@@ -217,7 +284,7 @@ op_open (AFormat fmt, int rate, int nch)
  fprintf (stderr, "%s: parameters not supported\n", __func__);
  xmms_show_message ("Unsupported format", "XMMS requested a "
  "format that is not supported by the audio device.\n\n"
- "Please try again with the aucat(1) server running.",
+ "Please try again with the sndiod(1) server running.",
  "OK", FALSE, NULL, NULL);
  goto error;
  }
@@ -225,17 +292,18 @@ op_open (AFormat fmt, int rate, int nch)
  rdpos = 0;
  wrpos = 0;
  sio_onmove (hdl, onmove_cb, NULL);
+ sio_onvol (hdl, onvol_cb, NULL);
 
+ bytes_per_sec = par.bps * par.pchan * par.rate;
+ pause_pending = flush_pending = volume_pending = 0;
+ restarted = 1;
  paused = 0;
  if (!sio_start (hdl)) {
  fprintf (stderr, "%s: failed to start audio device\n",
  __func__);
  goto error;
  }
-
- bytes_per_sec = par.bps * par.pchan * par.rate;
  pthread_mutex_unlock (&mutex);
- op_set_volume (volume, volume);
  return TRUE;
 
 error:
@@ -247,11 +315,9 @@ error:
 static void
 op_write (void *ptr, int len)
 {
+ unsigned n;
  EffectPlugin *ep;
 
- if (paused)
- return;
-
  /* This sucks but XMMS totally broke the effect plugin code when
    they added support for multiple enabled effects.  Complain to
    the non-existent XMMS team if a plugin does not work, however
@@ -259,13 +325,23 @@ op_write (void *ptr, int len)
  ep = get_current_effect_plugin ();
  ep->mod_samples (&ptr, len, afmt, par.rate, par.pchan);
 
- /* Do not lock sio_write as this will cause the GUI thread
-   to block waiting for a blocked sio_write to return. */
- len = sio_write (hdl, ptr, len);
-
- pthread_mutex_lock (&mutex);
- wrpos += len;
- pthread_mutex_unlock (&mutex);
+ pthread_mutex_lock(&mutex);
+ for (;;) {
+ pending_events();
+ if (paused)
+ break;
+ restarted = 0;
+ n = sio_write(hdl, ptr, len);
+ if (n == 0 && sio_eof(hdl))
+ break;
+ wrpos += n;
+ len -= n;
+ ptr = (char *)ptr + n;
+ if (len == 0)
+ break;
+ wait_ready();
+ }
+ pthread_mutex_unlock(&mutex);
 }
 
 static void
@@ -285,8 +361,8 @@ op_seek (int time_ms)
  int bufused;
 
  pthread_mutex_lock (&mutex);
- bufused = (rdpos < 0) ? wrpos : wrpos - rdpos;
- rdpos = time_ms / 1000 * bytes_per_sec;
+ bufused = wrpos - rdpos;
+ rdpos = (long long)time_ms * bytes_per_sec / 1000;
  wrpos = rdpos + bufused;
  pthread_mutex_unlock (&mutex);
 }
@@ -294,20 +370,30 @@ op_seek (int time_ms)
 static void
 op_pause (short flag)
 {
+ pthread_mutex_lock(&mutex);
  paused = flag;
+ pause_pending = 1;
+ pthread_mutex_unlock(&mutex);
 }
 
 static int
 op_buffer_free (void)
 {
 #define MAGIC 1000000 /* See Output/{OSS,sun,esd}/audio.c */
- return paused ? 0 : MAGIC;
+ int ret;
+
+ pthread_mutex_lock(&mutex);
+ pending_events();
+ ret = paused ? 0 : MAGIC;
+ pthread_mutex_unlock(&mutex);
+ return ret;
 }
 
 static int
 op_playing (void)
 {
- return paused ? TRUE : FALSE;
+ /* sndio drains in the background, do as we're done */
+ return FALSE;
 }
 
 static int
@@ -333,18 +419,10 @@ op_get_written_time (void)
 }
 
 static void
-onmove_cb (void *addr, int delta)
-{
- pthread_mutex_lock (&mutex);
- rdpos += delta * (int)(par.bps * par.pchan);
- pthread_mutex_unlock (&mutex);
-}
-
-static void
 op_configure(void)
 {
  GtkWidget *dev_vbox;
- GtkWidget *adevice_frame, *adevice_text, *adevice_vbox;
+ GtkWidget *adevice_frame, *adevice_vbox;
  GtkWidget *bbox, *ok, *cancel;
 
  if (configure_win) {
@@ -370,9 +448,6 @@ op_configure(void)
  adevice_vbox = gtk_vbox_new(FALSE, 5);
  gtk_container_set_border_width(GTK_CONTAINER(adevice_vbox), 5);
  gtk_container_add(GTK_CONTAINER(adevice_frame), adevice_vbox);
-
- adevice_text = gtk_label_new(_("(empty means default)"));
- gtk_box_pack_start_defaults(GTK_BOX(adevice_vbox), adevice_text);
 
  adevice_entry = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(adevice_entry), audiodev);

Reply | Threaded
Open this post in threaded view
|

Re: audio/xmms: sndio plugin update to test

Stuart Henderson
On 2012/09/06 09:02, Alexandre Ratchov wrote:
> Here's the "final" xmms diff; I got two test reports only, but I
> believe this is correct.

> ok?

I don't normally use xmms (prefer aqualung) but thought I'd have a look,
I tried quite hard to get the unpatched one to crash but only managed
to get one crash at exit and eventually one during playing a couple of
files from the command line (not repeatable though), so it would be
hard to say for sure if this made things better, anyway if people
seeing the problem think this helps then it's OK with me.

>
> -- Alexandre
>
> Index: Makefile
> ===================================================================
> RCS file: /cvs/ports/audio/xmms/Makefile,v
> retrieving revision 1.79
> diff -u -p -r1.79 Makefile
> --- Makefile 9 Aug 2012 17:54:47 -0000 1.79
> +++ Makefile 6 Sep 2012 06:49:30 -0000
> @@ -10,7 +10,7 @@ SHARED_ONLY= Yes
>  VERSION= 1.2.11
>  DISTNAME= xmms-${VERSION}
>  PKGNAME-main= xmms-${VERSION}
> -REVISION-main= 10
> +REVISION-main= 11
>  PKGNAME-vorbis= xmms-vorbis-${VERSION}
>  REVISION-vorbis= 4
>  PKGNAME-mikmod= xmms-mikmod-${VERSION}
> Index: files/audio_sndio.c
> ===================================================================
> RCS file: /cvs/ports/audio/xmms/files/audio_sndio.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 audio_sndio.c
> --- files/audio_sndio.c 5 Dec 2010 15:52:19 -0000 1.3
> +++ files/audio_sndio.c 6 Sep 2012 06:49:30 -0000
> @@ -14,9 +14,12 @@
>   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
>   */
>  
> +#include <errno.h>
> +#include <poll.h>
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <string.h>
> +#include <unistd.h>
>  
>  #include <gtk/gtk.h>
>  #include <libxmms/util.h>
> @@ -44,8 +47,6 @@ static int op_playing (void);
>  static int op_get_output_time (void);
>  static int op_get_written_time (void);
>  
> -static void onmove_cb (void *, int);
> -
>  static void configure_win_ok_cb(GtkWidget *, gpointer);
>  static void configure_win_cancel_cb(GtkWidget *, gpointer);
>  static void configure_win_destroy(void);
> @@ -54,8 +55,8 @@ static struct sio_par par;
>  static struct sio_hdl *hdl;
>  static long long rdpos;
>  static long long wrpos;
> -static int paused;
> -static int volume = XMMS_MAXVOL;
> +static int paused, restarted, volume;
> +static int pause_pending, flush_pending, volume_pending;
>  static long bytes_per_sec;
>  static AFormat afmt;
>  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
> @@ -91,6 +92,74 @@ get_oplugin_info (void)
>  }
>  
>  static void
> +reset(void)
> +{
> + if (!restarted) {
> + restarted = 1;
> + sio_stop(hdl);
> + sio_start(hdl);
> + rdpos = wrpos;
> + }
> +}
> +static void
> +onmove_cb (void *addr, int delta)
> +{
> + rdpos += delta * (int)(par.bps * par.pchan);
> +}
> +
> +static void
> +onvol_cb(void *addr, unsigned ctl)
> +{
> + /* Update volume only if it actually changed */
> + if (ctl != volume * SIO_MAXVOL / 100)
> + volume = ctl * 100 / SIO_MAXVOL;
> +}
> +
> +static void
> +pending_events(void)
> +{
> + if (volume_pending) {
> + sio_setvol(hdl, volume * SIO_MAXVOL / 100);
> + volume_pending = 0;
> + }
> + if (flush_pending) {
> + reset();
> + flush_pending = 0;
> + }
> + if (pause_pending) {
> + if (paused)
> + reset();
> + pause_pending = 0;
> + }
> +}
> +
> +static void
> +wait_ready(void)
> +{
> + int n;
> + struct pollfd pfds[16];
> +
> + if (paused) {
> + pthread_mutex_unlock(&mutex);
> + usleep(20000);
> + pthread_mutex_lock(&mutex);
> + return;
> + }
> + n = sio_pollfd(hdl, pfds, POLLOUT);
> + if (n != 0) {
> + pthread_mutex_unlock(&mutex);
> + while (poll(pfds, n, -1) < 0) {
> + if (errno != EINTR) {
> + perror("poll");
> + exit(1);
> + }
> + }
> + pthread_mutex_lock(&mutex);
> + }
> + (void)sio_revents(hdl, pfds);
> +}
> +
> +static void
>  op_about (void)
>  {
>   static GtkWidget *about;
> @@ -118,7 +187,7 @@ op_init (void)
>   xmms_cfg_free(cfgfile);
>  
>   if (!audiodev)
> - audiodev = g_strdup("");
> + audiodev = g_strdup(SIO_DEVANY);
>  }
>  
>  static void
> @@ -135,8 +204,7 @@ op_set_volume (int left, int right)
>   /* Ignore balance control, so use unattenuated channel. */
>   pthread_mutex_lock (&mutex);
>   volume = left > right ? left : right;
> - if (hdl != NULL)
> - sio_setvol (hdl, volume * SIO_MAXVOL / XMMS_MAXVOL);
> + volume_pending = 1;
>   pthread_mutex_unlock (&mutex);
>  }
>  
> @@ -146,8 +214,7 @@ op_open (AFormat fmt, int rate, int nch)
>   struct sio_par askpar;
>  
>   pthread_mutex_lock (&mutex);
> -
> - hdl = sio_open (strlen (audiodev) > 0 ? audiodev : NULL, SIO_PLAY, 0);
> + hdl = sio_open (audiodev, SIO_PLAY, 1);
>   if (hdl == NULL) {
>   fprintf (stderr, "%s: failed to open audio device\n", __func__);
>   goto error;
> @@ -217,7 +284,7 @@ op_open (AFormat fmt, int rate, int nch)
>   fprintf (stderr, "%s: parameters not supported\n", __func__);
>   xmms_show_message ("Unsupported format", "XMMS requested a "
>   "format that is not supported by the audio device.\n\n"
> - "Please try again with the aucat(1) server running.",
> + "Please try again with the sndiod(1) server running.",
>   "OK", FALSE, NULL, NULL);
>   goto error;
>   }
> @@ -225,17 +292,18 @@ op_open (AFormat fmt, int rate, int nch)
>   rdpos = 0;
>   wrpos = 0;
>   sio_onmove (hdl, onmove_cb, NULL);
> + sio_onvol (hdl, onvol_cb, NULL);
>  
> + bytes_per_sec = par.bps * par.pchan * par.rate;
> + pause_pending = flush_pending = volume_pending = 0;
> + restarted = 1;
>   paused = 0;
>   if (!sio_start (hdl)) {
>   fprintf (stderr, "%s: failed to start audio device\n",
>   __func__);
>   goto error;
>   }
> -
> - bytes_per_sec = par.bps * par.pchan * par.rate;
>   pthread_mutex_unlock (&mutex);
> - op_set_volume (volume, volume);
>   return TRUE;
>  
>  error:
> @@ -247,11 +315,9 @@ error:
>  static void
>  op_write (void *ptr, int len)
>  {
> + unsigned n;
>   EffectPlugin *ep;
>  
> - if (paused)
> - return;
> -
>   /* This sucks but XMMS totally broke the effect plugin code when
>     they added support for multiple enabled effects.  Complain to
>     the non-existent XMMS team if a plugin does not work, however
> @@ -259,13 +325,23 @@ op_write (void *ptr, int len)
>   ep = get_current_effect_plugin ();
>   ep->mod_samples (&ptr, len, afmt, par.rate, par.pchan);
>  
> - /* Do not lock sio_write as this will cause the GUI thread
> -   to block waiting for a blocked sio_write to return. */
> - len = sio_write (hdl, ptr, len);
> -
> - pthread_mutex_lock (&mutex);
> - wrpos += len;
> - pthread_mutex_unlock (&mutex);
> + pthread_mutex_lock(&mutex);
> + for (;;) {
> + pending_events();
> + if (paused)
> + break;
> + restarted = 0;
> + n = sio_write(hdl, ptr, len);
> + if (n == 0 && sio_eof(hdl))
> + break;
> + wrpos += n;
> + len -= n;
> + ptr = (char *)ptr + n;
> + if (len == 0)
> + break;
> + wait_ready();
> + }
> + pthread_mutex_unlock(&mutex);
>  }
>  
>  static void
> @@ -285,8 +361,8 @@ op_seek (int time_ms)
>   int bufused;
>  
>   pthread_mutex_lock (&mutex);
> - bufused = (rdpos < 0) ? wrpos : wrpos - rdpos;
> - rdpos = time_ms / 1000 * bytes_per_sec;
> + bufused = wrpos - rdpos;
> + rdpos = (long long)time_ms * bytes_per_sec / 1000;
>   wrpos = rdpos + bufused;
>   pthread_mutex_unlock (&mutex);
>  }
> @@ -294,20 +370,30 @@ op_seek (int time_ms)
>  static void
>  op_pause (short flag)
>  {
> + pthread_mutex_lock(&mutex);
>   paused = flag;
> + pause_pending = 1;
> + pthread_mutex_unlock(&mutex);
>  }
>  
>  static int
>  op_buffer_free (void)
>  {
>  #define MAGIC 1000000 /* See Output/{OSS,sun,esd}/audio.c */
> - return paused ? 0 : MAGIC;
> + int ret;
> +
> + pthread_mutex_lock(&mutex);
> + pending_events();
> + ret = paused ? 0 : MAGIC;
> + pthread_mutex_unlock(&mutex);
> + return ret;
>  }
>  
>  static int
>  op_playing (void)
>  {
> - return paused ? TRUE : FALSE;
> + /* sndio drains in the background, do as we're done */
> + return FALSE;
>  }
>  
>  static int
> @@ -333,18 +419,10 @@ op_get_written_time (void)
>  }
>  
>  static void
> -onmove_cb (void *addr, int delta)
> -{
> - pthread_mutex_lock (&mutex);
> - rdpos += delta * (int)(par.bps * par.pchan);
> - pthread_mutex_unlock (&mutex);
> -}
> -
> -static void
>  op_configure(void)
>  {
>   GtkWidget *dev_vbox;
> - GtkWidget *adevice_frame, *adevice_text, *adevice_vbox;
> + GtkWidget *adevice_frame, *adevice_vbox;
>   GtkWidget *bbox, *ok, *cancel;
>  
>   if (configure_win) {
> @@ -370,9 +448,6 @@ op_configure(void)
>   adevice_vbox = gtk_vbox_new(FALSE, 5);
>   gtk_container_set_border_width(GTK_CONTAINER(adevice_vbox), 5);
>   gtk_container_add(GTK_CONTAINER(adevice_frame), adevice_vbox);
> -
> - adevice_text = gtk_label_new(_("(empty means default)"));
> - gtk_box_pack_start_defaults(GTK_BOX(adevice_vbox), adevice_text);
>  
>   adevice_entry = gtk_entry_new();
>   gtk_entry_set_text(GTK_ENTRY(adevice_entry), audiodev);
>