diff options
author | Lennart Poettering <lennart@poettering.net> | 2006-08-12 16:02:26 +0000 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2006-08-12 16:02:26 +0000 |
commit | 4c9c4269bb70aad6c7a62ed7f73867087f4af217 (patch) | |
tree | 75e02aaebe8685c92bdc368e77aafc839af4988a /src | |
parent | 3cfed301d91ebf773ace89a02fea6db817426221 (diff) |
handle hot-remeving of OSS devices properly
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1221 fefdeb5f-60dc-0310-8127-8f9354f1896f
Diffstat (limited to 'src')
-rw-r--r-- | src/modules/module-oss-mmap.c | 74 | ||||
-rw-r--r-- | src/modules/module-oss.c | 42 |
2 files changed, 81 insertions, 35 deletions
diff --git a/src/modules/module-oss-mmap.c b/src/modules/module-oss-mmap.c index cc408f90..08cf1a8d 100644 --- a/src/modules/module-oss-mmap.c +++ b/src/modules/module-oss-mmap.c @@ -117,6 +117,42 @@ static void update_usage(struct userdata *u) { (u->source ? pa_idxset_size(u->source->outputs) : 0)); } +static void clear_up(struct userdata *u) { + assert(u); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) { + munmap(u->in_mmap, u->in_mmap_length); + u->in_mmap = NULL; + } + + if (u->out_mmap && u->out_mmap != MAP_FAILED) { + munmap(u->out_mmap, u->out_mmap_length); + u->out_mmap = NULL; + } + + if (u->io_event) { + u->core->mainloop->io_free(u->io_event); + u->io_event = NULL; + } + + if (u->fd >= 0) { + close(u->fd); + u->fd = -1; + } +} + static void out_fill_memblocks(struct userdata *u, unsigned n) { assert(u && u->out_memblocks); @@ -154,6 +190,9 @@ static void do_write(struct userdata *u) { if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); return; } @@ -217,6 +256,9 @@ static void do_read(struct userdata *u) { if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); return; } @@ -234,6 +276,12 @@ static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd struct userdata *u = userdata; assert (u && u->core->mainloop == m && u->io_event == e); + if (f & PA_IO_EVENT_ERROR) { + clear_up(u); + pa_module_unload_request(u->module); + return; + } + if (f & PA_IO_EVENT_INPUT) do_read(u); if (f & PA_IO_EVENT_OUTPUT) @@ -393,7 +441,7 @@ int pa__init(pa_core *c, pa_module*m) { if ((u->fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) goto fail; - if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_REALTIME) || !(caps & DSP_CAP_TRIGGER)) { + if (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER)) { pa_log(__FILE__": OSS device not mmap capable."); goto fail; } @@ -539,6 +587,8 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; + clear_up(u); + if (u->out_memblocks) { unsigned i; for (i = 0; i < u->out_fragments; i++) @@ -555,27 +605,5 @@ void pa__done(pa_core *c, pa_module*m) { pa_xfree(u->in_memblocks); } - if (u->in_mmap && u->in_mmap != MAP_FAILED) - munmap(u->in_mmap, u->in_mmap_length); - - if (u->out_mmap && u->out_mmap != MAP_FAILED) - munmap(u->out_mmap, u->out_mmap_length); - - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - if (u->io_event) - u->core->mainloop->io_free(u->io_event); - - if (u->fd >= 0) - close(u->fd); - pa_xfree(u); } diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 5ce74151..c3972680 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -107,6 +107,27 @@ static void update_usage(struct userdata *u) { (u->source ? pa_idxset_size(u->source->outputs) : 0)); } +static void clear_up(struct userdata *u) { + assert(u); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } + + if (u->io) { + pa_iochannel_free(u->io); + u->io = NULL; + } +} + static void do_write(struct userdata *u) { pa_memchunk *memchunk; ssize_t r; @@ -148,6 +169,9 @@ static void do_write(struct userdata *u) { if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); break; } @@ -199,8 +223,11 @@ static void do_read(struct userdata *u) { assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); - if (errno != EAGAIN) + if (errno != EAGAIN) { pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); + clear_up(u); + pa_module_unload_request(u->module); + } break; } @@ -501,22 +528,13 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; + + clear_up(u); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->silence.memblock) pa_memblock_unref(u->silence.memblock); - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - pa_iochannel_free(u->io); pa_xfree(u); } |