Path: blob/main/audio/alsa-plugins/files/patch-oss_pcm__oss.c
16462 views
--- oss/pcm_oss.c.orig 2024-06-10 09:18:39 UTC1+++ oss/pcm_oss.c2@@ -20,6 +20,7 @@34#include "config.h"5#include <stdio.h>6+#include <stdbool.h>7#include <sys/ioctl.h>8#include <alsa/asoundlib.h>9#include <alsa/pcm_external.h>10@@ -31,16 +32,32 @@11#include <soundcard.h>12#endif1314+#ifndef ARRAY_SIZE15+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))16+#endif17+18+#define ALSA_OSS_RATE_MIN 119+#define ALSA_OSS_RATE_MAX 38400020+21+#define ALSA_OSS_CHANNELS_MIN 122+#define ALSA_OSS_CHANNELS_MAX 823+24+#define ALSA_OSS_BUFSZ_MAX 13107225+#define ALSA_OSS_BLKCNT_MIN 226+#define ALSA_OSS_BLKSZ_MIN 16 /* (ALSA_OSS_CHANNELS_MAX * 4) */27+28+#define ALSA_OSS_BUFSZ_MIN (ALSA_OSS_BLKCNT_MIN * ALSA_OSS_BLKSZ_MIN)29+#define ALSA_OSS_BLKCNT_MAX (ALSA_OSS_BUFSZ_MAX / ALSA_OSS_BUFSZ_MIN)30+#define ALSA_OSS_BLKSZ_MAX (ALSA_OSS_BUFSZ_MAX / ALSA_OSS_BLKCNT_MIN)31+32typedef struct snd_pcm_oss {33snd_pcm_ioplug_t io;34char *device;35int fd;36- int fragment_set;37- int caps;38+ int bufsz;39int format;40- unsigned int period_shift;41- unsigned int periods;42- unsigned int frame_bytes;43+ int frame_bytes;44+ bool buffer_used;45} snd_pcm_oss_t;4647static snd_pcm_sframes_t oss_write(snd_pcm_ioplug_t *io,48@@ -56,8 +73,21 @@ static snd_pcm_sframes_t oss_write(snd_pcm_ioplug_t *i49buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8;50size *= oss->frame_bytes;51result = write(oss->fd, buf, size);52- if (result <= 0)53- return result;54+#ifdef __FreeBSD__55+ if (result == -1) {56+ if (errno == EAGAIN)57+ return 0;58+ else59+ return -errno;60+ }61+#else62+ if (result <= 0) {63+ if (result == -EAGAIN)64+ return 0;65+ else66+ return result;67+ }68+#endif69return result / oss->frame_bytes;70}7172@@ -74,37 +104,122 @@ static snd_pcm_sframes_t oss_read(snd_pcm_ioplug_t *io73buf = (char *)areas->addr + (areas->first + areas->step * offset) / 8;74size *= oss->frame_bytes;75result = read(oss->fd, buf, size);76- if (result <= 0)77- return result;78+#ifdef __FreeBSD__79+ if (result == -1) {80+ if (errno == EAGAIN)81+ return 0;82+ else83+ return -errno;84+ }85+#else86+ if (result <= 0) {87+ if (result == -EAGAIN)88+ return 0;89+ else90+ return result;91+ }92+#endif93return result / oss->frame_bytes;94}9596static snd_pcm_sframes_t oss_pointer(snd_pcm_ioplug_t *io)97{98snd_pcm_oss_t *oss = io->private_data;99- struct count_info info;100- int ptr;101+ snd_pcm_sframes_t frames;102+ audio_buf_info bi;103104- if (ioctl(oss->fd, io->stream == SND_PCM_STREAM_PLAYBACK ?105- SNDCTL_DSP_GETOPTR : SNDCTL_DSP_GETIPTR, &info) < 0) {106- fprintf(stderr, "*** OSS: oss_pointer error\n");107+ switch (io->state) {108+ case SND_PCM_STATE_XRUN:109+ return -EPIPE;110+ case SND_PCM_STATE_RUNNING:111+ case SND_PCM_STATE_DRAINING:112+ break;113+ default:114return 0;115}116- ptr = snd_pcm_bytes_to_frames(io->pcm, info.ptr);117- return ptr;118+119+ if (io->stream == SND_PCM_STREAM_PLAYBACK) {120+ if (ioctl(oss->fd, SNDCTL_DSP_GETOSPACE, &bi) < 0)121+ return -EINVAL;122+ } else {123+ if (ioctl(oss->fd, SNDCTL_DSP_GETISPACE, &bi) < 0)124+ return -EINVAL;125+ }126+127+ /* check for over- and under- run */128+ if (bi.bytes != oss->bufsz) {129+ oss->buffer_used = true;130+ } else {131+ if (oss->buffer_used)132+ return -EPIPE;133+ }134+135+ frames = bi.bytes / oss->frame_bytes;136+137+ /* range check */138+ if (frames < 0)139+ frames = 0;140+ else if (frames > io->buffer_size)141+ frames = io->buffer_size;142+143+ /* set hw_ptr directly */144+ if (io->stream == SND_PCM_STREAM_PLAYBACK) {145+ io->hw_ptr = io->appl_ptr + frames - io->buffer_size;146+ } else {147+ io->hw_ptr = io->appl_ptr + frames;148+ }149+ return 0;150}151152+static int oss_prepare(snd_pcm_ioplug_t *io)153+{154+ snd_pcm_oss_t *oss = io->private_data;155+ snd_pcm_sw_params_t *swparams;156+ snd_pcm_uframes_t min_avail;157+ int tmp;158+159+ snd_pcm_sw_params_alloca(&swparams);160+161+ if (snd_pcm_sw_params_current(io->pcm, swparams) == 0) {162+ snd_pcm_sw_params_get_avail_min(swparams, &min_avail);163+ snd_pcm_sw_params_alloca(&swparams);164+ } else {165+ min_avail = io->period_size;166+ }167+168+ tmp = min_avail * oss->frame_bytes;169+ if (tmp > oss->bufsz)170+ tmp = oss->bufsz;171+ else if (tmp < 1)172+ tmp = 1;173+174+#ifdef SNDCTL_DSP_LOW_WATER175+ if (ioctl(oss->fd, SNDCTL_DSP_LOW_WATER, &tmp) < 0)176+ return -EINVAL;177+#endif178+ oss->buffer_used = false;179+180+ return 0;181+}182+183static int oss_start(snd_pcm_ioplug_t *io)184{185snd_pcm_oss_t *oss = io->private_data;186int tmp = io->stream == SND_PCM_STREAM_PLAYBACK ?187PCM_ENABLE_OUTPUT : PCM_ENABLE_INPUT;188189+#ifdef ALSA_OSS_DEBUG_VERBOSE190+ fprintf(stderr, "%s()\n", __func__);191+#endif192if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &tmp) < 0) {193fprintf(stderr, "*** OSS: trigger failed\n");194+#ifdef __FreeBSD__195+ return -EINVAL;196+#else197if (io->stream == SND_PCM_STREAM_CAPTURE)198/* fake read to trigger */199read(oss->fd, &tmp, 0);200+#endif201}202return 0;203}204@@ -114,6 +229,10 @@ static int oss_stop(snd_pcm_ioplug_t *io)205snd_pcm_oss_t *oss = io->private_data;206int tmp = 0;207208+#ifdef ALSA_OSS_DEBUG_VERBOSE209+ fprintf(stderr, "%s()\n", __func__);210+#endif211+212ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &tmp);213return 0;214}215@@ -122,101 +241,164 @@ static int oss_drain(snd_pcm_ioplug_t *io)216{217snd_pcm_oss_t *oss = io->private_data;218219+#ifdef ALSA_OSS_DEBUG_VERBOSE220+ fprintf(stderr, "%s()\n", __func__);221+#endif222+223if (io->stream == SND_PCM_STREAM_PLAYBACK)224- ioctl(oss->fd, SNDCTL_DSP_SYNC);225+ ioctl(oss->fd, SNDCTL_DSP_SYNC, NULL);226return 0;227}228229-static int oss_prepare(snd_pcm_ioplug_t *io)230+static int oss_delay(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp)231{232snd_pcm_oss_t *oss = io->private_data;233int tmp;234235- ioctl(oss->fd, SNDCTL_DSP_RESET);236+ if (oss->fd < 0)237+ return -EBADFD;238239- tmp = io->channels;240- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0) {241- perror("SNDCTL_DSP_CHANNELS");242- return -EINVAL;243+ if (io->stream == SND_PCM_STREAM_PLAYBACK) {244+ if (ioctl(oss->fd, SNDCTL_DSP_GETODELAY, &tmp) < 0 || tmp < 0)245+ tmp = 0;246+ } else {247+ tmp = 0;248}249- tmp = oss->format;250- if (ioctl(oss->fd, SNDCTL_DSP_SETFMT, &tmp) < 0) {251- perror("SNDCTL_DSP_SETFMT");252- return -EINVAL;253- }254- tmp = io->rate;255- if (ioctl(oss->fd, SNDCTL_DSP_SPEED, &tmp) < 0 ||256- tmp > io->rate * 1.01 || tmp < io->rate * 0.99) {257- perror("SNDCTL_DSP_SPEED");258- return -EINVAL;259- }260- return 0;261+ *delayp = tmp / oss->frame_bytes;262+263+ return (0);264}265266+static const struct {267+ int oss_format;268+ snd_pcm_format_t alsa_format;269+} oss_formats_tab[] = {270+ { AFMT_U8, SND_PCM_FORMAT_U8 },271+ { AFMT_S8, SND_PCM_FORMAT_S8 },272+ { AFMT_MU_LAW, SND_PCM_FORMAT_MU_LAW },273+ { AFMT_A_LAW, SND_PCM_FORMAT_A_LAW },274+ { AFMT_S16_LE, SND_PCM_FORMAT_S16_LE },275+ { AFMT_S16_BE, SND_PCM_FORMAT_S16_BE },276+ { AFMT_U16_LE, SND_PCM_FORMAT_U16_LE },277+ { AFMT_U16_BE, SND_PCM_FORMAT_U16_BE },278+ { AFMT_S24_LE, SND_PCM_FORMAT_S24_3LE },279+ { AFMT_S24_BE, SND_PCM_FORMAT_S24_3BE },280+ { AFMT_U24_LE, SND_PCM_FORMAT_U24_3LE },281+ { AFMT_U24_BE, SND_PCM_FORMAT_U24_3BE },282+ { AFMT_S32_LE, SND_PCM_FORMAT_S32_LE },283+ { AFMT_S32_BE, SND_PCM_FORMAT_S32_BE },284+ { AFMT_U32_LE, SND_PCM_FORMAT_U32_LE },285+ { AFMT_U32_BE, SND_PCM_FORMAT_U32_BE },286+ /* Special */287+ { AFMT_S24_LE, SND_PCM_FORMAT_S20_3LE },288+ { AFMT_S24_BE, SND_PCM_FORMAT_S20_3BE },289+ { AFMT_U24_LE, SND_PCM_FORMAT_U20_3LE },290+ { AFMT_U24_BE, SND_PCM_FORMAT_U20_3BE },291+ { AFMT_S24_LE, SND_PCM_FORMAT_S18_3LE },292+ { AFMT_S24_BE, SND_PCM_FORMAT_S18_3BE },293+ { AFMT_U24_LE, SND_PCM_FORMAT_U18_3LE },294+ { AFMT_U24_BE, SND_PCM_FORMAT_U18_3BE },295+ { AFMT_S32_LE, SND_PCM_FORMAT_S24_LE },296+ { AFMT_S32_BE, SND_PCM_FORMAT_S24_BE },297+ { AFMT_U32_LE, SND_PCM_FORMAT_U24_LE },298+ { AFMT_U32_BE, SND_PCM_FORMAT_U24_BE },299+};300+301static int oss_hw_params(snd_pcm_ioplug_t *io,302snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED)303{304snd_pcm_oss_t *oss = io->private_data;305int i, tmp, err;306- unsigned int period_bytes;307+ int blksz_shift, blkcnt;308+ audio_buf_info bi;309long oflags, flags;310311+#ifdef ALSA_OSS_DEBUG_VERBOSE312+ fprintf(stderr, "%s()\n", __func__);313+#endif314+315oss->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8;316- switch (io->format) {317- case SND_PCM_FORMAT_U8:318- oss->format = AFMT_U8;319- break;320- case SND_PCM_FORMAT_S16_LE:321- oss->format = AFMT_S16_LE;322- break;323- case SND_PCM_FORMAT_S16_BE:324- oss->format = AFMT_S16_BE;325- break;326- default:327+ oss->format = 0;328+ for (i = 0; i != ARRAY_SIZE(oss_formats_tab); i++) {329+ if (oss_formats_tab[i].alsa_format == io->format) {330+ oss->format = oss_formats_tab[i].oss_format;331+ break;332+ }333+ }334+ if (oss->format == 0) {335fprintf(stderr, "*** OSS: unsupported format %s\n", snd_pcm_format_name(io->format));336return -EINVAL;337}338- period_bytes = io->period_size * oss->frame_bytes;339- oss->period_shift = 0;340- for (i = 31; i >= 4; i--) {341- if (period_bytes & (1U << i)) {342- oss->period_shift = i;343+344+ ioctl(oss->fd, SNDCTL_DSP_RESET);345+346+ /* use a 8ms HW buffer by default */347+ tmp = ((8 * io->rate) / 1000) * oss->frame_bytes;348+349+ /* round up to nearest power of two */350+ while (tmp & (tmp - 1))351+ tmp += tmp & ~(tmp - 1);352+353+ /* get logarithmic value */354+ for (blksz_shift = 0; blksz_shift < 24; blksz_shift++) {355+ if (tmp == (1 << blksz_shift))356break;357- }358}359- if (! oss->period_shift) {360- fprintf(stderr, "*** OSS: invalid period size %d\n", (int)io->period_size);361- return -EINVAL;362+363+ tmp = io->buffer_size * oss->frame_bytes;364+365+ /* compute HW buffer big enough to hold SW buffer */366+ for (blkcnt = ALSA_OSS_BLKCNT_MIN; blkcnt != ALSA_OSS_BLKCNT_MAX; blkcnt *= 2) {367+ if ((blkcnt << blksz_shift) >= tmp)368+ break;369}370- oss->periods = io->buffer_size / io->period_size;371372- _retry:373- tmp = oss->period_shift | (oss->periods << 16);374+ tmp = blksz_shift | (blkcnt << 16);375if (ioctl(oss->fd, SNDCTL_DSP_SETFRAGMENT, &tmp) < 0) {376- if (! oss->fragment_set) {377- perror("SNDCTL_DSP_SETFRAGMENT");378- fprintf(stderr, "*** period shift = %d, periods = %d\n", oss->period_shift, oss->periods);379- return -EINVAL;380- }381- /* OSS has no proper way to reinitialize the fragments */382- /* try to reopen the device */383- close(oss->fd);384- oss->fd = open(oss->device, io->stream == SND_PCM_STREAM_PLAYBACK ?385- O_WRONLY : O_RDONLY);386- if (oss->fd < 0) {387- err = -errno;388- SNDERR("Cannot reopen the device %s", oss->device);389- return err;390- }391- io->poll_fd = oss->fd;392- io->poll_events = io->stream == SND_PCM_STREAM_PLAYBACK ?393- POLLOUT : POLLIN;394- snd_pcm_ioplug_reinit_status(io);395- oss->fragment_set = 0;396- goto _retry;397+ perror("SNDCTL_DSP_SETFRAGMENTS");398+ return -EINVAL;399}400- oss->fragment_set = 1;401402+ tmp = oss->format;403+ if (ioctl(oss->fd, SNDCTL_DSP_SETFMT, &tmp) < 0 ||404+ tmp != oss->format) {405+ perror("SNDCTL_DSP_SETFMT");406+ return -EINVAL;407+ }408+409+ tmp = io->channels;410+ if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &tmp) < 0 ||411+ tmp != io->channels) {412+ perror("SNDCTL_DSP_CHANNELS");413+ return -EINVAL;414+ }415+416+ tmp = io->rate;417+ if (ioctl(oss->fd, SNDCTL_DSP_SPEED, &tmp) < 0 ||418+ tmp > io->rate * 1.01 || tmp < io->rate * 0.99) {419+ perror("SNDCTL_DSP_SPEED");420+ return -EINVAL;421+ }422+423+ if (ioctl(oss->fd, (io->stream == SND_PCM_STREAM_PLAYBACK) ?424+ SNDCTL_DSP_GETOSPACE : SNDCTL_DSP_GETISPACE, &bi) < 0) {425+ perror("SNDCTL_DSP_GET[I/O]SPACE");426+ return -EINVAL;427+ }428+429+ oss->bufsz = bi.fragsize * bi.fragstotal;430+431+#ifdef ALSA_OSS_DEBUG_VERBOSE432+ fprintf(stderr,433+ "\n\n[%lu -> %d] %lu ~ %d -> %d, %lu ~ %d -> %d [d:%ld lw:%d]\n\n",434+ io->buffer_size / io->period_size, bi.fragstotal,435+ io->buffer_size * oss->frame_bytes,436+ (1 << blksz_shift) * blkcnt, oss->bufsz,437+ io->period_size * oss->frame_bytes, 1 << blksz_shift,438+ bi.fragsize,439+ (long)(io->buffer_size * oss->frame_bytes) -440+ oss->bufsz, tmp);441+#endif442if ((flags = fcntl(oss->fd, F_GETFL)) < 0) {443err = -errno;444perror("F_GETFL");445@@ -236,16 +418,148 @@ static int oss_hw_params(snd_pcm_ioplug_t *io,446return 0;447}448449-#define ARRAY_SIZE(ary) (sizeof(ary)/sizeof(ary[0]))450-451static int oss_hw_constraint(snd_pcm_oss_t *oss)452{453+#ifdef __FreeBSD__454snd_pcm_ioplug_t *io = &oss->io;455static const snd_pcm_access_t access_list[] = {456SND_PCM_ACCESS_RW_INTERLEAVED,457SND_PCM_ACCESS_MMAP_INTERLEAVED458};459+#ifdef FREEBSD_OSS_BLKCNT_P2460+ unsigned int period_list[30];461+#endif462+#ifdef FREEBSD_OSS_BUFSZ_P2463+ unsigned int bufsz_list[30];464+#endif465unsigned int nformats;466+ unsigned int format[ARRAY_SIZE(oss_formats_tab)];467+ int i, err, tmp;468+469+#ifdef ALSA_OSS_DEBUG_VERBOSE470+ fprintf(stderr, "%s()\n", __func__);471+#endif472+473+ /* check trigger */474+ tmp = 0;475+ if (ioctl(oss->fd, SNDCTL_DSP_GETCAPS, &tmp) >= 0) {476+ if (!(tmp & DSP_CAP_TRIGGER))477+ fprintf(stderr, "*** OSS: trigger is not supported!\n");478+ }479+480+ /* access type - interleaved only */481+ if ((err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,482+ ARRAY_SIZE(access_list), access_list)) < 0)483+ return err;484+485+ /* supported formats. */486+ tmp = 0;487+ ioctl(oss->fd, SNDCTL_DSP_GETFMTS, &tmp);488+ nformats = 0;489+ for (i = 0; i < ARRAY_SIZE(oss_formats_tab); i++) {490+ if (tmp & oss_formats_tab[i].oss_format)491+ format[nformats++] = oss_formats_tab[i].alsa_format;492+ }493+ if (! nformats)494+ format[nformats++] = SND_PCM_FORMAT_S16;495+ if ((err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,496+ nformats, format)) < 0)497+ return err;498+499+#if 0500+ /* supported channels */501+ nchannels = 0;502+ for (i = 0; i < ARRAY_SIZE(channel); i++) {503+ tmp = i + 1;504+ if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &tmp) >= 0 &&505+ 1 + i == tmp)506+ channel[nchannels++] = tmp;507+ }508+ if (! nchannels) /* assume 2ch stereo */509+ err = snd_pcm_ioplug_set_param_minmax(io,510+ SND_PCM_IOPLUG_HW_CHANNELS, 2, 2);511+ else512+ err = snd_pcm_ioplug_set_param_list(io,513+ SND_PCM_IOPLUG_HW_CHANNELS, nchannels, channel);514+ if (err < 0)515+ return err;516+#endif517+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,518+ ALSA_OSS_CHANNELS_MIN, ALSA_OSS_CHANNELS_MAX);519+ if (err < 0)520+ return err;521+522+ /* supported rates */523+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,524+ ALSA_OSS_RATE_MIN, ALSA_OSS_RATE_MAX);525+ if (err < 0)526+ return err;527+528+ /*529+ * Maximum buffer size on FreeBSD can go up to 131072 bytes without530+ * strict ^2 alignment so that s24le in 3bytes packing can be fed531+ * directly.532+ */533+534+#ifdef FREEBSD_OSS_BLKCNT_P2535+ tmp = 0;536+ for (i = 1; i < 31 && tmp < ARRAY_SIZE(period_list); i++) {537+ if ((1 << i) > ALSA_OSS_BLKCNT_MAX)538+ break;539+ if ((1 << i) < ALSA_OSS_BLKCNT_MIN)540+ continue;541+ period_list[tmp++] = 1 << i;542+ }543+544+ if (tmp > 0)545+ err = snd_pcm_ioplug_set_param_list(io,546+ SND_PCM_IOPLUG_HW_PERIODS, tmp, period_list);547+ else548+#endif549+ /* periods , not strictly ^2 but later on will be refined */550+ err = snd_pcm_ioplug_set_param_minmax(io,551+ SND_PCM_IOPLUG_HW_PERIODS, ALSA_OSS_BLKCNT_MIN,552+ ALSA_OSS_BLKCNT_MAX);553+ if (err < 0)554+ return err;555+556+ /* period size , not strictly ^2 */557+ err = snd_pcm_ioplug_set_param_minmax(io,558+ SND_PCM_IOPLUG_HW_PERIOD_BYTES, ALSA_OSS_BLKSZ_MIN,559+ ALSA_OSS_BLKSZ_MAX);560+ if (err < 0)561+ return err;562+563+#ifdef FREEBSD_OSS_BUFSZ_P2564+ tmp = 0;565+ for (i = 1; i < 31 && tmp < ARRAY_SIZE(bufsz_list); i++) {566+ if ((1 << i) > ALSA_OSS_BUFSZ_MAX)567+ break;568+ if ((1 << i) < ALSA_OSS_BUFSZ_MIN)569+ continue;570+ bufsz_list[tmp++] = 1 << i;571+ }572+573+ if (tmp > 0)574+ err = snd_pcm_ioplug_set_param_list(io,575+ SND_PCM_IOPLUG_HW_BUFFER_BYTES, tmp, bufsz_list);576+ else577+#endif578+ /* buffer size , not strictly ^2 */579+ err = snd_pcm_ioplug_set_param_minmax(io,580+ SND_PCM_IOPLUG_HW_BUFFER_BYTES, ALSA_OSS_BUFSZ_MIN,581+ ALSA_OSS_BUFSZ_MAX);582+ if (err < 0)583+ return err;584+585+ return 0;586+#else587+ snd_pcm_ioplug_t *io = &oss->io;588+ static const snd_pcm_access_t access_list[] = {589+ SND_PCM_ACCESS_RW_INTERLEAVED,590+ SND_PCM_ACCESS_MMAP_INTERLEAVED591+ };592+ unsigned int nformats;593unsigned int format[5];594unsigned int nchannels;595unsigned int channel[6];596@@ -324,6 +638,7 @@ static int oss_hw_constraint(snd_pcm_oss_t *oss)597return err;598599return 0;600+#endif601}602603604@@ -331,6 +646,10 @@ static int oss_close(snd_pcm_ioplug_t *io)605{606snd_pcm_oss_t *oss = io->private_data;607608+#ifdef ALSA_OSS_DEBUG_VERBOSE609+ fprintf(stderr, "%s()\n", __func__);610+#endif611+612close(oss->fd);613free(oss->device);614free(oss);615@@ -346,6 +665,7 @@ static const snd_pcm_ioplug_callback_t oss_playback_ca616.hw_params = oss_hw_params,617.prepare = oss_prepare,618.drain = oss_drain,619+ .delay = oss_delay,620};621622static const snd_pcm_ioplug_callback_t oss_capture_callback = {623@@ -357,6 +677,7 @@ static const snd_pcm_ioplug_callback_t oss_capture_cal624.hw_params = oss_hw_params,625.prepare = oss_prepare,626.drain = oss_drain,627+ .delay = oss_delay,628};629630631@@ -367,6 +688,10 @@ SND_PCM_PLUGIN_DEFINE_FUNC(oss)632int err;633snd_pcm_oss_t *oss;634635+#ifdef ALSA_OSS_DEBUG_VERBOSE636+ fprintf(stderr, "%s()\n", __func__);637+#endif638+639snd_config_for_each(i, next, conf) {640snd_config_t *n = snd_config_iterator_entry(i);641const char *id;642643644