Date: Mon, 3 Dec 2007 11:01:22 GMT From: Henrik Gulbrandsen <henrik@gulbra.net> To: freebsd-gnats-submit@FreeBSD.org Subject: kern/118395: [patch] Audio playback aborted with SNDCTL_DSP_SETTRIGGER Message-ID: <200712031101.lB3B1MaR025882@www.freebsd.org> Resent-Message-ID: <200712031110.lB3BA0Sd007704@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 118395 >Category: kern >Synopsis: [patch] Audio playback aborted with SNDCTL_DSP_SETTRIGGER >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Mon Dec 03 11:10:00 UTC 2007 >Closed-Date: >Last-Modified: >Originator: Henrik Gulbrandsen >Release: 7.0-BETA3 >Organization: >Environment: FreeBSD Particle 7.0-BETA3 FreeBSD 7.0-BETA3 #2: Sat Dec 1 18:11:51 CET 2007 henrik@Particle:/usr/src/sys/i386/compile/GENERIC i386 >Description: Revision 1.121 of src/sys/dev/sound/pcm/channel.c introduced incorrect handling of the SNDCTL_DSP_SETTRIGGER ioctl request. Normally, this request allows users to delay the start of audio playback until the output buffer has been filled, as documented at pages 104-105 of http://www.opensound.com/pguide/oss.pdf. Current FreeBSD code interprets the blocked channel as an error and aborts playback. This bug affects version 19 of PortAudio (the audio/portaudio2 port) and may be the reason why the audio/audacity-devel port is explicitly configured with the older version 18 of PortAudio. >How-To-Repeat: The attached shell archive includes the trigger.c example program, which fails under FreeBSD 7.0-BETA3: Particle$ ./trigger Failed second SNDCTL_DSP_SETTRIGGER: Invalid argument Particle$ >Fix: The attached shell archive also includes the channel.c.patch file, which fixes the problem: Particle$ ./trigger Everything worked. Particle$ The patch also includes a corresponding fix for the recording case, which I have not actually tested. Judging from code and documentation, it should be handled in exactly the same way, though. Patch attached with submission follows: # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # trigger.c # channel.c.patch # echo x - trigger.c sed 's/^X//' >trigger.c << 'END-of-trigger.c' X#include <errno.h> X#include <fcntl.h> X#include <stdio.h> X#include <stdlib.h> X#include <string.h> X#include <sys/soundcard.h> X Xint main(int argc, char *argv[]) X{ X int dev, flags, enable_bits; X char buffer[1024]; X X memset(buffer, 0, sizeof(buffer)); X X dev = open("/dev/dsp", O_WRONLY); X if (dev == -1) { X perror("Failed open"); X return EXIT_FAILURE; X } X X flags = fcntl(dev, F_GETFL); X if (flags == -1) { X perror("Failed F_GETFL"); X return EXIT_FAILURE; X } X X flags |= O_NONBLOCK; X X if (fcntl(dev, F_SETFL, flags) == -1) { X perror("Failed F_SETFL"); X return EXIT_FAILURE; X } X X enable_bits = ~PCM_ENABLE_OUTPUT; X if (ioctl(dev, SNDCTL_DSP_SETTRIGGER, &enable_bits) == -1) { X perror("Failed first SNDCTL_DSP_SETTRIGGER"); X return EXIT_FAILURE; X } X X while (write(dev, buffer, sizeof(buffer)) != -1) { X /* Nothing */ X } X X if (errno != EAGAIN) { X perror("Unexpected write error"); X return EXIT_FAILURE; X } X X enable_bits = PCM_ENABLE_OUTPUT; X if (ioctl(dev, SNDCTL_DSP_SETTRIGGER, &enable_bits) == -1) { X perror("Failed second SNDCTL_DSP_SETTRIGGER"); X return EXIT_FAILURE; X } X X printf("Everything worked.\n"); X return EXIT_SUCCESS; X} END-of-trigger.c echo x - channel.c.patch sed 's/^X//' >channel.c.patch << 'END-of-channel.c.patch' X--- sys/dev/sound/pcm/channel.c.orig 2007-06-16 05:37:28.000000000 +0200 X+++ sys/dev/sound/pcm/channel.c 2007-12-03 10:53:48.000000000 +0100 X@@ -409,7 +409,7 @@ X sndbuf_acquire(bs, NULL, t); X } X ret = 0; X- if (CHN_STOPPED(c)) { X+ if (CHN_STOPPED(c) && !(c->flags & CHN_F_NOTRIGGER)) { X ret = chn_start(c, 0); X if (ret != 0) X c->flags |= CHN_F_DEAD; X@@ -520,7 +520,7 @@ X X CHN_LOCKASSERT(c); X X- if (CHN_STOPPED(c)) { X+ if (CHN_STOPPED(c) && !(c->flags & CHN_F_NOTRIGGER)) { X ret = chn_start(c, 0); X if (ret != 0) { X c->flags |= CHN_F_DEAD; END-of-channel.c.patch exit >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200712031101.lB3B1MaR025882>