]> code.delx.au - pulseaudio/blobdiff - src/modules/module-solaris.c
add test program for pa_rtpoll
[pulseaudio] / src / modules / module-solaris.c
index 8eaf6758eb43e3a033dae8ee172d2b0146560317..a50f1ecf8889183b6970b0eff5d87501735011a2 100644 (file)
@@ -2,17 +2,20 @@
 
 /***
   This file is part of PulseAudio.
+
+  Copyright 2006 Lennart Poettering
+  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
+
   PulseAudio is free software; you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published
   by the Free Software Foundation; either version 2 of the License,
   or (at your option) any later version.
+
   PulseAudio is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   General Public License for more details.
+
   You should have received a copy of the GNU Lesser General Public License
   along with PulseAudio; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
@@ -80,11 +83,14 @@ struct userdata {
     pa_usec_t poll_timeout;
     pa_signal_event *sig;
 
-    pa_memchunk memchunk, silence;
+    pa_memchunk memchunk;
+
+    unsigned int page_size;
 
     uint32_t frame_size;
     uint32_t buffer_size;
     unsigned int written_bytes, read_bytes;
+    int sink_underflow;
 
     int fd;
     pa_module *module;
@@ -119,10 +125,9 @@ static void update_usage(struct userdata *u) {
 static void do_write(struct userdata *u) {
     audio_info_t info;
     int err;
-    pa_memchunk *memchunk;
     size_t len;
     ssize_t r;
-    
+
     assert(u);
 
     /* We cannot check pa_iochannel_is_writable() because of our buffer hack */
@@ -145,7 +150,7 @@ static void do_write(struct userdata *u) {
     if (len > u->buffer_size)
         len = 0;
 
-    if (len == u->buffer_size)
+    if (!u->sink_underflow && (len == u->buffer_size))
         pa_log_debug("Solaris buffer underflow!");
 
     len -= len % u->frame_size;
@@ -153,37 +158,39 @@ static void do_write(struct userdata *u) {
     if (len == 0)
         return;
 
-    memchunk = &u->memchunk;
-    
-    if (!memchunk->length)
-        if (pa_sink_render(u->sink, len, memchunk) < 0)
-            memchunk = &u->silence;
-    
-    assert(memchunk->memblock);
-    assert(memchunk->memblock->data);
-    assert(memchunk->length);
-
-    if (memchunk->length < len) {
-        len = memchunk->length;
+    if (!u->memchunk.length) {
+        if (pa_sink_render(u->sink, len, &u->memchunk) < 0) {
+            u->sink_underflow = 1;
+            return;
+        }
+    }
+
+    u->sink_underflow = 0;
+
+    assert(u->memchunk.memblock);
+    assert(u->memchunk.memblock->data);
+    assert(u->memchunk.length);
+
+    if (u->memchunk.length < len) {
+        len = u->memchunk.length;
         len -= len % u->frame_size;
         assert(len);
     }
 
-    if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) {
+    if ((r = pa_iochannel_write(u->io,
+        (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, len)) < 0) {
         pa_log("write() failed: %s", pa_cstrerror(errno));
         return;
     }
 
     assert(r % u->frame_size == 0);
-    
-    if (memchunk != &u->silence) {
-        u->memchunk.index += r;
-        u->memchunk.length -= r;
-        
-        if (u->memchunk.length <= 0) {
-            pa_memblock_unref(u->memchunk.memblock);
-            u->memchunk.memblock = NULL;
-        }
+
+    u->memchunk.index += r;
+    u->memchunk.length -= r;
+
+    if (u->memchunk.length <= 0) {
+        pa_memblock_unref(u->memchunk.memblock);
+        u->memchunk.memblock = NULL;
     }
 
     u->written_bytes += r;
@@ -191,10 +198,11 @@ static void do_write(struct userdata *u) {
 
 static void do_read(struct userdata *u) {
     pa_memchunk memchunk;
-    int err, l;
+    int err;
+    size_t l;
     ssize_t r;
     assert(u);
-    
+
     if (!u->source || !pa_iochannel_is_readable(u->io))
         return;
 
@@ -203,6 +211,11 @@ static void do_read(struct userdata *u) {
     err = ioctl(u->fd, I_NREAD, &l);
     assert(err >= 0);
 
+    /* This is to make sure it fits in the memory pool. Also, a page
+       should be the most efficient transfer size. */
+    if (l > u->page_size)
+        l = u->page_size;
+
     memchunk.memblock = pa_memblock_new(u->core->mempool, l);
     assert(memchunk.memblock);
     if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) {
@@ -211,11 +224,11 @@ static void do_read(struct userdata *u) {
             pa_log("read() failed: %s", pa_cstrerror(errno));
         return;
     }
-    
+
     assert(r <= (ssize_t) memchunk.memblock->length);
     memchunk.length = memchunk.memblock->length = r;
     memchunk.index = 0;
-    
+
     pa_source_post(u->source, &memchunk);
     pa_memblock_unref(memchunk.memblock);
 
@@ -246,7 +259,7 @@ static void timer_cb(pa_mainloop_api*a, pa_time_event *e, const struct timeval *
 static void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) {
     struct userdata *u = userdata;
     pa_cvolume old_vol;
-    
+
     assert(u);
 
     if (u->sink) {
@@ -508,7 +521,7 @@ int pa__init(pa_core *c, pa_module*m) {
         pa_log("failed to parse module arguments.");
         goto fail;
     }
-    
+
     if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
         pa_log("record= and playback= expect numeric argument.");
         goto fail;
@@ -521,7 +534,7 @@ int pa__init(pa_core *c, pa_module*m) {
 
     mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
 
-    buffer_size = 16384;    
+    buffer_size = 16384;
     if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) {
         pa_log("failed to parse buffer size argument");
         goto fail;
@@ -532,7 +545,7 @@ int pa__init(pa_core *c, pa_module*m) {
         pa_log("failed to parse sample specification");
         goto fail;
     }
-    
+
     if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0)
         goto fail;
 
@@ -587,17 +600,18 @@ int pa__init(pa_core *c, pa_module*m) {
 
     u->memchunk.memblock = NULL;
     u->memchunk.length = 0;
+
+    /* We use this to get a reasonable chunk size */
+    u->page_size = sysconf(_SC_PAGESIZE);
+
     u->frame_size = pa_frame_size(&ss);
     u->buffer_size = buffer_size;
 
-    u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length = CHUNK_SIZE);
-    assert(u->silence.memblock);
-    pa_silence_memblock(u->silence.memblock, &ss);
-    u->silence.index = 0;
-
     u->written_bytes = 0;
     u->read_bytes = 0;
 
+    u->sink_underflow = 1;
+
     u->module = m;
     m->userdata = u;
 
@@ -631,7 +645,7 @@ fail:
 
     if (ma)
         pa_modargs_free(ma);
-    
+
     return -1;
 }
 
@@ -646,22 +660,20 @@ void pa__done(pa_core *c, pa_module*m) {
         c->mainloop->time_free(u->timer);
     ioctl(u->fd, I_SETSIG, 0);
     pa_signal_free(u->sig);
-    
+
     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);
 }