summaryrefslogtreecommitdiffstats
path: root/oss.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2007-05-17 19:19:08 +0000
committerLennart Poettering <lennart@poettering.net>2007-05-17 19:19:08 +0000
commitc58ce0879c1cabfd31dd8657d2594d78f13b1360 (patch)
treeb9254d64d59da3037cec32a540583813c8d76b2e /oss.c
parentacd9a2853021249bed55a8a47ef2a3d4d565b2c5 (diff)
add handling of watermarks
git-svn-id: file:///home/lennart/svn/public/libsydney/trunk@25 9ba3c220-e4d3-45a2-8aa3-73fcc9aff6ce
Diffstat (limited to 'oss.c')
-rw-r--r--oss.c659
1 files changed, 423 insertions, 236 deletions
diff --git a/oss.c b/oss.c
index 50063bd..b1b1168 100644
--- a/oss.c
+++ b/oss.c
@@ -23,13 +23,33 @@ struct oss_stream {
int fd;
pcm_attrs_t real_pcm_attrs;
converter_t converter_read, converter_write;
+ size_t read_fragment_size, write_fragment_size;
+ unsigned read_nfragments, write_nfragments;
};
+static int simple_log2(int v) {
+ int k = 0;
+
+ for (;;) {
+ v >>= 1;
+ if (!v) break;
+ k++;
+ }
+
+ return k;
+}
+
+static size_t fixup_bps(size_t s, size_t bps1, size_t bps2) {
+ return (s*bps2)/bps1;
+}
+
int driver_open(sa_stream_t *s) {
oss_stream_t *oss;
char *n;
- int f, arg, bs, r, phase, i, found, suggested;
+ int f, arg, bs, r, phase, i, found, suggested, fs, l, m;
unsigned c;
+ size_t real_bps = 0, bps;
+ int loops = 0;
static const int format_map[_SA_PCM_FORMAT_MAX] = {
[SA_PCM_FORMAT_U8] = AFMT_U8,
@@ -55,296 +75,437 @@ int driver_open(sa_stream_t *s) {
oss->parent = s;
n = s->device ? s->device : DEFAULT_DEVICE;
- if ((oss->fd = open(n, s->mode == SA_MODE_RDONLY ? O_RDONLY : (s->mode == SA_MODE_WRONLY ? O_WRONLY : O_RDWR) | O_NOCTTY | O_NONBLOCK)) < 0) {
+ if (!s->codec)
+ bps = s->pcm_frame_size * s->pcm_attrs.rate;
- if (errno == ENODEV || errno == ENOENT)
- return SA_ERROR_NO_DEVICE;
+ for (;;) {
+ /* We need to loop here, because we have to call SETFRAGMENT
+ * as first ioctl after the open, at a point where we
+ * don't now yet the sample type, freq and the number of
+ * channels we actually settled on. Hence we have to loop
+ * here: if the sampling format is too far off we have to call
+ * SETFRAGMENT again which can do only after reopening the
+ * device again. */
+
+ if ((oss->fd = open(n, s->mode == SA_MODE_RDONLY ? O_RDONLY : (s->mode == SA_MODE_WRONLY ? O_WRONLY : O_RDWR) | O_NOCTTY | O_NONBLOCK)) < 0) {
+
+ if (errno == ENODEV || errno == ENOENT)
+ r = SA_ERROR_NO_DEVICE;
+ else
+ r = SA_ERROR_SYSTEM;
+
+ goto fail;
+ }
- return SA_ERROR_SYSTEM;
- }
-
- fcntl(oss->fd, F_SETFL, fcntl(oss->fd, F_GETFL) & ~O_NONBLOCK); /* FIXME*/
-
- if (!s->device) {
- if (!(n = sa_strdup(n)))
- return SA_ERROR_OOM;
-
- s->device = n;
- }
-
- if (s->codec) {
-
- if (strcmp(s->codec, SA_CODEC_AC3) == 0)
- f = AFMT_AC3;
- else if (strcmp(s->codec, SA_CODEC_MPEG) == 0)
- f = AFMT_MPEG;
- else
- return SA_ERROR_NO_CODEC;
+ fcntl(oss->fd, F_SETFL, fcntl(oss->fd, F_GETFL) & ~O_NONBLOCK); /* FIXME*/
- } else
- f = format_map[s->pcm_attrs.format];
+ if (!s->device) {
+ if (!(n = sa_strdup(n))) {
+ r = SA_ERROR_OOM;
+ goto fail;
+ }
+
+ s->device = n;
+ }
- bs = 0;
-
- for (;;) {
- arg = f;
+ /* Set fragment settings */
+ if (s->mode & SA_MODE_WRONLY) {
+ fs = s->write_upper_watermark - s->write_lower_watermark;
+ bs = s->write_upper_watermark;
+ }
- if (ioctl(oss->fd, SNDCTL_DSP_SETFMT, &arg) < 0)
- return SA_ERROR_SYSTEM;
-
- if (arg == f)
- break;
-
- /* Hmm, the device doesn't support what we're looking for,
- * let's try our luck */
-
- if (f == AFMT_S16_LE && !bs) {
- f = AFMT_S16_BE;
- bs = 1;
- } else if (f == AFMT_S16_BE && !bs) {
- f = AFMT_S16_LE;
- bs = 1;
- } else if (f == AFMT_S16_LE || f == AFMT_S16_BE) {
- f = AFMT_MU_LAW;
- bs = 0;
- } else if (f == AFMT_MU_LAW && !bs) {
- f = AFMT_A_LAW;
- bs = 1;
- } else if (f == AFMT_A_LAW && !bs) {
- f = AFMT_MU_LAW;
- bs = 1;
- } else if (f == AFMT_A_LAW || f == AFMT_MU_LAW) {
- f = AFMT_U8;
- } else if (f == AFMT_AC3 || f == AFMT_MPEG)
- return SA_ERROR_NO_CODEC;
- else
- return SA_ERROR_NO_PCM_FORMAT;
- }
-
- if (!s->codec) {
-
- switch (f) {
- case AFMT_MU_LAW:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_ULAW;
- break;
-
- case AFMT_A_LAW:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_ALAW;
- break;
+ if (s->mode & SA_MODE_RDONLY) {
+ int rfs, rbs;
+
+ rfs = s->read_lower_watermark;
+ rbs = s->read_upper_watermark;
+
+ if (s->mode & SA_MODE_WRONLY) {
+ fs = fs < rfs ? fs : rfs;
+ bs = bs > rbs ? bs : rbs;
+ } else {
+ fs = rfs;
+ bs = rbs;
+ }
+ }
- case AFMT_U8:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_U8;
- break;
+ if (!s->codec && real_bps) {
+ bs = fixup_bps(bs, bps, real_bps);
+ fs = fixup_bps(fs, bps, real_bps);
+ }
- case AFMT_S16_LE:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_LE;
- break;
+ l = simple_log2(fs);
+ m = (bs+(1<<l)-1)/(1<<l);
+ if (l < 1) l = 1;
+ if (m < 2) m = 2;
+ if (m > 0x7FFF) m = 0x7FFF;
- case AFMT_S16_BE:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_BE;
+ printf("Asking OSS for: %u fragments, %u fragsize\n", m, 1 << l);
+
+ arg = (m << 16) | l;
+
+ ioctl(oss->fd, SNDCTL_DSP_SETFRAGMENT, &arg);
+ /* We ignore errors on this call, since it's merely a hint anyway */
+
+ if (s->codec) {
+
+ if (strcmp(s->codec, SA_CODEC_AC3) == 0)
+ f = AFMT_AC3;
+ else if (strcmp(s->codec, SA_CODEC_MPEG) == 0)
+ f = AFMT_MPEG;
+ else {
+ r = SA_ERROR_NO_CODEC;
+ goto fail;
+ }
+
+ } else
+ f = format_map[s->pcm_attrs.format];
+
+ bs = 0;
+
+ for (;;) {
+ arg = f;
+
+ if (ioctl(oss->fd, SNDCTL_DSP_SETFMT, &arg) < 0) {
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
+
+ if (arg == f)
break;
-
- default:
- sa_assert_not_reached();
+
+ /* Hmm, the device doesn't support what we're looking for,
+ * let's try our luck */
+
+ if (f == AFMT_S16_LE && !bs) {
+ f = AFMT_S16_BE;
+ bs = 1;
+ } else if (f == AFMT_S16_BE && !bs) {
+ f = AFMT_S16_LE;
+ bs = 1;
+ } else if (f == AFMT_S16_LE || f == AFMT_S16_BE) {
+ f = AFMT_MU_LAW;
+ bs = 0;
+ } else if (f == AFMT_MU_LAW && !bs) {
+ f = AFMT_A_LAW;
+ bs = 1;
+ } else if (f == AFMT_A_LAW && !bs) {
+ f = AFMT_MU_LAW;
+ bs = 1;
+ } else if (f == AFMT_A_LAW || f == AFMT_MU_LAW) {
+ f = AFMT_U8;
+ } else if (f == AFMT_AC3 || f == AFMT_MPEG) {
+ r = SA_ERROR_NO_CODEC;
+ goto fail;
+ } else {
+ r = SA_ERROR_NO_PCM_FORMAT;
+ goto fail;
+ }
}
-
- found = 0;
-
- if (s->adjust_nchannels >= 0) {
+ if (!s->codec) {
- /* First try more channels ... */
- for (c = s->pcm_attrs.nchannels; c < 8 || c == s->pcm_attrs.nchannels; c ++) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0)
- return SA_ERROR_SYSTEM;
-
- if (arg == (int) c) {
- found = 1;
+ switch (f) {
+ case AFMT_MU_LAW:
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_ULAW;
break;
- }
+
+ case AFMT_A_LAW:
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_ALAW;
+ break;
+
+ case AFMT_U8:
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_U8;
+ break;
+
+ case AFMT_S16_LE:
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_LE;
+ break;
+
+ case AFMT_S16_BE:
+ oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_BE;
+ break;
+
+ default:
+ sa_assert_not_reached();
}
-
- /* ... then try less channels */
- if (!found) {
- for (c = s->pcm_attrs.nchannels - 1; c > 0; c --) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0)
- return SA_ERROR_SYSTEM;
+
+
+ found = 0;
+
+ if (s->adjust_nchannels >= 0) {
+ /* First try more channels ... */
+ for (c = s->pcm_attrs.nchannels; c < 8 || c == s->pcm_attrs.nchannels; c ++) {
+ arg = c;
+ if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
+
if (arg == (int) c) {
found = 1;
break;
}
}
- }
- } else {
-
- /* First try less channels ... */
- for (c = s->pcm_attrs.nchannels; c > 0; c --) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0)
- return SA_ERROR_SYSTEM;
- if (arg == (int) c) {
- found = 1;
- break;
+ /* ... then try less channels */
+ if (!found) {
+ for (c = s->pcm_attrs.nchannels - 1; c > 0; c --) {
+ arg = c;
+ if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
+
+ if (arg == (int) c) {
+ found = 1;
+ break;
+ }
+ }
}
- }
-
- /* ... then try more channels */
- if (!found) {
- for (c = s->pcm_attrs.nchannels + 1; c < 8; c ++) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0)
- return SA_ERROR_SYSTEM;
+ } else {
+ /* First try less channels ... */
+ for (c = s->pcm_attrs.nchannels; c > 0; c --) {
+ arg = c;
+ if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
+
if (arg == (int) c) {
found = 1;
break;
}
}
- }
- }
- if (!found) {
- errno = EIO;
- return SA_ERROR_SYSTEM;
- }
-
- oss->real_pcm_attrs.nchannels = c;
-
- if (!(oss->real_pcm_attrs.channel_map = sa_new(sa_channel_t, c)))
- return SA_ERROR_OOM;
-
- switch (c) {
- case 8:
- oss->real_pcm_attrs.channel_map[7] = SA_CHANNEL_REAR_RIGHT;
- case 7:
- oss->real_pcm_attrs.channel_map[6] = SA_CHANNEL_REAR_LEFT;
- case 6:
- oss->real_pcm_attrs.channel_map[5] = SA_CHANNEL_FRONT_LEFT;
- case 5:
- oss->real_pcm_attrs.channel_map[4] = SA_CHANNEL_FRONT_RIGHT;
- case 4:
- oss->real_pcm_attrs.channel_map[3] = SA_CHANNEL_LFE;
- case 3:
- oss->real_pcm_attrs.channel_map[2] = SA_CHANNEL_CENTER;
- case 2:
- oss->real_pcm_attrs.channel_map[1] = SA_CHANNEL_RIGHT;
- oss->real_pcm_attrs.channel_map[0] = SA_CHANNEL_LEFT;
- break;
- case 1:
- oss->real_pcm_attrs.channel_map[0] = SA_CHANNEL_MONO;
- break;
- }
-
- r = s->pcm_attrs.rate;
-
- if (r < 8000)
- r = 8000;
-
- suggested = 0;
- phase = 0;
-
- for (;;) {
- arg = r;
+ /* ... then try more channels */
+ if (!found) {
+ for (c = s->pcm_attrs.nchannels + 1; c < 8; c ++) {
+ arg = c;
+ if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
+
+ if (arg == (int) c) {
+ found = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ errno = EIO;
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
+
+ oss->real_pcm_attrs.nchannels = c;
+
+ if (!(oss->real_pcm_attrs.channel_map = sa_new(sa_channel_t, c))) {
+ r = SA_ERROR_OOM;
+ goto fail;
+ }
- if (ioctl(oss->fd, SNDCTL_DSP_SPEED, &arg) < 0)
- return SA_ERROR_SYSTEM;
+ switch (c) {
+ case 8:
+ oss->real_pcm_attrs.channel_map[7] = SA_CHANNEL_REAR_RIGHT;
+ case 7:
+ oss->real_pcm_attrs.channel_map[6] = SA_CHANNEL_REAR_LEFT;
+ case 6:
+ oss->real_pcm_attrs.channel_map[5] = SA_CHANNEL_FRONT_LEFT;
+ case 5:
+ oss->real_pcm_attrs.channel_map[4] = SA_CHANNEL_FRONT_RIGHT;
+ case 4:
+ oss->real_pcm_attrs.channel_map[3] = SA_CHANNEL_LFE;
+ case 3:
+ oss->real_pcm_attrs.channel_map[2] = SA_CHANNEL_CENTER;
+ case 2:
+ oss->real_pcm_attrs.channel_map[1] = SA_CHANNEL_RIGHT;
+ oss->real_pcm_attrs.channel_map[0] = SA_CHANNEL_LEFT;
+ break;
+ case 1:
+ oss->real_pcm_attrs.channel_map[0] = SA_CHANNEL_MONO;
+ break;
+ }
+
+ r = s->pcm_attrs.rate;
+
+ if (r < 8000)
+ r = 8000;
+
+ suggested = 0;
+ phase = 0;
+
+ for (;;) {
+ arg = r;
+
+ if (ioctl(oss->fd, SNDCTL_DSP_SPEED, &arg) < 0) {
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
- sa_assert(arg > 0);
+ sa_assert(arg > 0);
- if (arg >= r*0.95 || arg <= r *1.05)
- break;
+ if (arg >= r*0.95 || arg <= r *1.05)
+ break;
- if (arg > suggested)
- suggested = arg;
+ if (arg > suggested)
+ suggested = arg;
- if (s->adjust_rate >= 0) {
+ if (s->adjust_rate >= 0) {
- if (phase == 0) {
- /* Find the next higher sample rate to try */
+ if (phase == 0) {
+ /* Find the next higher sample rate to try */
- for (i = 0; i < (int) elementsof(try_rates); i++) {
- /* Yes, we could optimize a little here */
+ for (i = 0; i < (int) elementsof(try_rates); i++) {
+ /* Yes, we could optimize a little here */
- if (try_rates[i] > r) {
- r = try_rates[i];
- break;
+ if (try_rates[i] > r) {
+ r = try_rates[i];
+ break;
+ }
}
- }
- if (i == elementsof(try_rates)) {
- phase = 1;
- r = s->pcm_attrs.rate;
+ if (i == elementsof(try_rates)) {
+ phase = 1;
+ r = s->pcm_attrs.rate;
+ }
}
- }
-
- if (phase == 1) {
- /* Find the next lower sample rate to try */
- for (i = elementsof(try_rates); i > 0; i--) {
- if (suggested > try_rates[i-1] && suggested < r) {
- r = suggested;
- break;
- } else if (try_rates[i-1] < r) {
- r = try_rates[i-1];
- break;
+ if (phase == 1) {
+ /* Find the next lower sample rate to try */
+
+ for (i = elementsof(try_rates); i > 0; i--) {
+ if (suggested > try_rates[i-1] && suggested < r) {
+ r = suggested;
+ break;
+ } else if (try_rates[i-1] < r) {
+ r = try_rates[i-1];
+ break;
+ }
}
- }
- sa_assert(i > 0);
- }
+ sa_assert(i > 0);
+ }
- } else {
+ } else {
- if (phase == 0) {
- /* Find the next lower sample rate to try */
+ if (phase == 0) {
+ /* Find the next lower sample rate to try */
- for (i = elementsof(try_rates); i > 0; i--) {
+ for (i = elementsof(try_rates); i > 0; i--) {
- if (try_rates[i-1] < r) {
- r = try_rates[i-1];
- break;
+ if (try_rates[i-1] < r) {
+ r = try_rates[i-1];
+ break;
+ }
}
- }
- if (i == 0) {
- phase = 1;
- r = s->pcm_attrs.rate;
+ if (i == 0) {
+ phase = 1;
+ r = s->pcm_attrs.rate;
+ }
}
- }
- if (phase == 1) {
- /* Find the next higher sample rate to try */
-
- for (i = 0; i < (int) elementsof(try_rates); i++) {
- if (suggested > r && suggested < try_rates[i]) {
- r = suggested;
- break;
- } else if (try_rates[i] < r) {
- r = try_rates[i];
- break;
+ if (phase == 1) {
+ /* Find the next higher sample rate to try */
+
+ for (i = 0; i < (int) elementsof(try_rates); i++) {
+ if (suggested > r && suggested < try_rates[i]) {
+ r = suggested;
+ break;
+ } else if (try_rates[i] < r) {
+ r = try_rates[i];
+ break;
+ }
}
- }
- sa_assert(i < (int) elementsof(try_rates));
+ sa_assert(i < (int) elementsof(try_rates));
+ }
}
+
}
+ oss->real_pcm_attrs.rate = r;
+
+ printf("Chosen: %u channels, %uHz, format=%u\n", oss->real_pcm_attrs.nchannels, oss->real_pcm_attrs.rate, oss->real_pcm_attrs.format);
+
+ real_bps = oss->real_pcm_attrs.nchannels * oss->real_pcm_attrs.rate * get_pcm_sample_size(oss->real_pcm_attrs.format);
+
+ if (real_bps != bps && loops < 1) {
+ loops++;
+
+ sa_free(oss->real_pcm_attrs.channel_map);
+ oss->real_pcm_attrs.channel_map = NULL;
+
+ close(oss->fd);
+
+ printf("bps changed, retrying...\n");
+ continue;
+ }
}
- oss->real_pcm_attrs.rate = r;
+ break;
+ }
- printf("Chosen: %u channels, %uHz, format=%u\n", oss->real_pcm_attrs.nchannels, oss->real_pcm_attrs.rate, oss->real_pcm_attrs.format);
+ /* First, let's try GETBLKSIZE */
+ if (ioctl(oss->fd, SNDCTL_DSP_GETBLKSIZE, &arg) >= 0) {
+ if (s->mode & SA_MODE_RDONLY) {
+ oss->read_fragment_size = arg;
+ oss->read_nfragments = 2;
+ }
+
+ if (s->mode & SA_MODE_WRONLY) {
+ oss->write_fragment_size = arg;
+ oss->write_nfragments = 2;
+ }
+ }
+
+ /* Now, let's use GETxSPACE */
+ if (s->mode & SA_MODE_RDONLY) {
+ audio_buf_info info;
+
+ if (ioctl(oss->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
+ oss->read_fragment_size = info.fragsize;
+ oss->read_nfragments = info.fragstotal;
+ }
+ }
+
+ if (s->mode & SA_MODE_WRONLY) {
+ audio_buf_info info;
+
+ if (ioctl(oss->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
+ oss->write_fragment_size = info.fragsize;
+ oss->write_nfragments = info.fragstotal;
+ }
+ }
+
+ if (s->mode & SA_MODE_WRONLY && (oss->write_fragment_size <= 0 || oss->write_nfragments <= 1)) {
+ errno = EIO;
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
+
+ if (s->mode & SA_MODE_RDONLY && (oss->read_fragment_size <= 0 || oss->read_nfragments <= 1)) {
+ errno = EIO;
+ r = SA_ERROR_SYSTEM;
+ goto fail;
+ }
+ if (!s->codec) {
+
if (s->adjust_nchannels != 0) {
sa_channel_t *cm;
- if (!(cm = sa_newdup(sa_channel_t, oss->real_pcm_attrs.channel_map, oss->real_pcm_attrs.nchannels)))
- return SA_ERROR_OOM;
+ if (!(cm = sa_newdup(sa_channel_t, oss->real_pcm_attrs.channel_map, oss->real_pcm_attrs.nchannels))) {
+ r = SA_ERROR_OOM;
+ goto fail;
+ }
sa_free(s->pcm_attrs.channel_map);
s->pcm_attrs.channel_map = cm;
@@ -358,26 +519,52 @@ int driver_open(sa_stream_t *s) {
if (s->mode & SA_MODE_RDONLY)
if ((r = converter_init(&oss->converter_read, &oss->real_pcm_attrs, &s->pcm_attrs, s->dynamic_rate_enabled)) < 0)
- return r;
+ goto fail;
if (s->mode & SA_MODE_WRONLY)
if ((r = converter_init(&oss->converter_write, &s->pcm_attrs, &oss->real_pcm_attrs, s->dynamic_rate_enabled)) < 0)
- return r;
+ goto fail;
+ }
+
+ if (s->adjust_watermarks) {
+
+ if (s->mode & SA_MODE_RDONLY) {
+ s->read_lower_watermark = oss->read_fragment_size;
+ s->read_upper_watermark = oss->read_fragment_size * oss->read_nfragments;
+ }
+
+ if (s->mode & SA_MODE_WRONLY) {
+ s->write_lower_watermark = oss->write_fragment_size;
+ s->write_upper_watermark = oss->write_fragment_size * oss->write_nfragments;
+ }
}
+
+ if (s->mode & SA_MODE_RDONLY)
+ printf("Chosen for read: %u fragments, %u fragsize\n", oss->read_nfragments, oss->read_fragment_size);
+ if (s->mode & SA_MODE_WRONLY)
+ printf("Chosen for write: %u fragments, %u fragsize\n", oss->write_nfragments, oss->write_fragment_size);
+
return SA_SUCCESS;
+
+fail:
+ driver_destroy(s);
+ return r;
}
int driver_destroy(sa_stream_t *s) {
oss_stream_t *oss = OSS_STREAM(s);
- if (oss->fd >= 0)
- close(oss->fd);
-
- sa_free(oss->real_pcm_attrs.channel_map);
- converter_done(&oss->converter_read);
- converter_done(&oss->converter_write);
- sa_free(oss);
+ if (oss) {
+ if (oss->fd >= 0)
+ close(oss->fd);
+
+ sa_free(oss->real_pcm_attrs.channel_map);
+ converter_done(&oss->converter_read);
+ converter_done(&oss->converter_write);
+ sa_free(oss);
+ }
+
return SA_SUCCESS;
}